难以想象,来到新岗位上做的事情竟然还可以用老套路去极大地提高效率,甚至在某些层面上,工作方式都是相似的,让人有种似曾相识的怪异感。尤其是这次,竟然是用脚本抓自己内部的网站了……谁让现有的系统不能自动做这些统计呢,连 SQL 也不暴露出来,手动做实在是太累了。
本文不成体系,说一些零碎的小点。
1. 如何修改只读控件的内容?
网页逻辑是,选择日期的文本框,点击之后由弹出的日期选择控件来完成日期输入,禁止用户修改日期文本框内容。于是通过 element.send_keys()
方法发送字符串时,会提示错误,无法修改只读属性的内容。
查了三四种解决方法,说什么的都有,甚至还有说模拟整个鼠标点击过程的……
简单有效的方法是,通过在页面内执行 JS 代码,将控件的只读属性取消。使用 webdriver
的 execute_script()
方法来在当前页面上执行 JS 脚本。核心是网页对象的 removeAttribute()
方法,指定移除 readonly
属性,不管他本来是 true
还是 false
。具体如何定位到想要取消属性的对象,有很多种方法,最方便的情况是这个控件有全局唯一的 ID,这样直接按照 ID 搜索即可。否则的话可能需要从一个可以被唯一确定的父级节点向下一步步查找。下例将一个 ID 为 targetElement
对象的只读属性移除。
# Python Code
from selenium import webdriver
# Settings
URL = "http://www.targetURL.com"
targetXPath = '//*[@id="targetElement"]'
# Browse page
driver = webdriver.Chrome()
driver.get(URL)
# Disable readonly attribute
driver.execute_script("document.getElementById('targetElement').removeAttribute('readonly')")
注意,由于 JS 里是单引号,这里的文本使用双引号。另外,引号内的语句正确性要手动检查。
这样取消掉属性之后就可以正常使用 send_key()
方法了,不过这个操作需要在每次页面发生刷新之后都要进行一次,执行结果是不会被缓存的。
2. 无法使用 element.clear() 方法?
有一个情况违反直觉:将控件的只读属性取消之后,仍然不能通过 element.clear()
方法清空这个文本框,错误提示大概是“无法对只读控件使用 clear() 方法”,但是实际上可以用 send_keys()
发送文本啊。
因为我很笨,所以我用的解决方法也很简单粗暴——把退格符当做按键通过 send_keys()
方法直接发给文本框,向左删除一个字符。
# Python Code
from selenium.webdriver.common.keys import Keys
...
element = driver.find_element_by_xpath(targetXPath)
element.send_keys(Keys.BACKSPACE)
字符太多怎么办?——办!
for i in range(0, 100):
element.send_keys(Keys.BACKSPACE)
没办法,我就会这样了。或者可以通过 JS 脚本来清空文本框内容?一定可以的,但是我不会 JS 啊……目前第一阶段,先解决问题是主要的。
3. 如何解决登录问题?
抓取目标是后台管理系统的一些统计数据,需要身份验证,一直是使用用户名和密码登录的。然后我就很天真地用 Selenium 去自动填写两项内容,点击登录。然后发现多弹出一个文本框要求输入验证码,看来是程序化登录被识别出来了。
然后就想着怎么解决这个二维码,以其复杂程度,开源的 OCR 不大可能有很大成功率识别出来。而登录系统有最多错误次数限制,不能贸然反复尝试。
然后就想着我先登录一次,然后保存下来 cookie,下次登陆的时候自动取用。试了一下,但因为每次启动浏览器驱动器,都是一个新进程,老的 cookie 没法用,还是过不了登录界面。
网上有文章说,很多工程师会在系统身份验证中留下后门,在保证安全的同时尽量让自动化测试更方便。问题在于,虽然我是我司的员工,但没有相关权限,也不认识搞这个系统的工程师,更有可能即便认识了人家也不希望我这么用。所以到头来还是得我自己解决这个问题。
咋办呢?——办!
那么我就手动登录然后自动抓数据好了。
# Pyhon Code
import time
...
driver.get(URL)
time.sleep(30)
...
打开网页后,先给我 30 秒时间登录系统,手动输入用户名和密码,然后如果遇到验证码的话,再手动输入一下,点击登录。此后等待计时器到时,再自动去扒数据。
啊!我觉得这个想法实在是太野蛮了,一点都不专业,也不优美,但是真能解决问题啊……太山寨了。有机会一定去学习如何用正经的办法去处理这样的情况,可能需要很多技术,很多技巧,很多工具,需要很多的学习。
大体上就是这样,我觉得自己虽然很业余,但是处理这些事情的思路是在是太亮了。