去年Ele练手弄了一个repo,玩了几个网站的登录和打卡功能之后就把这个小东东扔到香蕉派上,一并加入cron套餐。之后就没再理之。
小东西好好地跑了几个月,之后的某一天登上去看日志,发现好几个网站的自动登录和打卡都error了,懵逼之下跑到那些个网站上一看,哎呀,改版变规则什么的,就是辣么任性/(ㄒoㄒ)/~~
所以只能重写了。但是重写并非分分钟的事情(过程见[Python]沪江部落自动登录打卡),懒癌犯了的Ele就暂时这样LET IT GO了。
之后这个repo居然陆陆续续有人star,这引发了Ele的羞耻心,毕竟,坑人是不对的不对的不对的!!!又后来,懒惰的Ele看到了selenium,再然后又看到了splinter,正如干柴遇上了烈火(貌似有什么不对的东西混进来了O__O "…)
此为前因。
splinter是Python系用来测试web应用的一个工具,允许你自动化浏览器操作,例如访问URL,与页面元素进行交互等。
因此,我们可以用它来模拟登陆过程(输入用户名密码,点击登陆)和打卡(直接访问URL或者点击打卡按钮)过程,而后面的JavaScript等一系列点击响应事件则交给splinter处理,而无需像之前那样操心网络层面与服务器端是如何交互的。
为了和前面手解登录和打卡作对比,此次仍然以沪江部落为例
准备
- 使用pip安装splinter包:
1
pip install splinter
- 浏览器准备
- 如果使用firefox,则需要下载geckodriver,并将其解压到PATH可以找到的目录中。否则,运行时会出现错误:
Selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
- 如果使用chrome,则除了要安装chrome浏览器外,还需要下载chromedriver并解压。我们这里以chrome为例,将chromedriver解压缩到
/Users/elexu/Downloads
下。
准备好了,我们先来讲讲如何模拟登陆
登陆
我们先来看看一般手动登录过程。
从浏览器访问http://www.hjenglish.com/
,可以看到右上角有个登录按钮。点击登录按钮后,在弹出的登录框里填入正确的用户名密码,点击绿色的登录按钮。等待片刻即可登录成功。
现在,我们来看看,如何使用splinter来实现这一过程。
首先,我们要初始化一个Browser实例: 1
2from splinter import Browser
b = Browser(driver_name = "chrome", executable_path = "/Users/elexu/Downloads/chromedriver")
打开chrome的开发者工具,审查登录按钮。
为了让登录框弹出,我们需要定位到这个元素,然后点击一下。splinter提供了多种查找元素的方法,例如,css, xpath, tag, id, name等。我们现在来看看如何根据上面的图来找到这个登录按钮,并完成点击操作:
1 | # 访问网站 |
这里有几点说明: - 这里需要sleep一段时间,使得页面可以完全加载完毕,否则有可能在查找元素的时候,想查找的元素还未加载出来,从而导致查找不到元素。同理,点击完后,也要有一定的时间供给页面加载 - 使用Browser实例哪一个find_by_xxx方法就看元素如何是如何写的。像上面用下标定位出来的,万一页面元素发生了变动,就会失效了。如果元素可以直接通过name/id来定位,首选find_by_name和find_by_id - find_by_xpath方法返回的是一个splinter.element_list.ElementList
实例。我们可以直接在这个实例上调用click
方法进行点击,也可以像上面代码那样,找到定位到的第一个元素,再调用click
方法。
现在,从浏览器上可以看到,登录框已经弹出来了。接下来就是依葫芦画瓢找到用户名密码所在的输入框,填充值,然后点击登录按钮。 1
2
3b.fill("username", "ele")
b.fill("password", "xxxxxx")
b.find_by_xpath('//*[@id="hp-login-normal"]/button').click()fill(name, value)
方法的作用是用参数value
的内容填充由name
标识的域。运行上面代码,我们可以在打开的浏览器上看到,用户名密码输入框中迅速地填充了我们指定的值,然后在click操作后,成功登录。一切都跟我们手工登录过程一毛一样。
打卡
打开部落个人home页面,然后审查右上角的打卡按钮
我们要做的很简单,只要点击这个按钮即可
1 | bulo_home = "http://bulo.hujiang.com/home" |
代码很直观,但是有几点说明: - 供给页面加载时间还是需要的,这里我们选择了3s。其实可以不用那么长,这个可以自己调整 - Browser()实例也提供了多种is_element_present_by_xxx方法,可以来检测当前页面是否存在某个元素。这里我们需要检测下页面是否有打卡按钮,如果没有,就不用点了。
运行一下,程序抛异常: 1
ElementNotVisibleException: Message: element not visible
这是一种方法。当然,我们还可以利用[Python]沪江部落自动登录打卡中找到的url,直接访问,进行打卡 1
2
3import random
SIGN_URL = "http://bulo.hujiang.com/app/api/ajax_take_card.ashx?%.17f"%random.random()
b.visit(SIGN_URL)
通过splinter,实现模拟人与浏览器的互动,写代码的人完全就不用管底层是怎么跟对端服务器进行交互的。通过splinter封装的API,基本可以满足所需的浏览器操作。简直就是懒人常备小利器。
另外,很多时候,网站变更是隐藏在背后的,大多数让用户无感知。因此,不管底层逻辑怎么变更,只要打开看到的页面没有变动,这一套自动登录打卡便行之有效。免去了代码的频繁变更以适应新的网站逻辑。
于是,懒惰的Ele分分钟就把daka全部迁成splinter实现了~
当然,这种方法知其然而不知其所以然,一点都不geek。另外,对那些想要通过了解机制来学到点什么的小伙伴来说,最好还是跟自己死磕一下,老老实实抓包看代码吧。