7.用python写网络爬虫,验证码处理

news2024/11/15 21:33:20

前言

    验证码(CAPTCHA)的全称为全自动区分计算机和人类的公开图灵测试(Completely Automated Public Turing testtotellComputersand Humans Apart)从其全称可以看出,验证码用 于测试用户是否为真实人类。一个典型的验证码由扭曲的文本组成,此时计算机程序难以解析,但
人类仍然可以( 希望如此 )阅读。许多网站使用验证码来防御与其网站交互的机器人程序。比如许多银行网站强制每次登录时都需要输入验证码,这就令人十分痛苦。本章将介绍如何自动化处理验证码问题,首先使用光学字符识别(Optical Character Recognition , OCR),然后使用一个验证码处理 API。

7.1注册账号

    在前一章处理表单时,我们使用手工创建的账号登录网站,而忽略了自动化创建账号这一部分, 这是因为 注册表单需要输入验证码。注册页面为 http://example.webscraping.com/user/register, 如下图所示
    请注意,每次加载表单时都会显示不同的验证码图像。为了了解表单需要哪些参数,我们可以 复用上一章编写的parse_form( )函数。
    前面的代码中,除recaptcha_response_field之外的其他域都很容易处理,在本例中这个域要求我们从图像中抽取出strange字符串。

7.1 .1 加载验证码图像  

    在分析验证码图像之前,首先需要从表单中获取该图像。通过 Firebug 可以看到,图像数据是嵌入在网页中的,而不是从其他 URL 加载过来的,如下图所示
 
    为了在Python中处理该图像,我们将会用到 Pillow 包,可以使用如下命令通过 pip 安装该包。
    pip install pillow
    其他安装 Pillow 的方法可以参考 http://pillow.readthedocs. org/installation.html
    Pillow 提供了一个便捷的Image类,其中包含了很多用于处理验证码 图像的高级方法。下面的函数使用注册页的HTML作为输入参数,返回包含验证码图像的工mage对象。
    开始几行使用 lxml 从表单中获取图像数据。图像数据的前缀定义了数据类型。在本例中,这是一张进行了 Base64 编码的 PNG 图像,这种格式会使用ASCII编码表示二进制数据。我们可以通过在第一个逗号处分割的方法移除该前缀。然后,使用 Base64 解码图像数据,回到最初的二进制格式。要想加载图像,PIL需要一个类似文件的接口所以在传给Image类之前,我们又使用了Bytes IO对这个二进制数据进行了封装。
    在得到这个格式更加合适的验证码图像后,我们就可以尝试从中抽取文本了

7.2 光学字符识别 

    光学字符识别( Optical Character Recognition, OCR)用于从图像中抽取文本。本节中,我们将使用开源的Tesseract OCR 引擎。该引擎最初由惠普公司开发,目前由 Google 主导。Tesseract 的安装说明可以从 https://code.google.com/p/tesseract-ocr/wiki/ReadMe获取。然后,可以使用p ip安装其Python封装版本pytesseract。
    pip install pytes seract 
如果直接把验证码原始图像传给 pyte sseract,解析结果一般都会很糟糕。
    上面的代码在执行后,会返回一个空字符司抖也就是说 Tesseract 在抽取输入图像中的字符时失败了。这是因为 Tesseract 的设计初衷是抽取更加典型的文本,比如背景统一的书页。如果我们想要更加有效地使用 Tesseract,需要先修改验证码图像,去除其中的背景噪音,只保留文本部分。 为了更好地理解我们将要处理的验证码系统,下图中又给出了几个示例验证码。

 

    从上图的例子可以看出,验证码文本一般都是黑色的,背景则会更加明亮,所以我们可以通过检查像素是否为黑色将文本分离出来,该处理过程又被称为阁值化。通过 Pillow 可以很容易地实现该处理过程。
    此时,只有或淘值小于1的像素才会保留,也就是说,只有全黑的像素才会保留下来。这段代码片段保存了3张图像,分别是原始验证码图像、转换后的灰度图以及阔值化处理后的图像。下图所示为每个阶段保存的图像。

 

    最终,经过阔值化处理的图像中,文本更加清晰,此时我们就可以将其传给 Tesseract 进行处理 了。
    成功了!验证码中的文本已经被成功抽取出来了。在我测试的100张图片中,该方法正确解析了其中的84个验证码图像。由于示例文本总是小写的ASCII字符,因此我们可以将结果限定在这些字符中 ,从而进一步提高性能。
    在对相同的 100 张图片的测试中,其识别率提高到了88%。下面是目前注册脚本的完整代码。

 

    regi ster( )函数下载注册页面,抓取其中的表单,并在表单中设置新账号的名称、邮箱地址和密码。然后抽取验证码图像,传给OCR函数,并将OCR函数产生的结果添加到表单中。接下来提交表单数据,检查响应URL确认注册是否成功。如果注册失败,响应URL仍然会是注册页,这既可能是因为验证码图像解析不正确,也可能是注册账号的邮箱地址己经存在。现在,只需要使用新账号信息调用 regi ster( )函数,就可以注册账号了。

7.2.1 进一步改善 

 要想进一步改善验证码 OCR 的性能, 下面还有一些可能会使用 到 的方法:

实验不同阙值:
腐蚀阙值文本,突出字符形状:
调整图像大小( 有时增大只寸会起到作用 ):
根据验证码字体训练OCR工具:
限制结果为字典单词。
    如果你对改善性能的实验感兴趣,可以使用该链接中的示例数据:https://bitbucket.org/wswp/ code/src/tip/chapter07/samples/。不过对于我们注册账号这一目的,目前88%的准确率已经足够 了,这是因为即使是真实用户也会在输入验证码文本时出现错误。实际上,即使1%的准确率也是足够的,因为脚本可以运行多次直至成功,不过这样做对服务器不 够友好,甚至可能会导致 IP 被封禁。

7.3 处理复杂验证码

    前面用于测试的验证码系统相对来说比较容易处理,因为文本使用的黑色字体与背景很容易区分,而且文本是水平的,无须旋转就能被 Tesseract 准确解析。一般情况下,网站使用的都是类似这种比较简单的通用验证码系统,此时可以使用OCR方法。但是如果网站使用的是更加复杂的系统,比如Google 的 reCAPTCHA , OCR 方法则需要花费更多努力,甚至可能无法使用。
    下图所示为网络上找到的一些更加复杂的验证码图像。
    在这些例子中,因为文本被置于不同的角度,并且拥有不同的字体和颜色,所以要使用OCR方法的话,需要更多工作来清理这些噪音。即使是真实人类,解析这些图像也可能会存在困难,尤其是对于那些视觉障碍人士而言。

 7.3.1 使用验证码处理服务

    为了处理这些更加复杂的图像,我们将使用验证码处理服务。验证码处理服务有很多,比如 capt cha.com 和 deathbycaptcha.com,一般其服务价位在1美元1000个验证码图像左右。当把验证码图像传给它们的API时,会有人进行人工查看,并在 HTTP 响应中给出解析后的文本。一般来说该过程在30秒以内。在本节的示例中,我们将使用9kw.eu的服务。虽然该服务没有提供最便宜的验证码处理价格,也没有最好的API设计,但是使用该API可能不需要花钱。这是因为9kw.eu 允许用户人工处理验证码以获取积分,然后花费这些积分处理我们的验证码。

7.3.2 9kw入门

    要想开始使用9kw,首先需要创建一个账号,注册网址为https://www. 9kw.eu/register.html,注册界面如下图所示
    然后,按照账号确认说明进行操作。登录后,我们被定位到https://www. 9kw.eu/usercaptcha.html,其页面显示如下图所示

 

    在本页中,需要处理其他用户的验证码未获取后面使用 API 时所需的积 分。在处理了几个验证码之后,会被定位到https:// www.91α1.eu/index. cgi?action=userapinew&source=api来创建API key。

     9kw 验iiH马 API

    9kw的API文档地址为https://www.9kw.eu/api.html#apisubmit-tab。我们用 于提交验证码和检查结果的主要部分总结如下。

  提交验证码

URL: https://www.9kw.eu/index.cgi( POST)

apikey: 你 的 API key
action:必须设为“usercaptchaup I oad”
file-upload-01:需要处理的图像( 文件、url或字符串)
base64:如果输入是 Base64 编码,则设为“1”
maxtimeout:等待处理的最长时间( 必须为 60~3999 秒 )
selfsolve:如果自己处理该验证码,则设为“ 1 ”
返回值:该验证码的ID
请求己提交验证码的结果
URL: https:// www.9kw.eu/index.cgi ( GET )
apikey : 你的API key
action : 必须设为“usercaptchacorrectdata”
id: 要检查的验证码 ID
info: 若设为1,没有得到结果时返回 “NODATA"( 默认返回空 )
返回值: 要处理的验证码文本或错误码
错误码
0001 API ke y 不存在
0002 没有找到 API ke y
0003 没有找到激活 的 API ke y
0031 账号被系统禁用 24 小 时
0032 账号没有足够的权限
0033 需要升级插件
下面是发送验证码 图像到该 API 的初始实现代码 。
import urllib
import urllib2
API_URL = ’https://www.9kw.eu/index.cgi’ 
def send_captcha (api_key, img_data) :
data = {
    ’ action ’:’ usercaptchaupload ’ ,
    ’ apikey ’:api_key, 
    ’ file-upload-01’:img_data.encode(’base64’),
    ’ base64’:’1’,
    ’ selfsolve’:’1’,
    ’ maxtimeout’ :’60’
}

encoded_data = urllib.urlencode(data) 
request = urllib2.Request(API_URL, encoded_data) 
response = urllib2.urlopen(request) 
return response.read ()
    这个结构应该看起来很熟悉,首先我们创建了一个所需参数的字典,对其进行编码,然后将其作为请求体提交。需要注意的是,这里将selfsolve选项设为’1’,这种设置下,如果我们正在使用9kw 的Web界面处理验证码,那么验证码图像就会传给我们自己处理,从而可以节约我们的积分。如 果此时我们没有处于登录状态,验证码则会像平时一样传给其他用户。
    下面是获取验证码图像处理结果的代码
def get_captcha(api_key, captcha_id):
    data = {
        ’action’:’usercaptchacorrectdata’ ,
        ’id’:captcha_id,
        ’apikey’ : api_key
    }
    encoded data = urllib . url encode ( data ) 
    # note this is a GET request
    # so the data is appended to the URL    
    re sponse = urllib2.urlopen(API_URL + ’ ? ’ + encoded_data ) 
    return response.read()
    9kw的API有一个缺点是其响应是普通字符串,而不是类似 JSON 的结构化格式,这样就会使错误信息的区分更加复杂。例如,此时没有用户处理验证码图像,则会返回ERRORNOUSER字符 串。不过幸好我们提交的验证码图像永远不会包含这类文本。
    另一个困难是,只有在其他用户有时间人工处理验证码图像时,getcaptcha( )函数才能返回错误信息,正如之前提到的,通常要在30秒之后。为了使实现更加友好,我们将会增加一个封装函数,用于提交验证码图像以及等待结果返回。下面的扩展版本代码把这些功能封装到一个可复用
类当中,另外还增加了检查错误信息的功能。
import time 
import urllib 
import urllib2 
import re 
from io import BytesIO
 
class CaptchaAP I: 
    def__init__( self,api_key,timeout=60): 
       self.api_key = api_key 
       self.timeout = timeout 
       self.url = ’https://www.9kw.eu/index.cgi’ 

    def solve(self,img): 
        ””” Submit CAPTCHA and return result when ready 
        ”””
        img_buffer = BytesIO() 
        img.save(img_buffer,format=”PNG”) 
        img_data = img_buffer.getvalue() 
        captcha_id = self.send(img_data) 
        start_time     = time.time()
        while time.time() < start_time + self.timeout: 
            try: 
                text = self.get (captcha_id) 
            except CaptchaError: 
                pass # CAPTCHA still not ready 
            else: 
                if text != ’NO DATA ’    : 
                    if text == ’ERROR NO USER ’ : 
                        raise CaptchaError(’ Error: no user 
                            available to solve CAPTCHA’)     
                    else : 
                        print ’CAPTCHA solved!’

 

 

    Capt chaAPI类的源码可以从https://bitbucket.org/wswp/code/src/tip/chapter07/api.py获取,该链接中的代码会在9kw.eu修改其API时保持更新。这个类使用你的APIkey以及超时时间进行实例化,其中超时时间默认为60秒然后,solve()方法把验证码图像提交给API,并持续请求,直到验证码图像处理完成或者到达超时时间。目前,检查 API响应中的错误信息时check()方法只检查 了初始字符,确认其是否遵循错误信息前包含4位数字错误码的格式。要想该 API在使用时更加健壮,可以对该方法进行扩展,使其包含全部34种错误类型。
    下面是使用CaptchaAPI类处理验证码图像时的执行过程示例。
 
    这是本章前面给出的第一个复杂验证码图像的正确识别结果。如果再次提交相同的验证码图像, 则会立即返回缓存结果,并且不会再次消耗积分。

7.3.3 与 注册功能集成 

    目前我们已经拥有了一个可以运行的验证码API解决方案,下面我们可以将其与前面的表单进行集成。下面的代码对register函数进行了修改,使其将处理验证码图像的函数作为参数传递进来这样我们就可以选择使用OCR方法还是API方法了。

 下面是使用该函数的例子。

 

    运行成功了!我们从表单中成功获取到验证码图像,提交给9k的API,之后其他用户人工处理了该验证码,程序将返回结果提交到Web服务器端,注册了一个新账号。

 7.4 本章小结

    本章给出了处理验证码的方法:首先是使用OCR,然后是使用外部API。对于简单的验证码,或者需要处理大量验证码时,在OCR方法上花费时间是很值得的。否则,使用验证码处理API会更加经济有效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/693130.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高速电路设计系列分享-熟悉JESD204B(下)

目录 概要 整体架构流程 技术名词解释 技术细节 1.物理层 小结 概要 随着高速ADC跨入GSPS范围&#xff0c;与FPGA(定制ASIC)进行数据传输的首选接口协JESD204B。为了捕捉频率范围更高的RF频谱&#xff0c;需要宽带RFADC。在其推动下&#xff0c;对于能够捕捉更宽带宽并支持配置…

eclipse配置tomcat

一、为什么要配置tomcat &#xff1f; Eclipse是一款非常流行的Java开发集成环境&#xff08;IDE&#xff09;&#xff0c;它主要用于开发Java语言相关的应用程序。而Tomcat则是一个流行的开源Web服务器&#xff0c;也是一个Servlet容器。 在Java Web应用程序的开发过程中&…

有哪些免费好用的Python IDE(集成开发环境)?

工欲善其事&#xff0c;必先利其器。Python的学习过程少不了集成开发编辑环境(IDE)。这些Python IDE会提供插件、工具等帮助开发者加快使用Python开发的速度&#xff0c;提高效率。这里收集了一些对开发者非常有帮助的Python IDE(来自hittp://doc.okbase.net/havoc/archive/242…

【CGAL】Clion+vcpkg+MacOS M2

安装brew 链接如下&#xff1a; MacBook使用笔记&#xff1a;安装Homebrew&#xff08;M1&#xff09; - 知乎 打开mac终端&#xff0c;输入&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 这个是国内镜…

【Java面试题】设计模式

文章目录 设计模式你知道哪些?工厂模式单例模式★★★适配器模式代理模式定义作用静态代理动态代理★★★ 观察者模式★★★责任链模式 设计模式你知道哪些? ​ 创建型模式&#xff08;Creational Pattern&#xff09;&#xff1a;对类的实例化过程进行了抽象&#xff0c;能…

vegeta压测工具源码修改, 增加 摸高模式

在pacer.go中增加如下代码. pacer接口实现类作用就是控制吞吐量, 什么时间吞吐量多少. 摸高模式(梯度加压)效果如下 type HighTouchPacer struct {StartAt RateSlope float64HighTouchTimes float64PerHighTouchDuration float64PerStayDu…

uniapp 封装 navbar tabbar

最近换了一家公司工作 因为上家公司老板给的钱不多 还特别会压榨员工 好了好了&#xff0c;不扯皮了 1、封装navbar&#xff1a; 首先需要在pages.json中将对应页面的原生navbar给取消 举例&#xff1a; {"pages": [{"path" : "pages/home/inde…

Windows 10 首次RDP提示需要修改密码的处理方式

有一台Windows 10 的机器&#xff0c; 系统管理员给了一个RDP账号和密码&#xff0c; 使用这个账号远程登录这台机器&#xff0c; 在命令行输入 mstsc 命令&#xff0c;输入用户名密码之后却无法正常登入&#xff0c; 提示要修改密码&#xff0c; 提示的信息如下&#xff1a;…

《计算机系统与网络安全》 第三章 网络攻击预防与技术

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

【Android】跨端安全小计

前言 在挖移动端的时候&#xff0c;通常会关注跨端方向的问题&#xff0c;因为我们能直接从webview容器去访问native的代码&#xff0c;从客户端角度&#xff0c;从前端能直接深入到客户端&#xff0c;所以跨端这块比较有研究意义。 本文详细介绍android前端到客户端跨端通信…

用pytorch进行BERT文本分类

BERT 是一个强大的语言模型&#xff0c;至少有两个原因&#xff1a; 它使用从 BooksCorpus &#xff08;有 8 亿字&#xff09;和 Wikipedia&#xff08;有 25 亿字&#xff09;中提取的未标记数据进行预训练。顾名思义&#xff0c;它是通过利用编码器堆栈的双向特性进行预训练…

集合专题----set篇

1、Set 接口和常用方法 &#xff08;1&#xff09;Set 接口基本介绍 ① 无序&#xff08;添加和去除的顺序不一致&#xff09;&#xff0c;没有索引&#xff1b; ② 不允许重复元素&#xff0c;所以最多包含一个null&#xff1b; &#xff08;2&#xff09;Set 接口的常用方…

自动驾驶开源数据集(附下载链接)

自动驾驶是带动新兴产业的一个突破点&#xff0c;也是中国结合新能源汽车&#xff0c;实现汽车产业弯道超车的不二手段&#xff0c;是打破国外燃油车技术壁垒的关键一步&#xff01;它不会停止&#xff0c;只是在蓄势待发&#xff01; 数据集介绍&#xff1a;点击 自动驾驶场…

java进阶—通俗易懂线程池的概念(底层原理)及使用

前言 首先&#xff0c;我们知道创建一个线程 可以直接 使用 new Thread(() ->{}).start();这种形式来创建&#xff0c;当线程的run 方法执行结束&#xff0c;线程就终止了&#xff0c;线程对象就会被垃圾回收机制&#xff08;GC&#xff09;释放 然而在我们 开发工作中&…

智安网络|攻防演练对抗:网络边界自动化防御的关键

在当今高度互联的数字世界中&#xff0c;网络安全的重要性日益凸显。为了应对不断增长的网络威胁&#xff0c;组织和企业需要采取主动的防御策略&#xff0c;其中攻防演练对抗和自动化防御在保护网络边界方面扮演着重要的角色。本文将探讨攻防演练对抗的意义&#xff0c;并介绍…

四、用户管理

云尚办公系统&#xff1a;用户管理 B站直达【为尚硅谷点赞】: https://www.bilibili.com/video/BV1Ya411S7aT 本博文以课程相关为主发布&#xff0c;并且融入了自己的一些看法以及对学习过程中遇见的问题给出相关的解决方法。一起学习一起进步&#xff01;&#xff01;&#x…

ImportError: numpy.core.multiarray failed to import

遇到的问题&#xff1a; 解决方法&#xff1a; 根据你的opencv版本&#xff0c;去百度搜索对应的 numpy 版本&#xff0c;卸载掉现有的numpy &#xff0c;安装其他版本: sudo pip install numpy1.19.0或者直接升级到numpy的最新版本&#xff1a; sudo pip install --upgrade…

小程序-真机上接口无法调通,开发者工具上可以

近期在对接小程序&#xff0c;在这里记录一下&#xff0c;我们在对接小程序的时候碰到的一些奇奇怪怪的问题。 其中一个问题如下&#xff1a; 真实效果如下图 开发者工具上可以&#xff0c;访问没有人任何问题。 真机上接口无法调通&#xff0c;也没有报错&#xff0c;也没有…

idea中git的使用详细说明

一.克隆项目 1. 打开File>New>Project from Version Control... 2. 打开gitLab&#xff0c;复制项目地址 3. 粘贴到第1步中的URL中&#xff0c;点击“Clone” 二.代码提交 1. 修改文件后需要提交时&#xff0c;可以在git-Local Changes中看到你修改的文件及修改内容 2. 选…

netty学习(1):多个客户端与服务器通信

1. 基于前面一节netty学习&#xff08;1&#xff09;:1个客户端与服务器通信 只需要把服务器的handler改造一下即可&#xff0c;通过ChannelGroup 找到所有的客户端channel&#xff0c;发送消息即可。 package server;import io.netty.channel.*; import io.netty.channel.gr…