【前言】几天研究验证码解决方案有三种吧。第一、手工输入,即保存图片后然后我们手工输入;第二、使用cookie,必须输入密码一次,获取cookie;第三、图像处理+深度学习方案,研究生也做相关课题,就用了这种。
一、处理思路
1、图像处理,针对我要识别的期货中心的验证码,有我针对性的处理。目标是得到去噪后的二值图片,然后使用深度学习神经网络方法进行识别。
2、第一次尝试了用谷歌的开源tesseract-ocr方法,做了一个模型训练。因为都是集成好的开发环境,自动分割,自己只需手动的调整一些识别错误的。准确率还是可以的。
3、使用了腾讯的免费ocr接口,是被效果大大提升。最后用一个正则表达式加一个提取器,只提取字母和数字。识别率百分之90是有的。
直接上代码。亲测可用自动登录中国期货市场监控中心的网站https://investorservice.cfmmc.com/
1 # /usr/bin/python 2 # encoding: utf-8 3 4 import time 5 from selenium import webdriver 6 import sys 7 import urllib2 8 import urllib 9 import time 10 import re 11 12 from PIL import Image 13 from pytesseract import * 14 import PIL.ImageOps 15 16 import requests 17 import hmac 18 import hashlib 19 import base64 20 import time 21 import random 22 23 #方案一:在线二维码识别(也是先下载到本地,但是由于动态二维码原因,两次获取的页面不一样,导致验证码不匹配。匹配不成功) 24 #下面有针对此方案的解决方法,就是解析同一个界面下的验证码,先下载到本地,然后上传处理。这种适合服务器不能图片截屏获取二维码,可以使用session或者cookie方式。 25 def yanzheng_online(): 26 # 爬取图片 27 reload(sys) 28 sys.setdefaultencoding('utf8') 29 30 headers = ("User-Agent", 31 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36") 32 opener = urllib2.build_opener() 33 opener.addheaders = [headers] 34 urllib2.install_opener(opener) 35 36 #循环爬取多张,建立数据集 37 # for i in range(1, 1500): 38 # url = "https://investorservice.cfmmc.com/veriCode.do?t=1531728079700" + str(i) 39 # data = urllib2.urlopen(url).read() 40 # # data=urllib2.quote(data).decode('utf-8') 41 # file = "G:/360Downloads/pic/" + str(i) + ".png" 42 # playFile = open(file, 'wb') 43 # playFile.write(data) 44 # playFile.close() 45 # time.sleep(1) 46 url = "https://investorservice.cfmmc.com/veriCode.do?t=1531728079700" 47 data = urllib2.urlopen(url).read() 48 file = "G:/360Downloads/pic/" + "yanzhengma" + ".png" 49 playFile = open(file, 'wb') 50 playFile.write(data) 51 playFile.close() 52 time.sleep(1) 53 54 # 图像处理 55 im = Image.open('G:/360Downloads/pic/yanzhengma.png') 56 57 im = im.convert('L') 58 #im.show() 59 im2 = im.point(lambda x: 0 if x > 200 else 255) 60 #im2.show() 61 im3 = im2.save("G:/360Downloads/pic/yanzhengma.png") 62 63 # 借助腾讯免费的OCR识别 64 appid = "1257XX2374" # 写入自己的腾讯云号码,我修改了 65 # bucket = "你的bucket" # 不要也可以 66 secret_id = "AKIDGKXXXXXXXXX1XnnWyA5sFgz" # 写入自己的账号里面的地址 67 secret_key = "EDwRggaXXXXXXXXXXysY0CA" # 同上 68 expired = time.time() + 2592000 69 onceExpired = 0 70 current = time.time() 71 rdm = ''.join(random.choice("0123456789") for i in range(10)) 72 userid = "0" 73 fileid = "tencentyunSignTest" 74 75 info = "a=" + appid + "&k=" + secret_id + "&e=" + str(expired) + "&t=" + str(current) + "&r=" + str( 76 rdm) + "&u=0&f=" # 去掉bucket 77 78 signindex = hmac.new(secret_key, info, hashlib.sha1).digest() # HMAC-SHA1加密 79 sign = base64.b64encode(signindex + info) # base64转码 80 81 url = "http://recognition.image.myqcloud.com/ocr/general" 82 headers = {'Host': 'recognition.image.myqcloud.com', 83 "Authorization": sign, 84 } 85 files = {'appid': (None, appid), 86 # 'bucket': (None, bucket), 87 'image': ('yanzhengma.png', open('G:/360Downloads/pic/yanzhengma.png', 'rb'), 'image/jpeg') 88 89 } 90 91 r = requests.post(url, files=files, headers=headers) 92 responseinfo = r.content 93 #print responseinfo 94 # 创建内存中的word文档对象 95 # file=docx.Document() 96 r_index = r'itemstring":"(.*?)"' # 做一个正则匹配,会匹配出一些特殊符号 97 result = re.findall(r_index, responseinfo) 98 #print result 99 # result2=re.findall(r'\w+',result) 100 # new_crazy = filter(str.isalnum, result) 101 # print new_crazy 102 a = 0 103 for i in result: 104 # file.add_paragraph(i) 105 # 只识别出数字和字母 106 new_crazy = filter(str.isalnum, i) 107 #print new_crazy 108 a = new_crazy 109 # file.save("D:\\writeResult.docx") 110 return a 111 112 #方案二:网页裁剪验证码,本地识别识别。匹配成功!! 113 def yanzheng_local(): 114 #对截取的图片处理 115 im = Image.open('G:/360Downloads/pic/yanzhengma.png') 116 box = (526, 247, 623, 273) # 设置要裁剪的区域96*25,根据自己验证码位置 117 region = im.crop(box) # 此时,region是一个新的图像对象。 118 # region.show()#显示的话就会被占用,所以要注释掉 119 region.save("G:/360Downloads/pic/yanzhengma.png") 120 # 爬取图片 121 reload(sys) 122 sys.setdefaultencoding('utf8') 123 124 headers = ("User-Agent", 125 "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36") 126 opener = urllib2.build_opener() 127 opener.addheaders = [headers] 128 urllib2.install_opener(opener) 129 130 # 图像处理 131 im = Image.open('G:/360Downloads/pic/yanzhengma.png') 132 133 im = im.convert('L') 134 #im.show() 135 im2 = im.point(lambda x: 0 if x > 200 else 255) 136 #im2.show() 137 im3 = im2.save("G:/360Downloads/pic/yanzhengma.png") 138 139 # 腾讯ocr识别 140 appid = "1257XXX374" # 写入自己的腾讯云号码 141 # bucket = "你的bucket" # 不要也可以 142 secret_id = "AKIDGKXXXXXXXXnnWyA5sFgz" # 写入自己的账号里面的地址 143 secret_key = "EDwRggaXXXXXXXXtVrysY0CA" # 同上 144 expired = time.time() + 2592000 145 onceExpired = 0 146 current = time.time() 147 rdm = ''.join(random.choice("0123456789") for i in range(10)) 148 userid = "0" 149 fileid = "tencentyunSignTest" 150 151 info = "a=" + appid + "&k=" + secret_id + "&e=" + str(expired) + "&t=" + str(current) + "&r=" + str( 152 rdm) + "&u=0&f=" # 去掉bucket 153 154 signindex = hmac.new(secret_key, info, hashlib.sha1).digest() # HMAC-SHA1加密 155 sign = base64.b64encode(signindex + info) # base64转码 156 157 url = "http://recognition.image.myqcloud.com/ocr/general" 158 headers = {'Host': 'recognition.image.myqcloud.com', 159 "Authorization": sign, 160 } 161 files = {'appid': (None, appid), 162 # 'bucket': (None, bucket), 163 'image': ('yanzhengma.png', open('G:/360Downloads/pic/yanzhengma.png', 'rb'), 'image/jpeg') 164 165 } 166 167 r = requests.post(url, files=files, headers=headers) 168 responseinfo = r.content 169 #print responseinfo 170 # 创建内存中的word文档对象 171 # file=docx.Document() 172 r_index = r'itemstring":"(.*?)"' # 做一个正则匹配 173 result = re.findall(r_index, responseinfo) 174 #print result 175 # result2=re.findall(r'\w+',result) 176 # new_crazy = filter(str.isalnum, result) 177 # print new_crazy 178 a = 0 179 for i in result: 180 # file.add_paragraph(i) 181 # 只识别出数字和字母 182 new_crazy = filter(str.isalnum, i) 183 184 #print new_crazy 185 a = new_crazy 186 # print 'a' 187 # file.save("D:\\writeResult.docx") 188 return a 189 190 def login(username, password): 191 192 url = 'https://investorservice.cfmmc.com ' 193 194 driver = webdriver.Chrome(executable_path='C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe') 195 driver.get(url) 196 # print driver.title 197 name_input = driver.find_element_by_name('userID') # 找到用户名的框框 198 pass_input = driver.find_element_by_name('password') # 找到输入密码的框框 199 yanzheng_input=driver.find_element_by_name('vericode') #验证码输入框 200 login_button = driver.find_element_by_name('imageField2') # 找到登录按钮 201 202 name_input.clear() 203 name_input.send_keys(username) # 填写用户名 204 time.sleep(0.2) 205 pass_input.clear() 206 pass_input.send_keys(password) # 填写密码 207 #验证码获取 208 #local方法专用,截取验证码所在的网页 209 driver.get_screenshot_as_file('G:/360Downloads/pic/yanzhengma.png') # 截图网页保存 210 211 212 #yzm=yanzheng_online() 213 #使用本地裁剪识别,即方案二 214 yzm=yanzheng_local() 215 print yzm 216 yanzheng_input.send_keys(yzm) 217 time.sleep(1.2) 218 login_button.click() # 点击登录 219 220 time.sleep(1.2) 221 #print driver.get_cookies() 222 223 #打印“登录成功”表示成功,否则重新运行 224 if('login'in driver.current_url): 225 print "登录成功" 226 driver.close() 227 228 if __name__ == "__main__": 229 #账号密码 230 user = "xxxxxxx" 231 pw = "xxxxxxxx" 232 login(user, pw)
#后面会继续实现cookie保存,爬取信息,存储数据库。
二、最好的解决方法
这几天深入了解了python爬虫,因为要在登录之后,请求新的网页时要保持登录,不然在请求新的网页时又会跳转到登录页面。如何保持登录呢?两种方式,本地携带cookie访问,服务器端保持session.如此,不如在登录的时候采用登录保持的方式,保持session.(当然携带cookie也可以)。这几天学习了抓包分析表单,实现了请求cookie,提交token.还有一个验证码,就采用网页抓取,正则解析出验证码地址,下载本地上传深度学习模型,识别出验证码传入post表单。
源码地址:https://www.cnblogs.com/huangfuyuan/p/9356747.html
本方法适用于windows带图形界面的,不适用于服务器。
三、验证码生成原理及python代码
1 def verifycode(request): 2 # 引入绘图模块 3 from PIL import Image, ImageDraw, ImageFont 4 # 引入随机函数模块 5 import random 6 # 定义变量,用于画面的背景色、宽、高 7 bgcolor = (random.randrange(20, 100), random.randrange(20, 100), random.randrange(20, 100)) width = 100 height = 50 8 # 创建画面对象 9 im = Image.new('RGB',(width, height),bgcolor) 10 # 创建画笔对象 11 draw = ImageDraw.Draw(im) 12 # 调用画笔的point()函数绘制噪点 13 for i in range(0, 100): 14 xy = (random.randrange(0, width), random,randrange(0, height)) 15 fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) 16 draw.point(xy, fill=fill) 17 # 定义验证码的备选值 18 str = '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM' 19 # 随机选取四个值作为验证码 20 rand_str = '' 21 for i in range(0,4): 22 rand_str += str[random.randrange(0, len(str))] 23 # 构建字体对象 ,读取本地字体模板 24 font = ImageFont.truetype(r'C\Windows\Fonts\AdobeArabic-Bold.otf', 40) 25 # 构建字体颜色 26 fontcolor1 =(255, random.randrange(0, 255), random.randrange(0, 255)) 27 fontcolor2 =(255, random.randrange(0, 255), random.randrange(0, 255)) 28 fontcolor3 =(255, random.randrange(0, 255), random.randrange(0, 255)) 29 fontcolor4 =(255, random.randrange(0, 255), random.randrange(0, 255)) 30 # 绘制四个字 31 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1) 32 draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2) 33 draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3) 34 draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4) 35 # 释放画笔 36 del draw 37 # 存入session , 用于做进一步验证 38 request.session['verifycode'] = rand_str 39 # 内存文件操作 40 import io buf = io.BytesIO() 41 # 将图片保存在内存中,文件类型为png 42 im.safe(buf, 'png') 43 # 将内存中的图片数据返回给客户端,MIME类型为图片png 44 return HttpResponse(buf.getValue(), 'image/png')