这几天用keras+tensorflow训练了下验证码,弄了一个gpu的显卡,训练速度杠杠的^_^, 准度直接提升了几个档次,(小白阶段只会用框架^_^),图片识别准度基本达到96%,文字识别无限接近100%,但是在12306认证的过程中,很多时候都出现及时图片识别都正确,还是认证失败的问题。目前测试了下帮朋友抢到几张票,感觉有点成就感^_^

12306图片验证测试接口:http://www.xiuler.com/test

我在认证失败的图片加上了识别结果拿出来分析,基本上图片识别都是正确的

以上训练框架,我参考了 https://github.com/libowei1213/12306_captcha基于深度学习识别12306验证码,感谢分享的文章,在此中获益良多,其实目前12306抢票脚本已经很多,我随便找了个,然后稍稍改进了下加上图形界面,有些东西可以自行调整,里面用了上面提供的框架keras+tensorflow,里面采用了当前效果最好的卷积网络模型之一:DenseNet,很强大

主要实现代码附上: (目前只是为了研究所写,代码质量可以忽略……)

12306pass.py

#coding:utf-8
import requests
import random,re,time,threading,uuid
import http.cookiejar as HC
import json
from drawPro import *
from push_progress import *
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from code12306 import *class SignWidget(QDialog):txtInfo=Signal(str)def __init__(self, parent = None):super(SignWidget, self).__init__(parent)self.setAttribute(Qt.WA_QuitOnClose, True)# 禁用安全请求警告requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)self.session = requests.session()self.session.cookies = HC.LWPCookieJar(filename='cookies')try:self.session.cookies.load(ignore_discard=True)except:print('未找到cookies文件')self.session.headers = {'Host': 'kyfw.12306.cn','Origin': 'https://kyfw.12306.cn','X-Requested-With': 'XMLHttpRequest','Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8','Referer': 'https://kyfw.12306.cn/otn/login/init','Accept': '*/*','Accept-Encoding': 'gzip, deflate, br','Accept-Language': 'zh-CN,zh;q=0.8','User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.73 Safari/537.36',}self.session.verify = Falseself.stationNameToCode = dict()self.stationCodeToName = dict()self.stationDownloadName="stationCode.txt"self.trainDate = ''self.fromStationName = ''self.fromStationCode = ''self.toStationName = ''self.toStationCode = ''self.fromStationTelecode = ''self.toStationTelecode = ''self.trainSecretStr = ''self.trainNo = ''self.trainCode = ''self.leftTicket = ''self.seatType = ''self.trainLocation = ''self.submitToken = ''self.passengerTicketStr = ''self.oldPassengerStr = ''self.orderId = ''self.stoppiao=Falseself.seatMap = {'无座': '1', '硬座': '1', '硬卧': '3', '软卧': '4', '高级软卧': '6', '动卧': 'F', '二等座': 'O', '一等座': 'M','商务座': '9'}self.canChooseSeat = dict()self.textcon=""self.captchaDownloadName="temp/"self.proxy={'http': self.getnewip()}self.initStations()# 批量待签章按钮self.login_button = QPushButton()self.login_button.setStyleSheet('QPushButton{border:1px solid #3678b5;color:#ffffff;background:#3678b5}''QPushButton:hover{background:#5098ca}')self.login_button.setText(u'登陆')self.login_button.setFixedSize(50, 30)self.login_button.setCursor(Qt.PointingHandCursor)self.login_button.clicked.connect(self.loginthread)# 测试按钮self.test_button = QPushButton()self.test_button.setStyleSheet('QPushButton{border:1px solid #3678b5;color:#ffffff;background:#3678b5}''QPushButton:hover{background:#5098ca}')self.test_button.setText(u'测试')self.test_button.setFixedSize(50, 30)self.test_button.setCursor(Qt.PointingHandCursor)self.test_button.clicked.connect(self.test)# 开始抢票按钮self.sub_button = QPushButton()self.sub_button.setStyleSheet('QPushButton{border:1px solid #3678b5;color:#ffffff;background:#3678b5}''QPushButton:hover{background:#5098ca}')self.sub_button.setText(u'开始抢票')self.sub_button.setFixedSize(50, 30)self.sub_button.setCursor(Qt.PointingHandCursor)self.sub_button.clicked.connect(self.submitpaker)# 停止抢票self.stop_button = QPushButton()self.stop_button.setStyleSheet('QPushButton{border:1px solid #3678b5;color:#ffffff;background:#3678b5}''QPushButton:hover{background:#5098ca}')self.stop_button.setText(u'停止')self.stop_button.setFixedSize(50, 30)self.stop_button.setCursor(Qt.PointingHandCursor)self.stop_button.clicked.connect(self.stoptrain)self.textprint = QTextEdit()self.textprint.setStyleSheet("QTextEdit{border:1px solid #e1e1e1;}")self.textprint.setText(self.textcon)self.textprint.setReadOnly(True)usernamelabel = QLabel()usernamelabel.setText("用户名: ")self.usernameedit = QLineEdit()self.usernameedit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.usernameedit.setText("")self.usernameedit.setFixedSize(120, 30)pwdlabel = QLabel()pwdlabel.setText("密码: ")self.pwdedit = QLineEdit()self.pwdedit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.pwdedit.setText("")self.pwdedit.setEchoMode(QLineEdit.Password)self.pwdedit.setAttribute(Qt.WA_InputMethodEnabled, False)self.pwdedit.setFixedSize(100, 30)pushlabel = QLabel()pushlabel.setText("刷新频率: ")self.pushedit = QLineEdit()self.pushedit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.pushedit.setText("0.5")self.pushedit.setFixedSize(50, 30)beginStationlabel= QLabel()beginStationlabel.setText("起点站: ")self.beginStationedit = QLineEdit()self.beginStationedit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.beginStationedit.setText("深圳北")self.beginStationedit.setFixedSize(100, 30)endStationlabel = QLabel()endStationlabel.setText("终点站: ")self.endStationedit = QLineEdit()self.endStationedit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.endStationedit.setText("长沙南")self.endStationedit.setFixedSize(100, 30)begintimelabel = QLabel()begintimelabel.setText("坐车时间: ")self.begintimeedit = QLineEdit()self.begintimeedit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.begintimeedit.setText("2019-01-29")self.begintimeedit.setFixedSize(100, 30)seatlabel = QLabel()seatlabel.setText("座位: ")self.seatedit = QLineEdit()self.seatedit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.seatedit.setText("二等座")self.seatedit.setFixedSize(100, 30)userlabel = QLabel()userlabel.setText("乘车人: ")self.useredit = QLineEdit()self.useredit.setStyleSheet("QLineEdit{border:1px solid #e1e1e1;}")self.useredit.setText("李大厨")self.useredit.setFixedSize(100, 30)self.notseat=QCheckBox()self.notseat.setText("支持无座")# 加载列表self.createtable()# 脚部信息self.footlabel = QLabel()self.footlabel.setFixedHeight(14)self.footlabel.setText("欢迎进入")self.footlabel.setStyleSheet('QLabel{color:#999;}')self.trainlistnums=QListWidget()self.trainlistnums.setStyleSheet("QListWidget{border:1px solid #e1e1e1;}")self.trainlistnums.setFixedWidth(150)self.trainlistnums.itemDoubleClicked.connect(self.delitem)main_button_lyout = QHBoxLayout()main_button_lyout.addWidget(usernamelabel)main_button_lyout.addWidget(self.usernameedit)main_button_lyout.addWidget(pwdlabel)main_button_lyout.addWidget(self.pwdedit)main_button_lyout.addWidget(self.login_button)main_button_lyout.addWidget(pushlabel)main_button_lyout.addWidget(self.pushedit)main_button_lyout.addStretch(1)main_button_lyout.addWidget(self.test_button)main_button_lyout.addWidget(self.sub_button)main_button_lyout.addWidget(self.stop_button)main_two_lyout=QHBoxLayout()main_two_lyout.addWidget(beginStationlabel)main_two_lyout.addWidget(self.beginStationedit)main_two_lyout.addWidget(endStationlabel)main_two_lyout.addWidget(self.endStationedit)main_two_lyout.addWidget(begintimelabel)main_two_lyout.addWidget(self.begintimeedit)main_two_lyout.addWidget(seatlabel)main_two_lyout.addWidget(self.seatedit)main_two_lyout.addWidget(userlabel)main_two_lyout.addWidget(self.useredit)main_two_lyout.addWidget(self.notseat)main_two_lyout.addStretch(1)main_three_lyout=QHBoxLayout()main_three_lyout.addWidget(self.trainlistnums)main_three_lyout.addWidget(self.textprint)self.pro = PushProgress()self.pro.setFixedHeight(8)self.pro.setValue(0)self.pro.hide()main_lyout = QVBoxLayout()main_lyout.addLayout(main_button_lyout)main_lyout.addLayout(main_two_lyout)main_lyout.addWidget(self.pro)main_lyout.addWidget(self.MyTable)main_lyout.addLayout(main_three_lyout)main_lyout.addWidget(self.footlabel)self.main_content = QVBoxLayout()self.main_content.addLayout(main_lyout)self.main_content.setContentsMargins(5, 5, 5, 5)self.main_layout = QVBoxLayout()self.main_layout.addLayout(self.main_content)self.setLayout(self.main_layout)self.resize(1000,600)self.txtInfo.connect(self.printinfo)self.code12306=code12306()self.text_model,self.image_model=self.code12306.load_model()self.label_dict=self.code12306.load_label_dict()#停止抢票def stoptrain(self):self.stoppiao=True# 打印信息def printinfo(self, txt):print("txt:",txt)self.textcon = txt + "\r\n" + self.textconself.textprint.setText(self.textcon)# 创建TABLEdef createtable(self):self.MyTable = QTableView()self.MyTable.setStyleSheet('QTableView{selection-color:white;}QTableView:item:selected{background:#fff;color:#000;}QTableView:item:selected:!enabled{ background:transparent;}QTableView:item{border-bottom:1px solid #ddd;padding:10px;}')self.MyTable.horizontalHeader().setStyleSheet('QHeaderView:section{background:#f2f2f2;border:none; height:40px; border-right:1px solid #dddddd;border-bottom:1px solid #dddddd}')self.MyTable.setShowGrid(False)self.MyTable.setFocusPolicy(Qt.NoFocus)self.MyTable.setFrameShape(QFrame.NoFrame)self.MyTable.horizontalHeader().setHighlightSections(False)self.MyTable.setSelectionBehavior(QAbstractItemView.SelectRows)self.MyTable.verticalHeader().setVisible(False)self.MyTable.verticalHeader().setDefaultSectionSize(40)self.MyTable.horizontalHeader().setStretchLastSection(True)model = QStandardItemModel(self.MyTable)model.setHorizontalHeaderItem(0, QStandardItem(u"车次"))model.setHorizontalHeaderItem(1, QStandardItem(u"出发站\n到达站"))model.setHorizontalHeaderItem(2, QStandardItem(u"出发时间\n到达时间"))model.setHorizontalHeaderItem(3, QStandardItem(u"历时"))model.setHorizontalHeaderItem(4, QStandardItem(u"商务座\n特等座"))model.setHorizontalHeaderItem(5, QStandardItem(u"一等座"))model.setHorizontalHeaderItem(6, QStandardItem(u"二等座"))model.setHorizontalHeaderItem(7, QStandardItem(u"软卧\n一等卧"))model.setHorizontalHeaderItem(8, QStandardItem(u"硬卧\n二等卧"))model.setHorizontalHeaderItem(9, QStandardItem(u"硬座"))model.setHorizontalHeaderItem(10, QStandardItem(u"无座"))model.setHorizontalHeaderItem(11, QStandardItem(u"操作"))self.tableOperation = OperationDelegate(self.MyTable)self.MyTable.setItemDelegateForColumn(11, self.tableOperation)self.MyTable.setModel(model)# 信号与槽self.tableOperation.addtrain.connect(self.addtrainnum)# self.MyTable.horizontalHeader().resizeSection(0, 220)# self.MyTable.horizontalHeader().resizeSection(1, 280)# self.MyTable.horizontalHeader().resizeSection(2, 60)# self.MyTable.horizontalHeader().resizeSection(5, 90)# self.MyTable.horizontalHeader().resizeSection(3, 150)# self.MyTable.setColumnHidden(6, True)# self.MyTable.setColumnHidden(7, True)# self.MyTable.setColumnHidden(8, True)def delitem(self,item):index=self.trainlistnums.currentIndex().row()self.trainlistnums.takeItem(index)def addtrainnum(self,i):print(i)filterTrain=self.filterTrainList[i]trainDetailSplit = filterTrain.split('|')trainnum=trainDetailSplit[3]if not self.checknum(trainnum):self.trainlistnums.addItem(trainnum)def checknum(self,trainnum):ishave=Falsefor i in range(self.trainlistnums.count()):if trainnum == self.trainlistnums.item(i).text():ishave=Truebreakreturn ishave#获取抢票车次def gettrainnums(self):tnums=[]for i in range(self.trainlistnums.count()):trainnum = self.trainlistnums.item(i).text()tnums.append(trainnum)return tnumsdef test(self):row_count = self.MyTable.model().rowCount()self.MyTable.model().removeRows(0, row_count)self.MyTable.model().setRowCount(0)self.findTicket()# url = 'https://www.12306.cn/index/'# proxy = {#     'http': '111.181.54.207:9999'# }# response = self.session.get(url, data=None, proxies=proxy)# result = response.text# print(result)#读取iptxt文件def loadtxt(self):f = open("ip.txt")  # 返回一个文件对象realips = []line = f.readline()  # 调用文件的 readline()方法while line:line = f.readline()line = re.sub('\n', '', line)if (line != ''):realips.append(line)f.close()return realips# def loadtxt(self):#     realips = []#     try:#         r = urllib.request.urlopen(self.ipurl,timeout=30)#         result = r.read().decode('utf-8')#         for p in result.split('\n'):#             if (p != ''):#                 realips.append(p)#         r.close()#     except Exception as e:#         print(e)#     return realipsdef initStations(self):errorCount = 0while True:if errorCount > 3:print('读取车站代码失败,退出程序')sys.exit()try:with open(self.stationDownloadName, 'r', encoding='utf8') as f:stationsStr = f.read()stations = stationsStr.split('@')for s in stations:tempStationSplit = s.split('|')self.stationNameToCode[tempStationSplit[1]] = tempStationSplit[2]self.stationCodeToName[tempStationSplit[2]] =tempStationSplit[1]returnexcept:print('车站代码读取失败,正在重试...')errorCount += 1self.downloadStations()def downloadStations(self):print('正在下载城市代码...')stationUrl = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9035'response = self.session.get(stationUrl)pattern = re.compile('\'(.*?)\'')with open(self.stationDownloadName, 'w', encoding='utf8') as f:f.write(pattern.findall(response.text)[0].lstrip('@'))print('城市代码下载完毕')#获取新Ipdef getnewip(self):ips = self.loadtxt()pip = random.choice(ips)print("新ip:",pip)return pipdef create_captcha_answser(self,nlist):# 根据手动计算,得出点击图片中心得大致位置(基本准确)answer_list_all = [(35, 39), (106, 39), (173, 39), (240, 39), (39, 106), (106, 106), (173, 106), (240, 106)]# 根据打码函数返回的json格式的图片序号进行遍历,找到其对应的坐标,并加入到列表中cLists=[]for num in nlist:x, y=answer_list_all[num]result="{0},{1}".format(str(x + random.randint(-2, 3)), str(y + random.randint(-3, 2)))cLists.append(result)cLists = ','.join(cLists)return cListsdef getCoordinate(self,picurl):txtresult = self.code12306.online_test(picurl,self.text_model,self.image_model,self.label_dict)print(txtresult)self.txtInfo.emit(str(txtresult))# coordinates = ['8,44','108,46','186,43','249,44','26,120','107,120','185,125','253,119']# cLists=[]# for num in txtresult:#     cList = coordinates[num]#     cLists.append(cList)cLists=self.create_captcha_answser(txtresult)return cListsdef getcodeurl(self):# 获取验证码captchaRes = self.session.get('https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.46630622142659206',proxies=self.proxy)captcha = captchaRes.contentfilename = "%s%s.png" % (self.captchaDownloadName,uuid.uuid4())with open(filename, 'wb') as f:f.write(captcha)return filename#验证码验证def captchaCheck(self):captchaErrorCount = 0print('正在识别验证码...')self.txtInfo.emit('正在识别验证码...')while True:if captchaErrorCount > 10:print('验证码失败次数超过限制,登录失败,重新抢票')break#下载验证码图片codeimg=self.getcodeurl()captchaStr=""try:captchaStr = self.getCoordinate(codeimg)except Exception as e:print(e)print("captchaStr:",captchaStr)self.txtInfo.emit("captchaStr:"+captchaStr)#captchaStr = captchaStr.replace('|', ',')captchaStr = requests.utils.requote_uri(captchaStr)data = {'answer': captchaStr,'login_site' :'E','rand': 'sjrand'}#验证验证码response = self.session.post('https://kyfw.12306.cn/passport/captcha/captcha-check', data = data,proxies=self.proxy)print(response.text)result = response.json()if result['result_code'] == '4':print('识别验证码成功')breakelse:#print('识别验证码失败')captchaErrorCount += 1def secLoginVerify(self,newapptk):print('第二次验证')newAppTkErrorCount = 0url = 'https://kyfw.12306.cn/otn/uamauthclient'data = {'tk': newapptk}while True:if newAppTkErrorCount > 5:print('newAppTk获取失败,退出程序')sys.exit()response = self.session.post(url, data = data)try:verifyResult = response.json()print(verifyResult)return verifyResultexcept json.decoder.JSONDecodeError:newAppTkErrorCount += 1#登录线程def loginthread(self):self.login()#登录def login(self):# 1 伪装cookie++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++setCookieCountError = 0self.proxy = {'http': self.getnewip()}try:url = 'https://kyfw.12306.cn/otn/HttpZF/logdevice?algID=WYEdoc45yu&hashCode=EhTtj7Znzyie6I21jpgekYReLAnA8fyGEB4VlIGbF0g&FMQw=0&q4f3=zh-CN&VPIf=1&custID=133&VEek=unknown&dzuS=20.0%20r0&yD16=0&EOQP=895f3bf3ddaec0d22b6f7baca85603c4&lEnu=3232235778&jp76=e8eea307be405778bd87bbc8fa97b889&hAqN=Win32&platform=WEB&ks0Q=2955119c83077df58dd8bb7832898892&TeRS=728x1366&tOHY=24xx768x1366&Fvje=i1l1o1s1&q5aJ=-8&wNLf=99115dfb07133750ba677d055874de87&0aew={}&E3gR=abfdbb80598e02f8aa71b2b330daa098&timestamp={}'.format(self.session.headers['User-Agent'], str(round(time.time() * 1000)))response = self.session.get(requests.utils.requote_uri(url),proxies=self.proxy)pattern = re.compile('\(\'(.*?)\'\)')userVerify3 = eval(pattern.findall(response.text)[0])# print('设置cookie')# print(userVerify3)railExpiration = userVerify3['exp']railDeviceId = userVerify3['dfp']#self.session.cookies['RAIL_EXPIRATION'] = railExpiration#self.session.cookies['RAIL_DEVICEID'] = railDeviceIdexcept Exception as e:print(e)# 2 做验证码验证++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++self.captchaCheck()# 3 用户名密码登陆++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++print('用户名密码登录')loginUrl = 'https://kyfw.12306.cn/passport/web/login'data = {'username': self.usernameedit.text(),'password': self.pwdedit.text(),'appid': 'otn'}response = self.session.post(loginUrl, data=data,proxies=self.proxy)loginResult = response.json()if loginResult['result_code'] != 0:print('用户名密码错误(loginCheck) {}'.format(loginResult['result_code']))self.txtInfo.emit('用户名密码错误(loginCheck) {}'.format(loginResult['result_code']))return False#self.session.cookies['uamtk'] = loginResult['uamtk']# 4 用户登录第一次验证+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++url = 'https://kyfw.12306.cn/passport/web/auth/uamtk'data = {'appid': 'otn'}response = self.session.post(url, data=data,proxies=self.proxy)self.userVerify = response.json()print('第一次验证')self.txtInfo.emit('第一次验证')if self.userVerify['result_code'] != 0:print('验证失败(uamtk) code:{}'.format(self.userVerify['result_code']))# 5 用户登录第二次验证++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++newapptk = self.userVerify['newapptk']userVerify2 = self.secLoginVerify(newapptk)print('验证通过,用户为:{}'.format(userVerify2['username']))self.txtInfo.emit('验证通过,用户为:{}'.format(userVerify2['username']))self.session.cookies.save(ignore_discard=True, ignore_expires=True)def findTicket(self,isshow=True):status = Falseself.curtrainName=""self.proxy = {'http': self.getnewip()}#1 输入站名坐车时间++++++++++++++++++++++++++++++++++++++++++++++++self.trainDate = self.begintimeedit.text()stationNames = []stationNames.append(self.beginStationedit.text())stationNames.append(self.endStationedit.text())try:stationCode = list(map(lambda x: self.stationNameToCode[x],stationNames))self.fromStationName = stationNames[0]self.fromStationCode = stationCode[0]self.toStationName = stationNames[1]self.toStationCode = stationCode[1]print(self.fromStationName,self.fromStationCode,self.toStationName,self.toStationCode)except KeyError:print('车站名称错误,重新输入')#2 查询车次+++++++++++++++++++++++++++++++++++++++++++++++++++++++queryUrl = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(self.trainDate, self.fromStationCode, self.toStationCode)findTicketError = 0while True:# if findTicketError > 5:#     print('查询出现错误,退出程序')#     sys.exit()try:response = self.session.get(queryUrl,proxies=self.proxy)trainList = response.json()['data']['result']breakexcept (json.decoder.JSONDecodeError,KeyError):self.proxy = {'http': self.getnewip()}findTicketError += 1self.txtInfo.emit('查询车次失败第{0}次'.format(findTicketError))if len(trainList) > 0:'''secretstr 0内容是 预订 1不知道什么串加车次 2车次 3始发站 4终点站 5 要坐的站 6要到的站 7出发时间 8到达时间 9历时 10是否可以预订(Y可以 N和IS_TIME_NOT_BUY 不可以)   11  leftTicket 12日期20171216 13trainLocation 15软卧 23硬卧 28硬座 29无座 26二等座 30一等座 31商务座 32'''#3 过滤车次++++++++++++++++++++++++++++++++++++++++++++++++filterTrainList = []for train in trainList:trainDetailSplit = train.split('|')#if trainDetailSplit[11] == 'Y' and (not(trainDetailSplit[31] == ''or trainDetailSplit[31] == '无') or not(trainDetailSplit[30] == ''or trainDetailSplit[30] == '无') or not(trainDetailSplit[26] == ''or trainDetailSplit[26] == '无') or not(trainDetailSplit[23] == ''or trainDetailSplit[23] == '无') or not(trainDetailSplit[28] == ''or trainDetailSplit[28] == '无') or not(trainDetailSplit[29] == ''or trainDetailSplit[29] == '无')):filterTrainList.append(train)if len(filterTrainList) > 0:self.filterTrainList=filterTrainListif isshow:self.printTrainList(filterTrainList)#4 锁定用户输入车次++++++++++++++++++++++++++++++++++++++#trainName = input('请输入要预订的列车编号:').upper()trainnums=self.gettrainnums()print("trainnums:",trainnums)if len(trainnums)>0:for trainName in trainnums:if not status:for filterTrain in filterTrainList:trainDetailSplit = filterTrain.split('|')if trainDetailSplit[3] == trainName:self.seatType=""self.curtrainName=trainNameself.trainSecretStr = trainDetailSplit[0]self.trainNo = trainDetailSplit[2]self.trainCode = trainDetailSplit[3]self.fromStationTelecode = trainDetailSplit[6]self.toStationTelecode = trainDetailSplit[7]self.leftTicket = trainDetailSplit[12]self.trainLocation = trainDetailSplit[15]trainseat=self.seatedit.text()if trainseat=="硬座":if trainDetailSplit[29] != '' and trainDetailSplit[29] != u'无':self.seatType = self.seatMap[trainseat]status = Trueelif trainseat=="二等座":if trainDetailSplit[30] != '' and trainDetailSplit[30] != u'无':self.seatType = self.seatMap[trainseat]status = Trueelif trainseat=="一等座":if trainDetailSplit[31] != '' and trainDetailSplit[31] != u'无':self.seatType = self.seatMap[trainseat]status = Trueelif trainseat=="硬卧":if trainDetailSplit[28] != '' and trainDetailSplit[28] != u'无':self.seatType = self.seatMap[trainseat]status = Trueelif trainseat == "商务座":if trainDetailSplit[32] != '' and trainDetailSplit[32] != u'无':self.seatType = self.seatMap[trainseat]status = Trueif self.seatType=="":if self.notseat.isChecked():if trainDetailSplit[26] != '' and trainDetailSplit[26] != u'无':self.seatType = self.seatMap["无座"]status = Truebreakelse:breakelse:print("请选择车次")else:print('{},{}到{} 没有可买车次(已售完或暂停车次)'.format(self.trainDate, self.fromStationName, self.toStationName))else:print('{},{}到{} 无车次'.format(self.trainDate,self.fromStationName,self.toStationName))return statusdef printTrainList(self,filterTrainList):model = self.MyTable.model()for k,filterTrain in enumerate(filterTrainList):ft = filterTrain.split('|')trainnum = ft[3]fromStationName = self.stationCodeToName[ft[6]]toStationName = self.stationCodeToName[ft[7]]fromtime=ft[8]totime=ft[9]totaltime=ft[10]tedeng=(ft[32] if (ft[32]!="") else "--")yideng=(ft[31] if (ft[31]!="") else "--")erdeng = (ft[30] if (ft[30]!="") else "--")ruanwo=(ft[23] if (ft[23]!="") else "--")yingwo=(ft[28] if (ft[28]!="") else "--")yingzuo=(ft[29] if (ft[29]!="") else "--")wuzuo=(ft[26] if (ft[26]!="") else "--")fromtoStation=fromStationName+"\n"+toStationNamefromtotime=fromtime+"\n"+totime# status = QStandardItem()# status.setText("未完成")# status.setTextAlignment(Qt.AlignCenter)# status.setForeground(QBrush(QColor(255, 0, 0)))model.setItem(k, 0, QStandardItem(str(trainnum)))model.setItem(k, 1, QStandardItem(fromtoStation))model.setItem(k, 2, QStandardItem(fromtotime))model.setItem(k, 3, QStandardItem(totaltime))model.setItem(k, 4, QStandardItem(tedeng))model.setItem(k, 5, QStandardItem(yideng))model.setItem(k, 6, QStandardItem(erdeng))model.setItem(k, 7, QStandardItem(ruanwo))model.setItem(k, 8, QStandardItem(yingwo))model.setItem(k, 9, QStandardItem(yingzuo))model.setItem(k, 10, QStandardItem(wuzuo))model.setItem(k, 11, QStandardItem(""))#self.footlabel.setText("温馨提示: 共获取到 <font style='color:red'>{0}</font> 个车次.".format(len(filterTrainList)))#获取用户参数信息def choosePassenger(self,message):passengerList = message['data']['normal_passengers']print('账户可订票乘客: {}'.format(' '.join(list(map(lambda x: x['passenger_name'], passengerList)))))pessnames = self.useredit.text()  #输入订票乘客pesstotalnames=pessnames.split(",")pessDetailList=[]for pessengerName in pesstotalnames:for p in passengerList:if pessengerName == p['passenger_name']:pessengerDetail = {'passenger_flag' : p['passenger_flag'],'passenger_type' : p['passenger_type'],'passenger_name' : p['passenger_name'],'passenger_id_type_code' : p['passenger_id_type_code'],'passenger_id_no' : p['passenger_id_no'],'mobile_no' : p['mobile_no']}pessDetailList.append(pessengerDetail)return pessDetailList#获取乘客信息def getuserlist(self):self.session.headers['Referer'] = 'https://kyfw.12306.cn/otn/leftTicket/init'# 3 initDC+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'data = '_json_att='response = self.session.post(url, data=data)pattern = re.compile('globalRepeatSubmitToken = \'(.*?)\'')pattern2 = re.compile("key_check_isChange':'(.*?)'")self.submitToken = pattern.findall(response.text)[0]self.keyCheckIsChange = pattern2.findall(response.text)[0]print('token:{}'.format(self.submitToken))print('key_check_isChange:{}'.format(self.keyCheckIsChange))# 4 getPassengerDTOs++++++++++++++++++++++++++++++++++++++++++++++++++++++print('正在获取乘客信息')url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'data = {'_json_att': '','REPEAT_SUBMIT_TOKEN': self.submitToken}response = self.session.post(url, data=data)result = response.json()# print(result)print('获取信息成功')self.pd = self.choosePassenger(result)#self.chooseSeat(self.seatedit.text())def threadpiao(self):trainnums = self.gettrainnums()if len(trainnums) > 0:searchnum = 0while True:if not self.stoppiao:mtime=0.1if float(self.pushedit.text())>0 and float(self.pushedit.text())<1:mtime=random.random()elif float(self.pushedit.text())>=1:mtime = random.random()+1searchnum += 1result = self.findTicket(False)if result:self.txtInfo.emit('当前IP: {0},查询第 {1} 次,刷新速率:{2}, 结果:{3}'.format(self.proxy, searchnum,mtime,self.curtrainName + "找到余票,开始抢票"))self.bookingTicket()breakelse:self.txtInfo.emit('当前IP: {0},查询第 {1} 次,刷新速率:{2}, 结果:{3}'.format(self.proxy, searchnum,mtime, "此次没有找到余票"))time.sleep(mtime)else:breakdef submitpaker(self):self.stoppiao=Falset = threading.Thread(target=self.threadpiao)t.setDaemon(True)t.start()#组合购票人def combinuser(self,seatType,plist):passengerTicketStr=""oldPassengerStr=""for pd in plist:passengerTicketStr += seatType + ',' + pd['passenger_flag'] + ',' + pd['passenger_type'] + ',' + pd['passenger_name'] + ',' + pd['passenger_id_type_code'] + ',' + \pd['passenger_id_no'] + ',' + pd['mobile_no'] + ',N_'oldPassengerStr += pd['passenger_name'] + ',' + pd['passenger_id_type_code'] + ',' + pd['passenger_id_no'] + ',' + pd['passenger_type'] + '_'passengerTicketStr=passengerTicketStr[:-1]return passengerTicketStr,oldPassengerStr#抢票下单def bookingTicket(self):# 1 checkUser +++++++++++++++++++++++++++++++++++++++++++++self.session.headers['Referer'] = 'https://kyfw.12306.cn/otn/leftTicket/init'userCheckError = 0while True:if userCheckError > 5:print('用户登录检测失败,退出程序')sys.exit()url = 'https://kyfw.12306.cn/otn/login/checkUser'try:result = self.session.post(url).json()print(result)if not result['data']['flag'] :print('用户未登录checkUser')userCheckError += 1self.login()continueprint('验证登录状态成功checkUser')breakexcept json.decoder.JSONDecodeError:userCheckError += 1# 2 submitOrderRequest+++++++++++++++++++++++++++++++++++++print('正在提交订单...')self.txtInfo.emit('正在提交订单...')url = 'https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest'data = {'secretStr':self.trainSecretStr,'train_date':self.trainDate,'back_train_date':time.strftime("%Y-%m-%d", time.localtime(time.time())),'tour_flag':'dc',  # dc 单程'purpose_codes':'ADULT',  # adult 成人票'query_from_station_name':self.fromStationName,'query_to_station_name':self.toStationName}data = str(data)[1:-1].replace(':','=').replace(',','&').replace(' ','').replace('\'','')data = requests.utils.requote_uri(data)result = self.session.post(url,data=data).json()# print('submitOrderRequest+++++')# print(result)if not result['status']:print('提交订单失败 status = {}'.format(result['status']))self.txtInfo.emit('提交订单失败 status = {}'.format(result['status']))sys.exit()print('提交订单成功')self.txtInfo.emit('提交订单成功')url = 'https://kyfw.12306.cn/otn/confirmPassenger/initDc'data = '_json_att='response = self.session.post(url, data=data)pattern = re.compile('globalRepeatSubmitToken = \'(.*?)\'')pattern2 = re.compile("key_check_isChange':'(.*?)'")self.submitToken = pattern.findall(response.text)[0]self.keyCheckIsChange = pattern2.findall(response.text)[0]# print('token:{}'.format(self.submitToken))# print('key_check_isChange:{}'.format(self.keyCheckIsChange))# 4 getPassengerDTOs++++++++++++++++++++++++++++++++++++++++++++++++++++++print('正在获取乘客信息')self.txtInfo.emit('正在获取乘客信息')url = 'https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs'data = {'_json_att': '','REPEAT_SUBMIT_TOKEN': self.submitToken}response = self.session.post(url, data=data)result = response.json()# print(result)pdlists = self.choosePassenger(result)#self.chooseSeat(self.seatedit.text())# 5 checkOrderInfo++++++++++++++++++++++++++++++++++++++++++++++++++++++++print('正在验证订单...')self.txtInfo.emit('正在验证订单...')self.passengerTicketStr,self.oldPassengerStr=self.combinuser(self.seatType,pdlists)# print("passengerTicketStr:",self.passengerTicketStr)# print("oldPassengerStr:", self.oldPassengerStr)url = 'https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo'data = 'cancel_flag=2&bed_level_order_num=000000000000000000000000000000&passengerTicketStr={}&oldPassengerStr={}_&tour_flag=dc&randCode=&whatsSelect=1&_json_att=&REPEAT_SUBMIT_TOKEN={}'.format(self.passengerTicketStr,self.oldPassengerStr,self.submitToken)data = requests.utils.requote_uri(data)checkOrderRrrorCount = 0while True :if checkOrderRrrorCount > 3:print('验证订单失败,退出程序')sys.exit()response = self.session.post(url, data = data)result = response.json()if result['data']['submitStatus']:print('订单验证成功')self.txtInfo.emit('订单验证成功')breakprint("抢到的车次:",self.trainNo,"座位类型:",self.seatType)self.txtInfo.emit("抢到的车次:"+self.trainNo+"座位类型:"+self.seatType)# 6 getQueueCount+++++++++++++++++++++++++++++++++++++++++++++++++++++++++url = 'https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount'dateGMT = time.strftime('%a %b %d %Y %H:%M:%S  GMT+0800', time.strptime(self.trainDate, '%Y-%m-%d'))# data = 'train_date={}&train_no={}&stationTrainCode={}&seatType={}&fromStationTelecode={}&toStationTelecode={}&leftTicket={}&purpose_codes=00&train_location={}&_json_att=&REPEAT_SUBMIT_TOKEN={}'.format(#     dateGMT,self.trainNo,self.trainCode,self.seatType,self.fromStationTelecode,self.toStationTelecode,self.leftTicket,self.trainLocation,self.submitToken# )data = {'train_date' : dateGMT,'train_no' : self.trainNo,'stationTrainCode' : self.trainCode,'seatType' : self.seatType,'fromStationTelecode' : self.fromStationTelecode,'toStationTelecode' : self.toStationTelecode,'leftTicket' : self.leftTicket,'purpose_codes' : '00','train_location' : self.trainLocation,'_json_att' : '','REPEAT_SUBMIT_TOKEN' : self.submitToken}response = self.session.post(url, data = data)print('getQueueCount++++++')result = response.json()print(result)self.txtInfo.emit(str(result))# 7 confirmSingleForQueue++++++++++++++++++++++++++++++++++++++++++++++++++#https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleurl = 'https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue'data = {'passengerTicketStr' : self.passengerTicketStr,'oldPassengerStr' : self.oldPassengerStr,'randCode' : '','purpose_codes' : '00','key_check_isChange' : self.keyCheckIsChange,'leftTicketStr' : self.leftTicket,'train_location' : self.trainLocation,'choose_seats' : '','seatDetailType' : '000','whatsSelect' : '1','roomType' : '00','dwAll' : 'N','_json_att' : '','REPEAT_SUBMIT_TOKEN' : self.submitToken}qeueErrorCount = 0while True:response = self.session.post(url, data = data)try:result = response.json()print('confirmSingleForQueue++++++')print(result)self.txtInfo.emit('confirmSingleForQueue++++++\n'+str(result))if not result['data']['submitStatus']:print('订票失败,重新抢票')self.txtInfo.emit('订票失败,重新抢票')breakelse:breakexcept:qeueErrorCount += 1# 8 queryOrderWaitTime+++++++++++++++++++++++++++++++++++++++++waitTimeErrorCount = 0while True:# if waitTimeErrorCount > 10:#     print('请求次数过多,退出程序')#     sys.exit()url = 'https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime?random={}&tourFlag=dc&_json_att=&REPEAT_SUBMIT_TOKEN={}'.format(str(round(time.time() * 1000)),self.submitToken)response = self.session.get(url)result = response.json()print(result)self.txtInfo.emit('等待下票排队时间++++++\n'+str(result))resultCode = result['data']['waitTime']if resultCode == -1:self.orderId = result['data']['orderId']breakelif resultCode == -2:print('取消次数过多,今日不能继续订票')sys.exit()else:waitTimeErrorCount += 1time.sleep(2.5)# 8 resultOrderForDcQueue+++++++++++++++++++++++++++++++++++++++++url = 'https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue'data = 'orderSequence_no={}&_json_att=&REPEAT_SUBMIT_TOKEN={}'.format(self.orderId,self.submitToken)resultOrderErrorCount = 0while True:if resultOrderErrorCount > 3:print('查询订单错误')sys.exit()response = self.session.post(url, data = data)try:result = response.json()print(result)if result['data']['submitStatus']:self.txtInfo.emit('订票成功,请登录12306查看支付')print('订票成功,请登录12306查看')breakexcept json.decoder.JSONDecodeError:resultOrderErrorCount += 1def paintEvent(self, event):passif __name__ == '__main__':import sysapp = QApplication(sys.argv)table = SignWidget()table.show()sys.exit(app.exec_())

code12306.py   识别图片类

from model.densenet import DenseNet
from image_utils import *
import numpy as np
import time,random
import shutil
import osn_classes = 80
image_shape = (64, 64, 3)
text_model_weight = "saves/DenseNet-BC_k=12_d=40.weight"
image_model_weight = "saves/DenseNet-BC_k=24_d=40.weight"
save_path = "/Users/jylonger/Documents/IMAGE"
save_fail_path = "/Users/jylonger/Documents/FAIL"
class code12306():def load_model(self):print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))text_model = DenseNet(classes=n_classes, input_shape=image_shape, depth=40, growth_rate=12, bottleneck=True,reduction=0.5, dropout_rate=0.0, weight_decay=1e-4)image_model = DenseNet(classes=n_classes, input_shape=image_shape, depth=40, growth_rate=24, bottleneck=True,reduction=0.5, dropout_rate=0.0, weight_decay=1e-4)print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))text_model.load_weights(text_model_weight)image_model.load_weights(image_model_weight)return text_model, image_modeldef load_label_dict(self):# 读取类别名称label_dict = {}with open("labels.txt", encoding="utf-8") as file:for line in file:class_name, id = line.strip().split()label_dict[int(id)] = class_namereturn label_dictdef online_test(self,image_path,text_model, image_model, label_dict):"""获取验证码图片、模型识别、提交:return:"""# 下载验证码图片到本地#image_path = image_utils.download_captcha()# 切割验证码为文字部分和图片部分raw_texts, raw_images = process_raw_images(image_path, (image_shape[0], image_shape[1]))# 图像转换为np数组texts, images = np.array([np.asarray(image) for image in raw_texts]), np.array([np.asarray(image) for image in raw_images])# 模型输出text_predict = text_model.predict(texts)image_predict = image_model.predict(images)# 预测结果text_result = np.argmax(text_predict, 1)print(text_result)image_result = np.argmax(image_predict, 1)# 概率text_prob = np.max(text_predict, 1)image_prob = np.max(image_predict, 1)# 类别名text_label = [label_dict[r] for r in text_result]print(text_label)image_label = [label_dict[r] for r in image_result]print(image_label)ids = set()for r1 in text_result:for id, r2 in enumerate(image_result):if r1 == r2:ids.add(id)return ids# result = image_utils.submit_captcha(ids)# print(result)# if "成功" in result:#     # if save_path:#     #     # 保存图片#     #     for id in ids:#     #         image_utils.save(raw_images[id], os.path.join(save_path, "IMG"), label_dict[image_result[id]])#     #     for id, image in enumerate(raw_texts):#     #         image_utils.save(image, os.path.join(save_path, "TXT"), label_dict[text_result[id]])#     return True# else:#     if save_fail_path:#         for id,image in enumerate(raw_images):#             image_utils.save(image, os.path.join(save_fail_path, "IMG"), image_label[id])#         for id, image in enumerate(raw_texts):#             image_utils.save(image, os.path.join(save_fail_path, "TXT"), text_label[id])#         # if not os.path.exists(save_fail_path):#         #     os.mkdir(save_fail_path)#         # shutil.move(image_path, save_fail_path)#     return Falseif __name__ == '__main__':code12306=code12306()text_model, image_model = code12306.load_model()label_dict = code12306.load_label_dict()test_result = {True: 0, False: 0}try:test_result[code12306.online_test(text_model, image_model, label_dict)] += 1time.sleep(4)true_times, false_times = test_result[True], test_result[False]print("%d/%d 准确率:%.3f" % (true_times, true_times + false_times, true_times / (true_times + false_times)))except Exception as e:time.sleep(4)

先到这里吧,有时间再记录一下

12306自动抢票及自动识别验证码功能(二)相关推荐

  1. 12306自动抢票及自动识别验证码功能(一)

    其实12306抢票之前有做过,近年来随着技术的发展AI的兴起,我也随波逐流,研究了下python深度学习,来实现12306全自动抢票工具. 1. 实现12306自动识别验证码,我这里用的比较简单,目前 ...

  2. 12306自动抢票及自动识别验证码功能(三)--分流

    这几天研究了下12306分流,之前12306pass不停切换CDN来刷新数据,这样减少缓存时间,写了个脚本从官网上抓了一批CDN服务器来测试 验证cdn脚本: #! /usr/bin/env pyth ...

  3. python爬取12306列车信息自动抢票并自动识别验证码(二)selenium登录验证篇

    项目前言 自学python差不多有一年半载了,这两天利用在甲方公司搬砖空闲之余写了个小项目--[12306-tiebanggg-master]注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时 ...

  4. 2021最新 python爬取12306列车信息自动抢票并自动识别验证码(三)购票篇

    项目前言 tiebanggg又来更新了,项目--[12306-tiebanggg-master]注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时间进行删除:切忌用于一切非法途径,否则后果自行 ...

  5. python爬取12306列车信息自动抢票并自动识别验证码(一)列车数据获取篇

    项目前言 自学python差不多有一年半载了,这两天利用在甲方公司搬砖空闲之余写了个小项目--[12306-tiebanggg-master].注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一 ...

  6. 2021最新python爬取12306列车信息自动抢票并自动识别验证码

    项目描述 项目前言 tiebanggg又来更新了,项目--[12306-tiebanggg-master]注:本项目仅供学习研究,如若侵犯到贵公司权益请联系我第一时间进行删除:切忌用于一切非法途径,否 ...

  7. 基于python的12306自动抢票系统的设计与实现

    铁路售票系统12306网站作为一个广受人们的日常使用工具,受大极大的关注.铁路售票的管理者都主要考虑降低成本,提升售票服务满意度.一年一度的春运和节假日出行高峰期,给众多的出行群众者带来了极大的烦恼, ...

  8. python github 12306 文贤平_GitHub - itsmartkit/12306-Ticket-Booking: 12306自动抢票系统(2020-01-10)...

    基于Python的12306自动订票系统 系统功能 1.余票监控:发现余票自动下单 2.自动打码:采用第三方免费接口/本地识别算法两种模式,自动验证图片验证码 3.小黑屋:发展有余票但是下单失败的车次 ...

  9. python 100行代码实现 12306 自动抢票

    基于Selenium和Chrome浏览器实现. 默认抢票类型为普通票,硬座.需求多的话可以在源码里改,我写的注释挺详细. 复制粘贴就能使用,2019年8月13日 测试可用. from selenium ...

最新文章

  1. 编译 | 5G时代的游戏世界:一年后的AR与VR将会发生的几个变化
  2. 前端论坛、博客及公众号汇总
  3. 英特尔凌动处理器_曾押宝英特尔凌动CPU,华硕手机如今活得如何了?
  4. oracle 建表时间戳类型,Oracle插入timestamp类型数据详解
  5. 检测session用户信息跳转首页界面
  6. 电脑长时间睡眠会自动关机吗_长期对着电脑皮肤会变黑吗?经常对电脑如何保护皮肤?...
  7. java加载properties文件的几种方式,java高级面试笔试题
  8. thinkphp3.2.3 自动验证 正则验证
  9. python爬淘宝评论_python爬虫实例,一小时上手爬取淘宝评论(附代码)
  10. JS 生成条形码(一维码)jsBarcode
  11. 如何在iOS手机上进行自动化测试
  12. 自动对比度、灰阶调整
  13. 计算机盘0字节可用,本地磁盘显示0字节可用数据恢复方法教程
  14. JDBC SSL连接MySQL
  15. 首先下载安装data.table包_首次揭秘“超级签”与企业包行业内幕!
  16. OIS利率查询_图表加数据OIS隔夜基准利率掉期
  17. 三星官方smdkv210 uboot移植到我的s5pv210开发板
  18. Java—泛型、内部类、多继承
  19. 怎么确保数据在网络传输的安全性?
  20. 1x pcie 引脚_PCIe 接口 引脚定义 一览表

热门文章

  1. 外包公司面试门槛高吗?软件测试员进外包公司容易吗?
  2. 传奇登录器修改服务器列表,传奇登录器TCP服务器远程列表「防劫持」设置教程...
  3. [BugKu Web]ez_serialize
  4. word2vec你可能不知道的秘密
  5. java基础国庆作业_0715于昊-国庆作业.md
  6. 从翻唱到原创,抖音千万粉丝网红郭聪明是如何养成的?
  7. Mysql、Oracle、DM、Tbase数据库差异性
  8. 商圈分析如何大数据软件采集相关要素
  9. 分享:ThinkPad E40无线网卡驱动安装 FOR CENTOS6.3
  10. 旷厂练习生Vol.10 | 一名“旷视大学3年级研究生”的观察报告