python爬虫-->验证码处理
来源:互联网 发布:java可以做网站吗 编辑:程序博客网 时间:2024/05/19 20:18
在上一篇博文中,介绍了如何自动化的进行表单交互,但是我们是用手动进行网址注册账号的,然后用这个账号密码进行自动化交互。那么在上一篇博文中为何不去自动化的注册账号呢?因为通常在网站注册账号,需要输入图片中的验证码。本篇博文中,将详细介绍如何自动化的对验证码进行处理。
本篇博文将从两个方面来对验证码进行处理
- 利用OCR自动化处理验证码
- 在线方式处理复杂验证码
OCR自动化处理验证码
打开注册网页http://example.webscraping.com/places/default/user/register,以下代码是用来获取表单的验证码图像。
import urllibimport urllib2import cookielibfrom io import BytesIOimport lxml.htmlfrom PIL import ImageREGISTER_URL = 'http://example.webscraping.com/places/default/user/register'def extract_image(html): ## 利用lxml获取表单中图像数据。图像数据的前缀定义了数据类型。 tree = lxml.html.fromstring(html) img_data = tree.cssselect('div#recaptcha img')[0].get('src') ##利用逗号分割,将其分为两部分,移除该前缀。这是一张进行了base64编码的图像 img_data = img_data.partition(',')[-1] #open('test_.png', 'wb').write(data.decode('base64')) ##进行base64解码,回到最初的二进制 binary_img_data = img_data.decode('base64') ##要想加载该图片,PIL需要对一个类似文件的接口,在传给Image类,我们又使用ByteIO对这个二进制进行封装 file_like = BytesIO(binary_img_data) img = Image.open(file_like) return img
光学字符识别(OCR)用于从图像中抽取文本。通过以下命令安装:
sudo pip install pytesseract 安装后运行如果出现错误:OSError: [Errno 2] No such file or directory sudo apt-get install tesseract-ocr
如果我们想更好的使用Tesseract,需要先修改验证码图像,去除其中背景噪音,只保留其中文本部分。可以通过阈值化对图像背景和文本部分进行分离。以下为实现代码:
def ocr(img): # threshold the image to ignore background and keep text #img.save('capcha_originl.png') gray = img.convert('L') #gray.save('captcha_greyscale.png') bw = gray.point(lambda x: 0 if x < 1 else 255, '1')##只保留阈值小于1的像素也就是全黑的像素才保留。 #bw.save('captcha_threshold.png') #print bw word = pytesseract.image_to_string(bw) ascii_word = ''.join(c for c in word if c in string.letters).lower() ##将识别的每个字母连接起来组成验证码 print ascii_word return ascii_word
说了这么多,我们来尝试下自动化处理验证码和自动化注册,以下实现代码:
def parse_form(html): """extract all input properties from the form 提取表单内所有的输入属性值对 """ 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 datadef register(first_name, last_name, email, password, captcha_fn): ##自动化处理验证码,进而自动化的注册网站账号密码 cj = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) html = opener.open(REGISTER_URL).read() form = parse_form(html) form['first_name'] = first_name form['last_name'] = last_name form['email'] = email form['password'] = form['password_two'] = password img = extract_image(html)##获取图像数据 captcha = ocr(img)##利用OCR进行识别图像内文本 form['recaptcha_response_field'] = captcha encoded_data = urllib.urlencode(form) request = urllib2.Request(REGISTER_URL, encoded_data) response = opener.open(request) success = '/user/register' not in response.geturl()##如果注册成功,则会发生跳转,'/user/register'不在跳转以后的网址内 return successif __name__ == '__main__': print register('Test Account', 'Test Account', '1234567@webscraping.com', 'example', ocr)
在线方式处理复杂验证码
像类似以上的一些验证码图像,OCR很难很好的识别,有些验证码人眼都不容易识别。此时我们需要使用一些在线人工服务来解决。
这里我们使用9kw,打开网页9kw官网进行注册https://www.9kw.eu/register.html,注册完成后将被定位到https://www.9kw.eu/usercaptcha.html,在本页中,需要处理其他用户发来的验证码。在处理了几个验证码以后,我们将被定位到https://www.9kw.eu/userapi_203959.html,从而获取自己的API Key
下面是发送验证码到该API的初始实现代码
def send(self, img_data): """Send CAPTCHA for solving 发送验证码到该API """ print 'Submitting CAPTCHA' data = { 'action': 'usercaptchaupload', 'apikey': self.api_key, 'file-upload-01': img_data.encode('base64'), 'base64': '1', ''' 'selfsolve': '1':表示如果我们正在使用9kw的Web界面处理验证码,那么验证码图像会传给我们自己处理 如果我们没有处于登录,那么会将验证码图像传给其他用户处理 ''' 'selfsolve': '1', 'maxtimeout': str(self.timeout) } encoded_data = urllib.urlencode(data) request = urllib2.Request(self.url, encoded_data) response = urllib2.urlopen(request) result = response.read() self.check(result) return result
下面是获取验证码图像处理结果的代码
def get(self, captcha_id): """Get result of solved CAPTCHA 获取验证码图像处理结果 """ data = { 'action': 'usercaptchacorrectdata', 'id': captcha_id, 'apikey': self.api_key, 'info': '1' } encoded_data = urllib.urlencode(data) response = urllib2.urlopen(self.url + '?' + encoded_data) result = response.read() self.check(result) return result
9kw的API有两个缺点:
①其响应是普通字符串,而不是json结构化格式。例如:如果此时没有用户处理验证码图像,将会返回“ERROR NO USER”。幸好一般的验证码里面文本不会是“ERROR NO USER”。
②只有在其他用户有时间人工处理验证码图像时,上面的get函数才能返回信息。通常在30s以后。
为了实现友好,我们将会增加一个封装函数,用于提交验证码图像以及等待结果返回。下面的扩展版本把这些功能封装到一个可复用类中,另外增加了检查错误功能。
#coding:utf-8import sysimport reimport urllib2import urllibimport timefrom io import BytesIOfrom PIL import Imagefrom form import registerdef main(api_key): captcha = CaptchaAPI(api_key) print register('Test Account', 'Test Account', 'example125@webscraping.com', 'example', captcha.solve)class CaptchaError(Exception): passclass CaptchaAPI: 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)##发送验证码到该API 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!' print "验证码为 :",text return text print 'Waiting for CAPTCHA ...' raise CaptchaError('Error: API timeout') def send(self, img_data): """Send CAPTCHA for solving 发送验证码到该API """ print 'Submitting CAPTCHA' data = { 'action': 'usercaptchaupload', 'apikey': self.api_key, 'file-upload-01': img_data.encode('base64'), 'base64': '1', ''' 'selfsolve': '1':表示如果我们正在使用9kw的Web界面处理验证码,那么验证码图像会传给我们自己处理 如果我们没有处于登录,那么会将验证码图像传给其他用户处理 ''' 'selfsolve': '1', 'maxtimeout': str(self.timeout) } encoded_data = urllib.urlencode(data) request = urllib2.Request(self.url, encoded_data) response = urllib2.urlopen(request) result = response.read() self.check(result) return result def get(self, captcha_id): """Get result of solved CAPTCHA 获取验证码图像处理结果 """ data = { 'action': 'usercaptchacorrectdata', 'id': captcha_id, 'apikey': self.api_key, 'info': '1' } encoded_data = urllib.urlencode(data) response = urllib2.urlopen(self.url + '?' + encoded_data) result = response.read() self.check(result) return result def check(self, result): """Check result of API and raise error if error code detected 该方法只检查初始字符,确认其是否遵循错误信息前包含4位数字错误码的格式。 """ if re.match('00\d\d \w+', result): raise CaptchaError('API error: ' + result)if __name__ == '__main__': api_key = '1FLYJ8B8035NQM9K12' main(api_key)
上面的类使用你的APIkey以及超时时间进行实例化,其中超时时间为60s,然后solve()方法把验证码图像提交给API,并持续请求,直到验证码图像处理完成或者达到超时时间。
- python爬虫-->验证码处理
- 【Python爬虫7】验证码处理
- python 处理验证码
- [python爬虫]爬取学校教务处以及登录过程验证码的处理
- python爬虫进阶(十):日志系统、守护线程以及验证码处理
- scrapy+python当你的爬虫遇到验证码处理方式之一
- Python爬虫-尝试使用人工和OCR处理验证码模拟登入
- 爬虫之处理简单验证码
- Python爬虫---处理HTTPS请求 SSL证书验证
- python爬虫解决验证码的思路
- Python爬虫实现验证码登录
- python爬虫解决验证码的思路
- python 处理图片验证码
- python爬虫-异常处理
- 【Python网络爬虫学习01】爬取网络验证码
- python爬虫学习日记(1)--获取验证码
- python爬虫解决百度贴吧登陆验证码问题
- Python爬虫之自动登录与验证码识别
- Android Gson详解(二)
- 3155: Preprefix sum
- JS禁止页面中的一些操作事件
- python中如何判断路径是否存在
- ssm的事物回滚实现
- python爬虫-->验证码处理
- Python爬虫实践笔记(三)
- 28&29day-UIWebView
- USACO 2.3 Money Systems 题解
- L
- composer 国内镜像配置
- 如何有效预防晕机?
- Java泛型中擦除的问题
- Cow Bowling -- 动态规划的简单递归