【前言】几天研究验证码解决方案有三种吧。第一、手工输入,即保存图片后然后我们手工输入;第二、使用cookie,必须输入密码一次,获取cookie;第三、图像处理+深度学习方案,研究生也做相关课题,就用了这种。

一、处理思路

  1、图像处理,针对我要识别的期货中心的验证码,有我针对性的处理。目标是得到去噪后的二值图片,然后使用深度学习神经网络方法进行识别。

  2、第一次尝试了用谷歌的开源tesseract-ocr方法,做了一个模型训练。因为都是集成好的开发环境,自动分割,自己只需手动的调整一些识别错误的。准确率还是可以的。

  3、使用了腾讯的免费ocr接口,是被效果大大提升。最后用一个正则表达式加一个提取器,只提取字母和数字。识别率百分之90是有的。

  直接上代码。亲测可用自动登录中国期货市场监控中心的网站



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表单。

本方法适用于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')