Decode CAPTCHA by Selenium

参考:http://www.jianshu.com/p/7ed519854be7

获取验证码有两种思路

1.获取页面源代码,提取验证码图片

2.利用selenium截取页面,定位验证码元素的位置,利用Image进行处理,获取其中验证码部分

下面进行解析

1.获取页面源代码,提取验证码图片

如何获取源代码并提取验证码图片过程就不在分析了,既然看到这篇文章,相信这些工作都不在话下了。
这里只分析一下缺点:当提取验证码url后发现每次打开该验证码图片,其内容不断变化,
以搜狗验证码为例:http://weixin.sogou.com/antispider/util/seccode.php?tc=1486691901,该验证码是单独加载进页面,而非嵌入,这时候,单纯提取验证码url会发现当前验证码和提取验证码地址打开的内容不一样。这时候,我们需要一个更方便简单的方法。

2.利用selenium截取页面
selenium.webdriver 内置了截取当前页面的功能,其中:

a.WebDriver.Chrome自带的方法只能对当前窗口截屏,若是需要截取的窗口超过了一屏,就只能另辟蹊径了。

b.WebDriver.PhantomJS自带的方法支持对整个网页截屏。

在这里,我们利用两种方法均可,因为验证码界面通常比较简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#打开验证码界面
driver = webdriver.Chrome()
url = "http://weixin.sogou.com/antispider/?from=%2fweixinwap%3Fpage%3d2%26_rtype%3djson%26ie%3dutf8%26type%3d2%26query%3d%E6%91%A9%E6%8B%9C%E5%8D%95%E8%BD%A6%26pg%3dwebSearchList%26_sug_%3dn%26_sug_type_%3d%26"
driver.set_window_size(1200, 800)
cookies = info['cookies']

#处理cookies
driver.get(url)
for k,v in cookies.iteritems():
cookie_dict ={'name':k,'value':v}
driver.add_cookie(cookie_dict)
driver.get(url)

#获取截图
driver.get_screenshot_as_file('CrawlResult/screenshot.png')

#获取指定元素位置
element = driver.find_element_by_id('seccodeImage')
left = int(element.location['x'])
top = int(element.location['y'])
right = int(element.location['x'] + element.size['width'])
bottom = int(element.location['y'] + element.size['height'])

#通过Image处理图像
im = Image.open('CrawlResult/screenshot.png')
im = im.crop((left, top, right, bottom))
im.save('CrawlResult/code.png')

到这里,我们的验证码就拿下来啦,怎么处理呢?

1.pytesser,tesseract,OCR 等库处理

2.验证码不多,并为了提高识别效率和简化操作,我采用了调用打码平台(ruokuai)API方法,价格大概是1块钱打100-150个(根据验证码位数和是否数字/字母混合)

验证码类型和价格介绍http://www.ruokuai.com/home/pricetype

下面分析一下怎样使用打码平台:

1.先把开发文档贴上:http://wiki.ruokuai.com/

2.官方的调用方法(有两种:DOS版和普通版,下面贴的普通版,基本原理一样)

原理: 将验证码图片,打码平台账号,密码等按照指定格式调用API(访问URL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class RClient(object):

def __init__(self, username, password, soft_id, soft_key):
self.username = username
self.password = md5(password).hexdigest()
self.soft_id = soft_id
self.soft_key = soft_key
self.base_params = {
'username': self.username,
'password': self.password,
'softid': self.soft_id,
'softkey': self.soft_key,
}
self.headers = {
'Connection': 'Keep-Alive',
'Expect': '100-continue',
'User-Agent': 'ben',
}

def rk_create(self, im, im_type, timeout=60):
"""
im: 图片字节
im_type: 题目类型
"""
params = {
'typeid': im_type,
'timeout': timeout,
}
params.update(self.base_params)
files = {'image': ('a.jpg', im)}
r = requests.post('http://api.ruokuai.com/create.json', data=params, files=files, headers=self.headers)
return r.json()

def rk_report_error(self, im_id):
"""
im_id:报错题目的ID
"""
params = {
'id': im_id,
}
params.update(self.base_params)
r = requests.post('http://api.ruokuai.com/reporterror.json', data=params, headers=self.headers)
return r.json()

rc = RClient('username', 'password', 'soft_id', 'soft_key')
imagePath = 'CrawlResult/code.png'
im = open(imagePath, 'rb').read()
code_json = rc.rk_create(im, '验证码类型')# 类型和价格介绍http://www.ruokuai.com/home/pricetype