爬虫之图片验证码处理
了解常见验证码
在日常生活与工作中,在进行各类设计个人账户安全的操作时,往往需要填写各种验证码来进行验证,短信、语音、文字、问答、图片、拖拽、旋转腾挪、拼图接图.......千奇百怪,各种各样,种类繁多,花样迭起!就拿奇葩验证码鼻祖的12306来说,如今我们在12306中可以碰到各种有趣,各种类型的验证码的原因,要归功于为抢票事业做出巨大贡献的——黄牛们,它的“进化史”就是一部不断与黄牛和抢票软件“斗智斗勇”的历史。
目前我们常见的验证码,无非就是文本、图像以及音频这三大类。
而当文本验证码仍容易被机器“击破”时,图像验证码就应运而生了。通常是会提供一些物体、动物、植物、人、风景之类的图像,让我们选择正确的图像进行标记。这就是以12306为首的图像验证码了,但是这个还不算后来图像验证码又增加了新的玩法,比如旋转图片,比如拼图以及宫格,目的还是为了对抗爬虫这些机器。
接下来是音频验证码,这种相比前两种数量相对要小一些,主要是会给我们一段录音,里面有随机的单词或数字,有的会加一些噪音,我们基于录音输入其中听到的单词或数字,或者把它读出来。从安全性上来说,声音验证码比文本和图像等级要提升一个层级,因为机器想要听录音并分辨,这个难度会非常大。
验证码的处理方案
• 手动输入(input) 这种方法仅限于登录一次就可持续使用的情况
• 图像识别引擎解析 使用光学识别引擎处理图片中的数据,目前常用于图片数据提取,较少用于验证码处理
• 打码平台 爬虫常用的验证码解决方案
图像识别引擎
OCR,即Optical Character Recognition,光学字符识别,是指通过扫描字符,然后通过其形状将其翻译成电子文本的过程,对应图形验证码来说,它们都是一些不规则的字符,这些字符是由字符稍加扭曲变换得到的内容,我们可以使用OCR技术来讲其转化为电子文本,然后将结果提取交给服务器,便可以达到自动识别验证码的过程
tesserocr与pytesseract是Python的一个OCR识别库,但其实是对tesseract做的一层Python API封装,pytesseract是Google的Tesseract-OCR引擎包装器;所以它们的核心是tesseract,因此在安装tesserocr之前,我们需要先安装tesseract。
图片识别引擎环境的安装
1 引擎的安装
• mac环境下直接执行命令
brew install --with-training-tools tesseract
• windows环境下的安装 可以通过exe安装包安装,下载地址可以从GitHub项目中的wiki找到。安装完成后记得将Tesseract 执行文件的目录加入到PATH中,方便后续调用。
• linux环境下的安装
sudo apt-get install tesseract-ocr
2 Python库的安装
# PIL用于打开图片文件
pip/pip3 install pillow
# pytesseract模块用于从图片中解析数据
pip/pip3 install pytesseract
本次案例我们使用图片识别引擎识别验证码登陆古诗文网
通过分析我们发现验证码点击刷新的链接是:
所以我们请求10次本链接获取10张图片,进行图片识别
import time
from PIL import Image
import pytesseract
import requests
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
}
image_url = 'https://so.gushiwen.org/RandCode.ashx'
# 下载验证码图片
session = requests.Session() # 使用session是为了保证验证码的请求和登陆请求信息一致
for i in range(10):
r = session.get(image_url, headers=headers)
with open('images/code'+str(i)+'.jpg', 'wb') as fp:
fp.write(r.content)
time.sleep(10)
print('下载完成第'+str(i)+'张!')
# 依次识别并保存到文件中
# 进行二值处理
def erzhihua(image, threshold):
''':type image:Image.Image'''
image = image.convert('L')
table = []
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(1)
return image.point(table, '1')
# 对刚才保存的10张图片进行识别
for i in range(10):
im = Image.open('images/code' + str(i) + '.jpg')
im = erzhihua(im, 127)
im.show()
result = pytesseract.image_to_string(im, lang='eng')
print(result)
但是很遗憾10次或者更多次数才能打码成功一次。
打码平台
此时我们就要寻求专业的打码平台,申请第三方的平台,宋宋试了一下阿里提供的各种免费的打码平台。链接:https://market.aliyun.com/products/?keywords=图片识别验证码,但是识别效果不是很佳(哈哈因为是免费的缘故吧!只有标记优品的那个还不错其他的也可以自行试一试)。
为了测试它的识别效果,我们尝试申请成交次数最多的那个,查看官方API说明如下:
因此我们使用验证码打码平台获取验证码并登录
实现思路:
使用requests.session获取图片并进行本地保存
使用打码平台识别图片
获取登录链接,登陆链接是一个post请求,并携带了你的表单中填入的用户名和密码
登陆获取cookies, 才能去访问用户的个人页
import json
from PIL import Image
import pytesseract
import requests
import urllib.request
import base64
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
# 1. 使用requests.session获取图片并进行本地保存
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
, 'Host': 'www.xqb5200.com'
, 'Referer': 'https://www.xqb5200.com/login.php'
}
session = requests.Session() # 使用session是为了保证验证码的请求和登陆请求信息一致
code_image_url = "https://www.xqb5200.com/checkcode.php"
r = session.get(code_image_url, headers=headers)
with open('code.jpg', 'wb') as fp:
fp.write(r.content)
# 2. 使用打码平台识别图片
# 修改API说明修改接口地址
url = 'https://imgurlocr.market.alicloudapi.com/urlimages'
method = 'POST'
appcode = '你的APPCODE'
querys = ''
bodys = {}
f = open(r'code.jpg', 'rb')
contents = base64.b64encode(f.read())
f.close()
bodys['image'] = bytes("data:image/jpg;base64,", encoding="utf8")+contents
post_data = urllib.parse.urlencode(bodys).encode(encoding='UTF8')
request = urllib.request.Request(url, post_data)
# 根据API的要求,定义相对应的Content-Type
request.add_header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
request.add_header('Authorization', 'APPCODE ' + appcode)
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
response = urllib.request.urlopen(request, context=ctx)
content = response.read()
if (content):
code = json.loads(content.decode('utf-8'))
print(code)
print(code['result']['words'])
# 3. 获取登录链接,登陆链接是一个post请求,并携带了你的表单中填入的用户名和密码
login_url = "https://www.xqb5200.com/login.php?do=submit"
# 用户名和密码大家可以注册一个新的用户
data = {
"username": "你的用户名",
"password": "你的秘密",
"checkcode": code,
"action": "login",
"submit": "%26%23160%3B%B5%C7%26%23160%3B%26%23160%3B%C2%BC%26%23160%3B"
}
# 4. 登陆获取cookies, 才能去访问用户的个人页
response = session.post(url=login_url, headers=headers, data=data)
response.encoding = 'utf-8'
cookies = response.cookies
# 查看登陆是否成功了
with open('logsucess.html', 'wb') as fp:
response.encoding = response.apparent_encoding
fp.write(response.content)
这样我们还是可以识别这个验证码的,如图
最后保存到本地的文件,显示登陆成功
还有滑动验证码和点触验证码的使用以及selenium+验证码登陆,期待下篇文章给大家分享...