【前言】几天研究验证码解决方案有三种吧。第一、手工输入,即保存图片后然后我们手工输入;第二、使用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')