1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 12306验证码识别初尝试(1)

12306验证码识别初尝试(1)

时间:2022-09-05 10:57:16

相关推荐

12306验证码识别初尝试(1)

首先,贴代码(尚未完成,仅供参考):

# -*- coding: utf-8 -*-"""@author: Steve"""from selenium import webdriverfrom mon.action_chains import ActionChains# 导入Keys 模块from mon.keys import Keysfrom splinter.browser import Browserfrom time import sleepfrom PIL import Imagefrom PIL import ImageFilter#import urllib #这是python2的用法#import urllib2 #这是python2的用法import urllib.requestimport reimport jsonimport sslimport tracebackimport time, sysimport winsoundif hasattr(ssl, '_create_unverified_context'):ssl._create_default_https_context = ssl._create_unverified_contextUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36"#pic_url = "/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand&0.21191171556711197"def get_img(pic_url):resp = urllib.request.urlopen(pic_url)raw = resp.read()with open("./tmp.jpg", 'wb') as fp:fp.write(raw)return Image.open("./tmp.jpg")def get_sub_img(im, x, y):assert 0 <= x <= 3assert 0 <= y <= 2WITH = HEIGHT = 68left = 5 + (67 + 5) * xtop = 41 + (67 + 5) * yright = left + 67bottom = top + 67return im.crop((left, top, right, bottom))def baidu_stu_lookup(im):url = "/n/image?fr=html5&needRawImageUrl=true&id=WU_FILE_0&name=233.png&type=image%2Fpng&lastModifiedDate=Mon+Mar+16++20%3A49%3A11+GMT%2B0800+(CST)&size="im.save("./query_temp_img.png")raw = open("./query_temp_img.png", 'rb').read()url = url + str(len(raw))req = urllib.request.Request(url, raw, {'Content-Type': 'image/png', 'User-Agent': UA})resp = urllib.request.urlopen(req)resp_url = resp.read() # return a pure urlurl = "/n/searchpc?queryImageUrl=" + urllib.request.quote(resp_url)req = urllib.request.Request(url, headers={'User-Agent': UA})resp = urllib.request.urlopen(req)html = resp.read()return baidu_stu_html_extract(html)def baidu_stu_html_extract(html):# pattern = pile(r'<script type="text/javascript">(.*?)</script>', re.DOTALL | re.MULTILINE)pattern = pile(r"keywords:'(.*?)'")#pattern = pattern.decode('utf-8') # /zoulonglong/article/details/78547191html = html.decode('utf-8')matches = pattern.findall(html)if not matches:return '[UNKNOWN]'json_str = matches[0]json_str = json_str.replace('\\x22', '"').replace('\\\\', '\\')# print json_strresult = [item['keyword'] for item in json.loads(json_str)]return '|'.join(result) if result else '[UNKNOWN]'def ocr_question_extract(im):# git@:madmaze/pytesseract.gitglobal pytesseracttry:import pytesseractexcept:print("[ERROR] pytesseract not installed")returnim = im.crop((127, 3, 260, 22))im = pre_ocr_processing(im)im.show()return pytesseract.image_to_string(im, lang='chi_sim').strip()def pre_ocr_processing(im):im = im.convert("RGB")width, height = im.sizewhite = im.filter(ImageFilter.BLUR).filter(ImageFilter.MaxFilter(23))grey = im.convert('L')impix = im.load()whitepix = white.load()greypix = grey.load()for y in range(height):for x in range(width):greypix[x, y] = min(255, max(255 + impix[x, y][0] - whitepix[x, y][0],255 + impix[x, y][1] - whitepix[x, y][1],255 + impix[x, y][2] - whitepix[x, y][2]))new_im = grey.copy()binarize(new_im, 150)return new_imdef binarize(im, thresh=120):assert 0 < thresh < 255assert im.mode == 'L'w, h = im.sizefor y in range(0, h): # for y in xrange(0, h): # xrange只用于python 2for x in range(0, w): # for x in xrange(0, w): # xrange只用于python 2if im.getpixel((x, y)) < thresh:im.putpixel((x, y), 0)else:im.putpixel((x, y), 255)class huoche(object):"""docstring for huoche"""#dr = webdriver.Chrome() #此命令可以成功打开chromedriver_name = ''executable_path = ''# 用户名,密码username = u"xxxx@"passwd = u"xxxx"# cookies值,需自行寻找#starts = u"%u6B66%u6C49%2CWHN" # 武汉#ends = u"%u9EBB%u57CE%2CMCN" # 麻城starts = u"%u5317%u4EAC%2CBJP"ends = u"%u9A7B%u9A6C%u5E97%u897F%2CZLN"# 时间格式-01-19dtime = u"-01-16"# 车次,选择第几趟,0则从上之下依次点击order = 0###乘客名users = [u"王笨","李莎莎"]##席位xb = u"二等座"pz = u"成人票""""网址"""ticket_url = "/otn/leftTicket/init"login_url = "/otn/login/init"initmy_url = "/otn/view/index.html"buy = "/otn/confirmPassenger/initDc"login_url = '/otn/login/init'def __init__(self):self.driver_name = 'chrome'self.executable_path = 'C:\Python27\chromedriver.exe'def login(self):self.driver.visit(self.login_url)#sleep(9)# 填充密码self.driver.fill("loginUserDTO.user_name", self.username)# sleep(1)self.driver.fill("userDTO.password", self.passwd)print(u"等待验证码,自行输入...")#验证码部分# 定位到要右击的元素#qqq = self.driver.driver.find_element_by_xpath("//*[@id='loginForm']/div/ul[2]/li[4]/div/div/div[3]").textpic = self.driver.driver.find_element_by_xpath("//*[@id='loginForm']/div/ul[2]/li[4]/div/div/div[3]/img")#sleep(3)pic_src = pic.get_attribute('src')# image = pic.find_element_by_tag_name("img")#pic_src = pic.value_of_css_property('background-color')#pic_src = pic.getText()print('url is: %s' % (pic_src))#print(pic.get_attribute("alt"))# 对定位到的元素执行鼠标右键操作#qqq2 = ActionChains(self.driver).context_click(qqq).perform()#ActionChains(self.driver).contextClick(qqq).sendKeys(Keys.ARROW_DOWN).build().perform()#actionChains = ActionChains(self.driver)#actionChains.context_click(qqq).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ENTER).perform()#action = ActionChains(self.driver)#action.move_to_element(qqq) # 移动到该元素#action.context_click(qqq) # 右键点击该元素#action.send_keys(Keys.ARROW_DOWN) # 点击键盘向下箭头#action.send_keys('v') # 键盘输入V保存图#action.perform() # 执行保存im = get_img(pic_src)print('OCR Question: ',ocr_question_extract(im))for y in range(2):for x in range(4):im2 = get_sub_img(im, x, y)result = baidu_stu_lookup(im2)print(y, x), resultwhile True:if self.driver.url != self.initmy_url:sleep(1)else:breakdef start(self):self.driver = Browser(driver_name=self.driver_name, executable_path=self.executable_path)self.driver.driver.set_window_size(1400, 1000)self.login() # 此Login指上面的login函数# sleep(1)self.driver.visit(self.ticket_url) # 打开12306界面try:print(u"购票页面开始...")# sleep(1)# 加载查询信息self.driver.cookies.add({"_jc_save_fromStation": self.starts})self.driver.cookies.add({"_jc_save_toStation": self.ends})self.driver.cookies.add({"_jc_save_fromDate": self.dtime})self.driver.reload()# 重新加载cookies# 添加车次类型。放在加载之后,因为实测发现比如勾选"GC-高铁/城际"checkbox后,什么都不干页面就会自动变化l = ['GC-高铁/城际', 'D-动车'] # 在列表里可以去掉不需要的车次类型for i in l:btn = self.driver.find_by_text(i)btn.click()i = 0 # 上面的for循环使用了i,这里如果不清零,下面因为也用到了i,会报错。count = 0if self.order != 0:while self.driver.url == self.ticket_url: # 判断是否成功跳转到目标页面self.driver.find_by_text(u"查询").click()count += 1print(u"循环点击查询... 第 %s 次" % count)# sleep(1)try:self.driver.find_by_text(u"预订")[self.order - 1].click()except Exception as e:print(e)print(u"还没开始预订")continueelse:while self.driver.url == self.ticket_url:self.driver.find_by_text(u"查询").click()count += 1print(u"循环点击查询... 第 %s 次" % count)# sleep(0.8)try:for i in self.driver.find_by_text(u"预订"):i.click()sleep(1)except Exception as e:print(e)print(u"还没开始预订 %s")continueprint(u"开始预订...")# sleep(3)# self.driver.reload()sleep(1)print(u'开始选择用户...')for user in self.users:self.driver.find_by_text(user).last.click()print(u"提交订单...")sleep(1)# self.driver.find_by_text(self.pz).click()# self.driver.find_by_id('').select(self.pz)# # sleep(1)# self.driver.find_by_text(self.xb).click()# sleep(1)self.driver.find_by_id('submitOrder_id').click()# print u"开始选座..."# self.driver.find_by_id('1D').last.click()# self.driver.find_by_id('1F').last.click()sleep(1.5)print(u"确认选座...")self.driver.find_by_id('qr_submit_id').click()# 连续发出提示音while True:winsound.Beep(300, 1000)except Exception as e:print(e)cities = {'成都': '%u6210%u90FD%2CCDW','重庆': '%u91CD%u5E86%2CCQW','北京': '%u5317%u4EAC%2CBJP','广州': '%u5E7F%u5DDE%2CGZQ','杭州': '%u676D%u5DDE%2CHZH','宜昌': '%u5B9C%u660C%2CYCN','郑州': '%u90D1%u5DDE%2CZZF','深圳': '%u6DF1%u5733%2CSZQ','西安': '%u897F%u5B89%2CXAY','大连': '%u5927%u8FDE%2CDLT','武汉': '%u6B66%u6C49%2CWHN','上海': '%u4E0A%u6D77%2CSHH','麻城': '%u9EBB%u57CE%2CMCN','临沂': '%u4E34%u6C82%2CLVK','驻马店西': '%u9A7B%u9A6C%u5E97%u897F%2CZLN'}if __name__ == '__main__':huoche = huoche()#huoche.starts = cities[sys.argv[1]]#huoche.ends = cities[sys.argv[2]]#huoche.dtime = sys.argv[3]huoche.start()

首先,我在寻找验证码图片的url上花费了不少时间,终于在别人的基础上写出了正确的代码:

注意这个img:

结果如下:

上述代码的健壮性不够好,我的感觉是大概运行五次出一次问题,打印不出url,因为没有找到。

又出现了这个问题:

解决方法:原因是python 2的程序用在了python 3中。

python 2中的写法是:

python 3中得这样写:

然后就进入了12306验证码识别的第一个核心阶段:识别提示文字,例如:

在上面的程序中有这样一句报错:

因此在网上找到了pytesseract安装的正确方法:

第一步,安装pytesseract。这应该是我的火车票抢票程序安装的第一个东西:

第二步:安装Tesseract-OCR.(安装包下载地址与安装方法:/article/219f4bf788addfde442d38fe.html)

下载过程中,系统提醒我有个包没下载(好像是equ),照着下文的提示下载并放到了下文所说的地址:

/tesseract-ocr/tessdata

放到我的这个地址:

D:\Program Files (x86)\Tesseract-OCR\tessdata

下载并安装之后,发现Tesseract并未自动注册路径,因此在Path中加入了Tesseract的路径,然后就可以在CMD中输入tesseract了:

并且注册了TESSDATA_PREFIX这个系统变量(路径是安装,值为: D:\Program Files (x86)\Tesseract-OCR\tessdata)这个必须注册,并且值是…\tessdata,不然会报错找不到chi_sim等等!:

我的pytesseract.py的路径为:

C:\Users\Administrator\AppData\Local\Programs\Python\Python37\Lib\site-packages\pytesseract

打开pytesseract.py后,将tessract_cmd='tesseract’改为正确的路径(注意斜杠是右斜杠,而不是上面的左斜杠):

最后按照此文中的方法,截图验证了tesseract已经安装成功(/article/219f4bf788addfde442d38fe.html):

然后,pycharm中必须install pytesseract才能import pytesseract:

安装完毕,试验的时候发现print了奇怪的字符,再在cmd中试验,发现tesseract基本识别不出12306验证码中的中文字符,网上查询说需要训练。哈哈,还是躲不过人工智能这一步啊。此外,截图也有问题,明显没有截取完全:

从此,我的悲催生活就开始了。。。主要是查询发现,如果要训练,需要下载jtessboxeditorfx来生成tesseract-orc的字典,务必选择带FX的版本,才支持中文字符编辑。但是这个jtessboxeditorfx实在是不好用,因为我使用过250张12306的验证码截图,每张截图中的每个字都得在jtessboxeditorfx一点一点地手工修改,光修改就花了我六个小时,而这六个小时过去后,发现训练结果仍然很差。 我十分想找到更好的训练方法来训练tesseract,如果不行,就只能另寻其他方法了。

jTessBoxEditor的作用:tesseract生成的 “.box”文件中列出了每个字符在图片上的位置以及内容, jTessBoxEditor的作用就是用来调整每个字符在图片上的位置以及内容的。(参考:/soft/432051.html)

我开始以为训练是很容易的,就只截取了五张图来训练:

旧版的jTessBoxEditor只能处理后缀为 “.tif” 的图片,而2.0版本就可以处理 GPEG、PNG、BItmap等几乎所有格式的图片,不再需要对样本进行 “.tif” 格式的转化了。

jTessBoxEditor或jTessBoxEditorFX无需安装,双击文件夹中的train.bat即可打开,将五张图片(jpg格式即可)–Tools–Merge TIFF成了一张:mjorcen.normal.expFinal.tif

将最终得到的tif文件转换为box文件,可见只识别出了一张:

此时我以为编辑box文件(把第四张图的内容(红框括起来的那部分)拷贝三次,注意最后一列的编号要变),然后在jtessboxeditor中操作后就ok了,没想到修改后还是不行(/dcrmg/article/details/78233459; /view/6caccb76a31614791711cc7931b765ce05087aa7.html):

保存后,此时再用jTessEditorFX打开,竟然可以看到前三张都有框了(修改之前都没有),哈哈!:

此时必须修改character,X,Y,W,H。后面四项都无法直接输入,而必须要一点一点地改变,慢慢享受吧!

新建文件font_properties,并输入normal 0 0 0 0 0:

生成train文件,不知道这一步为什么前三页还是empty page,这里不修改了,后面用250张图片修改时加入了psm参数,就不会出现empty page了:

执行下列命令,生成字符集文件:

先执行第一条命令,再执行第二条命令,生成字典数据:

生成之后手工修改 Clustering 过程生成的 4 个文件(inttemp、pffmtable、normproto、shapetable)的名称为 [lang].xxx。这里改为 mjorcen.inttemp、mjorcen.pffmtable、mjorcen.normproto、mjorcen.shapetable。

在终端执行此命令,合并数据文件:

将生成的 mjorcen.traineddata” 语言包文件拷贝到 tessdata 目录下,就可以用它来进行中文字符识别了。

现在试验一下,识别"茶几”这两个字,生成是生成了,但是字不正确:

再用tesseract自带的语言包试验一下,发现效果比自己训练出来的好,哈哈:

因此接下来多找点图片来训练,就刷新12306,得到了251张图片。

照着以下步骤做(主要是添加了psm参数,下面可以看到psm参数的巨大作用):

1.jTessEditorFX–Tools–Merge Tiff,将251张jpg文件合并成一个tif文件。

2.makebox。cmd中进入tif文件所在目录,并输入以下命令:

tesseract mjorcen.normal.exp0.tif mjorcen.normal.exp0 -l chi_sim --psm 7 batch.nochop makebox

3.jTessEditorFX–Box Editor–Open,打开tif文件,一张一张地把每个框都修改好。有一张图片实在修改不好,就放弃了。

4.新建文件font_properties(注意没有后缀!它没有文件类型,不是txt文件!),并输入normal 0 0 0 0 0

5.cmd中生成train文件:mjorcen.normal.exp0.tif mjorcen.normal.exp0 -l chi_sim --psm 7 nobatch box.train

6.cmd中生成字符集文件:unicharset_extractor mjorcen.normal.exp0.box

7.生成字典数据(先执行第一条命令,再执行第二条命令):

mftraining -F font_properties -U unicharset -O mjorcen.unicharset mjorcen.normal.exp0.tr

cntraining mjorcen.normal.exp0.tr

8.手工修改上面生成的 4 个文件(inttemp、pffmtable、normproto、shapetable)的名称为 [lang].xxx。这里改为 mjorcen.inttemp、mjorcen.pffmtable、mjorcen.normproto、mjorcen.shapetable.

9.cmd中合并数据文件: combine_tessdata mjorcen

10.将生成的 mjorcen.traineddata” 语言包文件拷贝到 tessdata 目录下,就可以用它来进行中文字符识别了。

试验一下:

cmd中输入 tesseract mjorcen.normal.exp0.jpg 1.txt -l mjorcen --psm 7

结果:

1.排风机档案袋 未能识别

2.档案袋 识别成 桃漏袋

3.药片 识别成 药片

4.茶几 识别成 茶几绿

5.拖把 识别成 跑把

6.狮子 识别成 独子口

7.订书机 识别成 灯书机

8.中国结 识别成 中口国结

可见识别效果非常之差,得想办法提高tesseract的中文识别效果,不行的话,只能弃用tesseract用其他的方法了。

在此说明一下psm的重要作用:

psm参数极为重要,上述第二步由于有psm参数,大获成功!makebox时成功率为100%,每一张都没有empty page了!

用jTessEditorFx打开来编辑box:

在没用psm参数时,第一张图片根本一个框都没有,这样的话,jTessEditorFX的"Insert”根本没法用,即一旦一个框都没有,那这张图片就废了,但是用了psm之后,所有的图片都有框!所以用jTessEditorFx打开可以来编辑所有图片的box

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。