Python 网页抓取 - 处理验证码

在本章中,让我们了解如何执行网络抓取和处理用于测试用户是人还是机器人的验证码。


什么是 CAPTCHA(验证码)?

CAPTCHA的完整形式是Completely Automated Public Turing test to tell Computers and Humans Apart,这清楚地表明它是一种判断用户是否为人类的测试。

验证码是一种扭曲的图像,通常不容易被计算机程序检测到,但人类可以通过某种方式设法理解它。 大多数网站都使用 CAPTCHA 来防止机器人进行交互。


用 Python 加载验证码

假设我们要在一个网站上进行注册,并且有带有CAPTCHA的表格,那么在加载CAPTCHA图像之前,我们需要了解该表格所需的具体信息。 借助下一个 Python 脚本,我们可以了解名为 http://example.webscrapping.com 的网站上的注册表单的表单要求。

import lxml.html
import urllib.request as urllib2
import pprint
import http.cookiejar as cookielib
def form_parsing(html):
   tree = lxml.html.fromstring(html)
   data = {}
   for e in tree.cssselect('form input'):
      if e.get('name'):
         data[e.get('name')] = e.get('value')
   return data
REGISTER_URL = '<a target="_blank" rel="nofollow" 
   href="http://example.webscraping.com/user/register">http://example.webscraping.com/user/register'</a>
ckj = cookielib.CookieJar()
browser = urllib2.build_opener(urllib2.HTTPCookieProcessor(ckj))
html = browser.open(
   '<a target="_blank" rel="nofollow" 
      href="http://example.webscraping.com/places/default/user/register?_next">
      http://example.webscraping.com/places/default/user/register?_next</a> = /places/default/index'
).read()
form = form_parsing(html)
pprint.pprint(form)

在上面的Python脚本中,首先我们定义了一个函数,该函数将使用lxml python模块解析表单,然后打印表单要求如下 −

{
   '_formkey': '5e306d73-5774-4146-a94e-3541f22c95ab',
   '_formname': 'register',
   '_next': '/places/default/index',
   'email': '',
   'first_name': '',
   'last_name': '',
   'password': '',
   'password_two': '',
   'recaptcha_response_field': None
}

您可以从上面的输出中检查除 recpatcha_response_field 之外的所有信息都是可以理解和直接的。 现在的问题是我们如何处理这些复杂的信息并下载 CAPTCHA。 它可以在 pillow Python 库的帮助下完成,如下所示;


Pillow Python 包

Pillow 是 Python 图像库的一个分支,具有处理图像的有用功能。 它可以在以下命令的帮助下安装 −

pip install pillow

在下一个示例中,我们将使用它来加载验证码 −

from io import BytesIO
import lxml.html
from PIL import Image
def load_captcha(html):
   tree = lxml.html.fromstring(html)
   img_data = tree.cssselect('div#recaptcha img')[0].get('src')
   img_data = img_data.partition(',')[-1]
   binary_img_data = img_data.decode('base64')
   file_like = BytesIO(binary_img_data)
   img = Image.open(file_like)
   return img

上面的 python 脚本使用了 pillow python 包并定义了一个用于加载验证码图像的函数。 它必须与前面脚本中定义的名为 form_parser() 的函数一起使用,以获取有关注册表单的信息。 该脚本将以一种有用的格式保存验证码图像,该格式可以进一步提取为字符串。


OCR:使用 Python 从图像中提取文本

以有用格式加载验证码后,我们可以借助光学字符识别 (OCR) 提取它,这是一种从图像中提取文本的过程。 为此,我们将使用开源 Tesseract OCR 引擎。 它可以在以下命令的帮助下安装 −

pip install pytesseract

示例

这里我们将扩展上面的Python脚本,它使用Pillow Python包加载验证码,如下 −

import pytesseract
img = get_captcha(html)
img.save('captcha_original.png')
gray = img.convert('L')
gray.save('captcha_gray.png')
bw = gray.point(lambda x: 0 if x < 1 else 255, '1')
bw.save('captcha_thresholded.png')

上面的 Python 脚本将以黑白模式读取验证码,这将清晰且易于传递给 tesseract,如下所示 −

pytesseract.image_to_string(bw)

运行上述脚本后,我们将获得注册表的验证码作为输出。