12306自動搶票及自動識別驗證碼功能(二)
這幾天用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 = False
self.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=False
self.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.textcon
self.textprint.setText(self.textcon)
# 建立TABLE
def 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=False
for i in range(self.trainlistnums.count()):
if trainnum == self.trainlistnums.item(i).text():
ishave=True
break
return ishave
#獲取搶票車次
def gettrainnums(self):
tnums=[]
for i in range(self.trainlistnums.count()):
trainnum = self.trainlistnums.item(i).text()
tnums.append(trainnum)
return tnums
def 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 realips
def initStations(self):
errorCount = 0
while 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]
return
except:
print('車站程式碼讀取失敗,正在重試...')
errorCount += 1
self.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('城市程式碼下載完畢')
#獲取新Ip
def getnewip(self):
ips = self.loadtxt()
pip = random.choice(ips)
print("新ip:",pip)
return pip
def 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 cLists
def 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 cLists
def 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.content
filename = "%s%s.png" % (self.captchaDownloadName,uuid.uuid4())
with open(filename, 'wb') as f:
f.write(captcha)
return filename
#驗證碼驗證
def captchaCheck(self):
captchaErrorCount = 0
print('正在識別驗證碼...')
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('識別驗證碼成功')
break
else:
#print('識別驗證碼失敗')
captchaErrorCount += 1
def secLoginVerify(self,newapptk):
print('第二次驗證')
newAppTkErrorCount = 0
url = '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 verifyResult
except json.decoder.JSONDecodeError:
newAppTkErrorCount += 1
#登入執行緒
def loginthread(self):
self.login()
#登入
def login(self):
# 1 偽裝cookie++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
setCookieCountError = 0
self.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×tamp={}'.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'] = railDeviceId
except 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 = False
self.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 = 0
while True:
# if findTicketError > 5:
# print('查詢出現錯誤,退出程式')
# sys.exit()
try:
response = self.session.get(queryUrl,proxies=self.proxy)
trainList = response.json()['data']['result']
break
except (json.decoder.JSONDecodeError,KeyError):
self.proxy = {
'http': self.getnewip()
}
findTicketError += 1
self.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 13
trainLocation 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=filterTrainList
if 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=trainName
self.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 = True
elif trainseat=="二等座":
if trainDetailSplit[30] != '' and trainDetailSplit[30] != u'無':
self.seatType = self.seatMap[trainseat]
status = True
elif trainseat=="一等座":
if trainDetailSplit[31] != '' and trainDetailSplit[31] != u'無':
self.seatType = self.seatMap[trainseat]
status = True
elif trainseat=="硬臥":
if trainDetailSplit[28] != '' and trainDetailSplit[28] != u'無':
self.seatType = self.seatMap[trainseat]
status = True
elif trainseat == "商務座":
if trainDetailSplit[32] != '' and trainDetailSplit[32] != u'無':
self.seatType = self.seatMap[trainseat]
status = True
if self.seatType=="":
if self.notseat.isChecked():
if trainDetailSplit[26] != '' and trainDetailSplit[26] != u'無':
self.seatType = self.seatMap["無座"]
status = True
break
else:
break
else:
print("請選擇車次")
else:
print('{},{}到{} 沒有可買車次(已售完或暫停車次)'.format(self.trainDate, self.fromStationName, self.toStationName))
else:
print('{},{}到{} 無車次'.format(self.trainDate,self.fromStationName,self.toStationName))
return status
def 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"+toStationName
fromtotime=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 = 0
while True:
if not self.stoppiao:
mtime=0.1
if float(self.pushedit.text())>0 and float(self.pushedit.text())<1:
mtime=random.random()
elif float(self.pushedit.text())>=1:
mtime = random.random()+1
searchnum += 1
result = self.findTicket(False)
if result:
self.txtInfo.emit(
'當前IP: {0},查詢第 {1} 次,重新整理速率:{2}, 結果:{3}'.format(self.proxy, searchnum,mtime,self.curtrainName + "找到餘票,開始搶票"))
self.bookingTicket()
break
else:
self.txtInfo.emit('當前IP: {0},查詢第 {1} 次,重新整理速率:{2}, 結果:{3}'.format(self.proxy, searchnum,mtime, "此次沒有找到餘票"))
time.sleep(mtime)
else:
break
def submitpaker(self):
self.stoppiao=False
t = 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 = 0
while 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 += 1
self.login()
continue
print('驗證登入狀態成功checkUser')
break
except 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 = 0
while 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('訂單驗證成功')
break
print("搶到的車次:",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/confirmSingle
url = '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 = 0
while 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('訂票失敗,重新搶票')
break
else:
break
except:
qeueErrorCount += 1
# 8 queryOrderWaitTime+++++++++++++++++++++++++++++++++++++++++
waitTimeErrorCount = 0
while 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']
break
elif resultCode == -2:
print('取消次數過多,今日不能繼續訂票')
sys.exit()
else:
waitTimeErrorCount += 1
time.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 = 0
while 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檢視')
break
except json.decoder.JSONDecodeError:
resultOrderErrorCount += 1
def paintEvent(self, event):
pass
if __name__ == '__main__':
import sys
app = 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 os
n_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_model
def 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_name
return label_dict
def 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 False
if __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)] += 1
time.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)
先到這裡吧,有時間再記錄一下
相關文章
- Python3.6實現12306火車票自動搶票Python
- playwright--自動化(二):過滑塊驗證碼 驗證碼缺口識別
- 12306搶票系統無介面版本——(1)登入(12306驗證碼問題破解)
- 使用 Forth 實現驗證碼識別與自動化登入
- 使用 Crystal 實現驗證碼識別與自動化登入
- tensorflow 訓練 think-captcha 圖片驗證碼自動識別APT
- 使用 C++ 實現驗證碼識別與自動化登入C++
- WWDC 2018:自動強密碼與驗證碼自動輸入密碼
- python+selenium實現自動搶票Python
- 形式語言與自動機:實驗二——DFA識別句子
- 短影片app原始碼,圖形和簡訊驗證碼的自動識別獲取APP原始碼
- 教你用Python動重新整理搶12306火車票,附原始碼!Python原始碼
- 直播app開發搭建,圖形和簡訊驗證碼的自動識別獲取APP
- 自動化驗證碼登入如何實現?
- 使用 Chapel 實現滑動驗證碼識別
- 最新12306搶票爬蟲爬蟲
- ThinkPHP3.2.3 欄位對映/自動驗證/自動完成PHP
- python實現自動搶課指令碼Python指令碼
- 手機驗證碼自動跳轉下一個輸入框之功能
- selenium自動爬取網易易盾的驗證碼
- 自動化測試中的驗證碼處理
- BIM自動識別三維地圖-Revit模型自動識別三維地圖-IFC模型自動識別三維地圖製作地圖模型
- 驗證碼識別
- 自動化測試時對驗證碼的處理
- 使用 Seed7 實現滑動驗證碼識別
- 使用 ActionScript 實現簡單滑動驗證碼識別
- 卡證自動識別填充,簡化應用繫結操作
- API智慧識別平臺,API介面自動識別API
- php短視訊原始碼,自動生成驗證碼,支援點選更換驗證碼數字PHP原始碼
- 初探驗證碼識別
- 自動識別技術的發展及應用領域
- 使用Fortran實現當前驗證碼自動化處理
- Python web自動化爬蟲-selenium/處理驗證碼/XpathPythonWeb爬蟲
- 自動識別是否穿著工作服
- python 驗證碼識別示例(一) 某個網站驗證碼識別Python網站
- 自動識別PC端、移動端,並跳轉
- 手機直播原始碼,驗證碼自動讀秒倒數計時原始碼
- 12306火車票搶票Python程式碼最新完整版釋出,五一搶票就靠它了!Python