前面讲的图片验证码跟滑动验证码都是有迹可循,然而对于点触式验证码,通过个人处理就显的力不从心了。我们先来看看点触式验证码长什么样
类似这种需要按顺序点击图中文字,全部点对才正确的验证码就是点触式验证码,点击效果如下,
这里如果靠我们自己识别,样例文字识别是个问题,有些样例文字慎重各种歪曲变形,会极大降低我们识别率,图片中的文字更是难以识别,如上图中的短 字已经惨不忍睹了,即便有更好的思路恐怕也是难以实现。此文将介绍打码平台来处理我们的验证码,这里介绍的超级鹰,官网
超级鹰验证码识别-专业的验证码云端识别服务,让验证码识别更快速、更准确、更强大www.chaojiying.com开始之前我们先来理一下本文的思路,
1 将目标图片截下,截下的范围包括识别图片本身和问题
2 将图片以请求方式发送至打码平台 打码平台返回识别图片的坐标
3 我们根据返回的坐标模拟对该图片进行点击
思路很简单,我们一步一步来,首先注册超级鹰的账号,注册完记录自己的账户名跟密码,等下会在程序中使用,然后获取一个软件的id,获取方式在用户中心>>软件ID 新建完
将该软件id记下。官方给了一个demo,
Python语言Demo下载-超级鹰验证码识别API接口www.chaojiying.com可以直接下载使用,我这边稍微改了一下,把自己注册的信息填到里面即可,
import requests
from hashlib import md5
# 超级鹰用户名、密码、软件 ID、
CHAOJIYING_USERNAME = ''
CHAOJIYING_PASSWORD = ''
CHAOJIYING_SOFT_ID = 898777
class Chaojiying:
def __init__(self):
self.username = CHAOJIYING_USERNAME
self.password = md5(CHAOJIYING_PASSWORD.encode('utf8')).hexdigest()
self.soft_id = CHAOJIYING_SOFT_ID
self.base_params = {
'user': self.username,
'pass2': self.password,
'softid': self.soft_id,
}
self.headers = {
'Connection': 'Keep-Alive',
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
}
def PostPic(self, im, codetype):
"""
im: 图片字节
codetype: 题目类型 参考 http://www.chaojiying.com/price.html
"""
params = {
'codetype': codetype,
}
params.update(self.base_params)
files = {'userfile': ('ccc.jpg', im)}
r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
return r.json()
def ReportError(self, im_id):
"""
im_id:报错题目的图片ID
"""
params = {
'id': im_id,
}
params.update(self.base_params)
r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
return r.json()
if __name__ == '__main__':
chaojiying = Chaojiying()
# 本地图片文件路径 来替换 a.jpg
with open('a.jpg', 'rb') as f:
im = f.read()
#1902 验证码类型 官方网站>>价格体系 3.4+版 print 后要加()
res = chaojiying.PostPic(im, 1902)
if res['pic_str']:
data = res['pic_str']
接口是收费的,不过在微信绑定超级鹰账号会送1000个题分,够我们测试用了,接下来测试以上改写官方demo
这是官网给的例图,识别效果如下
{'err_no': 0, 'err_str': 'OK', 'pic_id': '8061023432201800003', 'pic_str': '7261',
'md5': '36944b46c1210cfd6b4508102bf1eb25'}
demo看看就好,我们来搞真正的点触验证码。今天的目标是yy的注册页面
YY安全中心 - 帐号注册aq.yy.com打开控制平台发现我们的目标在iframe标签里面
那这简单,我们获取iframe的src属性,就是我们真正的目标页面。同样开启selenium的远程调试模式
# win:
chrome.exe --remote-debugging-port=9222 --user-data-dir="D:packageselenium"
# mac
'Google Chrome' --remote-debugging-port=9222 --user-data-dir="/Users/chenpin/Downloads/package/seleium"
初始化
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver import ActionChains
chrome_options = Options()
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
# 题目类型 坐标多选,返回1~4个坐标,如:x1,y1|x2,y2|x3,y3
CHAOJIYING_KIND = 9004
class YYVerification:
def __init__(self):
self.url = 'https://aq.yy.com/p/reg/account.do?appid=&url=&fromadv=udbclsd_r'
self.driver = webdriver.Chrome(options=chrome_options)
self.wait = WebDriverWait(self.driver, 20)
self.chaojiying = Chaojiying()
进入到iframe的src属性所在的页面
self.wait.until(EC.presence_of_element_located((By.XPATH, '//iframe')))
i = self.driver.find_element_by_xpath('//iframe')
url_1 = i.get_attribute('src')
self.driver.get(url_1)
去到目标页面以后我们截取整个页面
screenshot = self.get_screenshot()
screenshot.save('yy.png')
time.sleep(1)
截取的图片如下
上面的截图截的是整个页面,接下来我们需要把目标图片剪切下来
def get_img_element(self):
"""
获取验证图片对象
:return: 图片对象
"""
element = self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'pw_main')))
return element
# 剪切图片
captcha = self.get_img_element()
left = captcha.location['x']
top = captcha.location['y']
right = captcha.location['x'] + captcha.size['width']
bottom = captcha.location['y'] + captcha.size['height']
im = Image.open('yy.png')
im = im.crop((left*2, top*2, right*2, bottom*2))
im.show()
这里还是使用pil来处理,裁剪的目标根据 左上右下的顺序进行裁剪, 眼尖的人看到我裁剪的时候全部*2了,这是为什么?这个本人也摸不着头脑,截下来的图片像素是2倍的,*2才能定位准确,我是mac机子,知道原因的欢迎给我留言,截图如下
接下来把图片发送给超级鹰
def get_points(self, captcha_result):
"""
解析识别结果
:param captcha_result: 识别结果
:return: 转化后的结果
"""
groups = captcha_result.get('pic_str').split('|')
locations = [[int(number) for number in item.split(',')] for item in groups]
return locations
bytes_array = BytesIO()
im.save(bytes_array, format('PNG'))
result = self.chaojiying.PostPic(bytes_array.getvalue(), CHAOJIYING_KIND)
locations = self.get_points(result)
返回吃下
{'err_no': 0, 'err_str': 'OK', 'pic_id': '6061111282201800007', 'pic_str': '363,298|275,246|276,172', 'md5': '6b94b1b62a8bd9ac5718b5a209038395'}
根据返回的数据稍微处理成
[[363, 298], [275, 246], [276, 172]]
看着这坐标,我疑惑了 这张图也才272*174,想起刚才我们是*2截图,那定位的话就应该除以2才对,根据这思路我们模拟按顺序点击
for location in locations:
ActionChains(self.driver).move_to_element_with_offset(self.get_img_element(), location[0]/2, location[1]/2).click().perform()
time.sleep(1)
识别成功,点击也成功!源代码请参考
wuzhenbin/yyVerificationgithub.com