1、图形验证码识别技术
阻碍我们爬虫的,有时候正是在登录或者请求一些数据时候的图形验证码。因此这里我们讲解一种能将图片翻译成文字的技术。将图片翻译成文字一般被称为光学文字识别(Optical Character Recognition),简写为OCR。实现OCR的库不是很多,特别是开源的。因为这块存在一定的技术壁垒(需要大量的数据、算法、机器学习、深度学习知识等),并且如果做好了具有很高的商业价值。因此开源的比较少。这里介绍一个比较优秀的图像识别开源库:Tesseract。
2、Tesseract
2.1 定义
Tesseract是一个将图像翻译成文字的OCR(光学文字识别,Optical Character Recognition),目前由谷歌赞助。Tesseract是目前公认最优秀、最准确的开源OCR库。Tesseract具有很高的识别度,也具有很高的灵活性,他可以通过训练识别任何字体。
2.2 Windows系统安装Tesseract
Windows在Python中调用Tesseract时,既需要安装tesseract.exe,也需要安装pytesseract库;
在链接中载可执行文件:https://github.com/tesseract-ocr/
pip install pytesseract
在ubuntu下通过以下命令进行安装
sudo apt install tesseract-ocr
2.3 设置环境变量
安装完成后,如果想要在命令行中使用Tesseract,那么应该设置环境变量。Mac和Linux在安装的时候就默认已经设置好了。
在Windows下把tesseract.exe所在的路径添加到PATH环境变量中。
还有需要把训练的数据文件路径(tessdata)也放到环境变量中。
在环境变量中,添加一个
TESSDATA_PREFIX=D:\Tesseract-OCR\tessdata
进入cmd输入下面的命令查看版本,正常运行则安装成功
tesseract --version
2.4 在命令行中使用tesseract识别图像
tesseract 图片路径 识别后文件保存路径
不需要加尾缀,默认会添加尾缀txt
tesseract demo.png test
识别中文图像,需要下载语言安装包
语言安装包地址:https://github.com/tesseract-ocr/tessdat
中文语言安装包文件名:chi_sim.traineddata
2.5 在代码中使用tesseract识别图像
import pytesseract
from PIL import Image
pytesseract.pytesseract.tesseract_cmd = r"F:\Tesseract-OCR\tesseract.exe"
tessdata_dir_config = r"--tessdata-dir 'F:\Tesseract-OCR\tessdata'"
img = Image.open("demo.jpg")
print(pytesseract.image_to_string(img, config=tessdata_dir_config, lang="eng"))
2.6 用pytesseract处理图形验证码
验证码接口:https://passport.lagou.com/vcode/create?from=register&refresh=1513081451891
import pytesseract
import os
from PIL import Image
from urllib import request
def get_img():
url = "https://passport.lagou.com/vcode/create?from=register&refresh=1513081451891"
if not os.path.exists("img"):
os.mkdir("img")
request.urlretrieve(url, "img/test.png")
img = Image.open("img/test.png")
return img
def recognition(img):
pytesseract.pytesseract.tesseract_cmd = r"F:\Tesseract-OCR\tesseract.exe"
tessdata_dir_config = r"--tessdata-dir 'F:\Tesseract-OCR\tessdata'"
result = pytesseract.image_to_string(img, config=tessdata_dir_config, lang="eng")
print(result)
if __name__ == '__main__':
img = get_img()
recognition(img)
注意:
tesseract识别白底黑字的二维码比较准确,其他效果很一般;
登入图鉴 二维码识别网站
通过图鉴 二维码识别网站的API登入 图鉴 二维码识别网站
总结:
图片base64解码那里卡了很久,但其实很简单,页面中一共有两个是关于验证码的,一个是变化的url接口,一个是不变的src属性,当发现拿src解码时出错,应该要第一时间拿获取到的src属性和页面中的去对比的,通过长度等,去比较哪里不一样,这里是因为网页中的src属性中是自动换行了的,Base64一行不能超过76字符,超过则添加回车换行符,获取到的src属性中换行符都是被%0A替代了,所以在base64解码的时候会报错填充不正确(Incorrect padding),所以只需将%0A替换成\n,再进行解码就正常了;
from tujianAPI import base64_api
from selenium import webdriver
from PIL import Image
from configparser import ConfigParser
import base64
import time
import os
class TujianSpider(object):
def __init__(self, user, password):
self.url = "http://www.ttshitu.com/login.html"
self.driver = webdriver.Chrome()
self.user = user
self.password = password
def login(self, captcha):
if not self.driver.find_element_by_name("userName").get_attribute("value"):
self.driver.find_element_by_name("userName").send_keys(user)
self.driver.find_element_by_name("password").send_keys(password)
self.driver.find_element_by_name("captcha").send_keys(captcha)
btn = self.driver.find_element_by_xpath("//button[@class='layui-btn layui-btn-normal full-width']")
self.driver.execute_script("arguments[0].click();", btn)
def save_img_captcha(self):
img_base64 = self.driver.find_element_by_id("captchaImg").get_attribute("src").split(",")[1].replace('%0A', '\n')
print(img_base64)
img_byte = base64.b64decode(img_base64)
if not os.path.exists("img"):
os.mkdir("img")
with open('img/demo.jpg', 'wb') as f:
f.write(img_byte)
def get_captcha(self):
img = Image.open("img/demo.jpg")
captcha = base64_api(uname=self.user, pwd=self.password, img=img)
print(captcha)
return captcha
def run(self):
# 1 selenium打开登入页面
self.driver.get(self.url)
while True:
# 2 保存验证码图片
self.save_img_captcha()
# 3 调用图鉴提供的接口,识别保存下来的图片验证码
captcha = self.get_captcha()
# 4 传入验证码,登入
self.login(captcha)
time.sleep(1)
# 5 登入成功后,结束循环
if self.driver.current_url != self.url:
break
def userdata():
cfg = ConfigParser()
r = cfg.read("userdata.ini")
user = cfg.get("user", "user")
password = cfg.get("password", "password")
return user, password
if __name__ == '__main__':
user, password = userdata()
tujianspider = TujianSpider(user, password)
tujianspider.run()