12306破解!
- 2020 年 3 月 13 日
- 筆記
验证码(CAPTCHA),是一种区分用户是计算机还是人的公共全自动程序。对于研究爬虫来说,这应该是爬虫的“天敌”。
原因就是在于,现在各大网站为了反爬,都加入了点选图片验证码,滑动验证码,英文乱码等验证码干扰,因此想要爬取网站,需要做的第一步就是解决验证码的问题。
聊到验证码,简单的看图输入型的数字验证码,英文验证码,中文验证码,都已经被爬虫工程师机灵的攻克了,孕育而生的又有需要按照图片显示的数据公式进行计算后输入结果的验证码,以及非常有名的12306魔鬼点选验证码。
这一类的验证码很难通过简单的机器学习等方式进行操作,毕竟遇到点选“白百合”还是“王珞丹”,人脸识别也要束手无策。
本篇就针对12306的点选验证码进行讲解和破解。让我们一起来学习一下。

点选验证码是近代用于验证是否为人类的一种措施之一。他的验证方式是通过给出需要点击的图片类型,用户需要根据给出的几种图片中,正确点击出正确的图片,否则就会视为自动化脚本,不给予通过验证。这为反爬虫工作提升了一个新的高度,因为基本上传统的破解方式都已经不能绕过该验证码。若真想破解点选验证码,只有使用深度学习网络,训练出图片分类器,才可能有机会破解点选验证码。
个人观点: 对于开发周期太短,技术实现太复杂的情况我其实是推荐用服务商的接口。因为如果花太多时间在绕过验证码这方面,还不如优化一下代码,使得代码运行速度更快、鲁棒性更强,(另外实在不行的情况下我们也可以让功能先上线再说…技术的东西慢慢不上),毕竟攻城狮能合理调配资源解决问题也是牛攻城狮;
另外对于点选验证码,这种的破解难度十分高,为什么这么说呢?
是因为如果要破解点选图片验证码,这就与计算机视觉(CV)的知识有交叉了。我来简单说下计算机是如何识别图片的。
首先现在的一般图片都是由二维的像素点加通道数构成的,在计算机眼里,就是一个三位数组,每个像素点的值代表的是亮度,0-255之间;举个例子,对于一张灰度图片例如长这样:

它由字母以及噪声构成,他对应的量化矩阵就只有一个通道,图片尺寸大小的一个矩阵。如果想要训练计算机认识这个图片,人们肯定不想把噪声也放进去的,人们就会通过矩阵与卷积核进行卷积,得到一张过滤后的图片,卷积核就是相当于一个滤波器。
常见的卷积核有拉普拉斯算子,高斯算子等,用已知的这些算子可以对图片进行平滑化的操作,但我们想要的是图片的关键部分啊!!!
这时候深度学习就出来了,通过一个数据池,里面有很多这种类型的验证码,通过计算,不断地拟合出一个适合这个数据池使用的卷积核,最后通过人工设置的数轮计算后,拿到卷积核,我们便可以拿这个拟合出来的卷积核对新的图片进行卷积,从而判断这个图片是什么。但这个只是一个通道,尺寸比较小的图片,对于一些尺寸较大的、彩色的图片,那么这个计算量就十分之大了。
回到12306的验证码,验证码所显示的图片类型是完全随机的,一会是洗洁精图片,一会是黑板的图片,一会是玛雅神殿的图片,对于一般的开发者来说,不可能通过深度学习训练出一个适合12306的图片预测器,因为数据量实在是太大了。
这时我们不妨可以借用第三方接口,来满足我们的需要,俗话说得好:”永远不要用自己的业余挑战别人的职业”。
别人通过专业的机器、大量的人员来解决专业领域的问题,我们可以通过分享部分的利润,来实现自己的功能,这个双赢的局面,也能增加全球的GDP嘛哈哈。直接使用第三方平台吧,直接调用别人的接口快速完成业务是真的爽。
本文使用的第三方服务:
https://2captcha.com/zh?from=8873291
根据本人测试,这是目前识别率最高的平台,而且调用他们家的api也是十分简单而且响应速度也不错。另外他们家除了有点选验证码外,还有很多的验证码解决方案。
下面直接敲代码,一起体验使用api的快感。
首先看下官方文档:

基本意思是我们得要先把图片发至:
https://2captcha.com/in.php
后再从
https://2captcha.com/res.php
取得我们所需要的坐标。而这个就是官方提供的参数:


其中说明一下这两个参数:
- textinstructions 标识如果图片中没有显示需要点击的图片类型,则需要传送一个字段过去。用文本形式,即字符串。ps:因为这个是国外网站,我们需要传送一个英语文本过去,这里提示一下,可以使用国内的大厂子的翻译平台api转换,遇到图片显示时,我们也可以使用大厂子的ocr图片转文字或者使用python库pytesseract进行转换为文本,再用翻译api对文本进行翻译再请求。
- imginstrutions 这个类似上面那个也是用于标识需要点击的图片类型,不过这个是用图片进行标识。
下面,直接封装一个请求函数,我已经将常用的参数都写进函数里面了,以后调用的时候就可以十分方便了,美滋滋!
from requests import Session from urllib.parse import urlencode from json import loads class Captcha: def__init__(self, key): self.send_url ='https://2captcha.com/in.php' self.result_url ='https://2captcha.com/res.php' self.key = key self.session = Session() defclick_image_captcha(self, image_name, method='post', imginstructions='', textinstructions=''): data ={ 'key': self.key, 'method': method, 'coordinatescaptcha':1, 'json':1, } if textinstructions: data['textinstructions']= textinstructions if textinstructions: data['imginstructions']= imginstructions files ={ 'file':open(image_name,'rb') } params ={ 'method':'post', 'url': self.send_url, 'data': data, 'files': files, } response = loads(self.session.request(**params).text) return response defget_result(self, request_id): params ={ 'key': self.key, 'action':'get', 'id': request_id, 'json':1 } response = self.session.request(method='get', url=self.result_url +'?'+ urlencode(params)) return response.text
这个是测试用的png,命名为111.png。

根据上面给出的函数接口,直接调用并传入图片文件111.png,让我们一起看看返回结果。
t = Captcha('85c*****************a939') answer = t.click_image_captcha(image_name='111.png', textinstructions='click on images with seal.') print(answer)
请求并打印一下得到这个。

而拿到的这个是什么东西呢?这是平台给出的,用于请求答案的唯一request-id码,我们将拿到的request值再通过请求函数请求一次。
answer = t.get_result('63283539784') print(answer)


我们最后对照后发现,我们得到了两个坐标,我们可以使用图片工具打开图片:




通过上图发现,这两个坐标的位置正是验证码中那两个符合条件的印章位置,最后我们可以通过selenium模拟登陆,模拟点击完成验证码的突破了。
另外需要提醒的是,selenium模拟点击的坐标需要另外计算,也就是说先要知道图片所在浏览器的坐标位置,再通过这个位置,与拿到的坐标相加再点击才能正确点击该点的位置,还有使用selenium库点击后,鼠标点击的坐标并不会回到绝对坐标中的0,0位置,而是会在点击后的原有位置设为绝对坐标(0,0),用人话说就是需要在点击以后,另外做一个反向移动的操作,这个操作我已经封装了一个函数了,需要的自取把,在这里就不演示了 因为下面顺便发出封装好的selenium模拟点击。
defclick_locxy(dr, x, y, left_click=True): if left_click: ActionChains(dr).move_by_offset(x, y).click().perform() else: ActionChains(dr).move_by_offset(x, y).context_click().perform() ActionChains(dr).move_by_offset(-x,-y).perform()
本文介绍到这里。
总结
在这篇文章里,我们针对“12306”魔鬼验证码进行了实验。可以看到精度还是相当高的,确实是给爬虫操作解决了大麻烦。
2captcha 本身我看到很多爬虫博主都在使用,其针对滑动验证码,以及谷歌系列的点选验证码的效果都非常好。另外调用api的形式简单方便,确实是非常值得推荐的。