朋友圈瘋傳加速包搶票,還不如Python自動(dòng)搶票來的靠譜!

寫在前面

一年一度的春運(yùn)已經(jīng)悄然來臨,不知道身在異鄉(xiāng)的你是否搶到一張回家的火車票

又有多少人因?yàn)橐粡埿⌒〉幕疖嚻倍荒芑丶疫^春節(jié)。漂泊在外的游子在這個(gè)時(shí)候的鄉(xiāng)愁就是一張小小的火車票


近日在朋友圈被一波搶票加速包瘋狂刷屏了

小編在群里看得干著急,現(xiàn)在市面上各種平臺(tái)的搶票軟件都是收費(fèi)的的,而且不能保證百分百能搶到票,很多小伙伴甚至被一些釣魚網(wǎng)站騙錢了。這不是得不償失了嘛。

作為一個(gè)技術(shù)控,我喜歡通過自己的技術(shù)去解決問題,下面小編將制作一個(gè)12306搶票軟件,實(shí)現(xiàn)自動(dòng)搶票,一起期待吧~

代碼編寫

1、程序效果圖

沒錯(cuò),搶到票之后還是需要手動(dòng)付款的,這個(gè)對大家來說還是輕輕松松的吧~

廢話不多說,下面就直接開始技術(shù)主要部分闡述。

2、主要代碼及調(diào)試

理論部分:首先我們需要代碼實(shí)現(xiàn)一個(gè)瀏覽器功能,那么模塊基本上可以確定urllib.parse、urllib.request,這兩個(gè)包都是和網(wǎng)址有關(guān)的模塊,那么咱們?nèi)サ卿浺粋€(gè)網(wǎng)址,特別是有驗(yàn)證碼這些的網(wǎng)址,我們登錄進(jìn)去是不是就行了?答案是對的,但是我們用代碼實(shí)現(xiàn)的話,這個(gè)網(wǎng)址可能每次都有可能被代碼去請求,那么服務(wù)器怎么知道我們是一個(gè)人,而不是多個(gè)瀏覽器不同的用戶呢?

此時(shí)cookie就非常重要了,在代碼中設(shè)置好cookie,那么對方服務(wù)器自然就知道我們是一個(gè)人,比較服務(wù)器都是這么區(qū)分的。python3中 cookie這個(gè)功能是封裝在http.cookiejar這個(gè)模塊之內(nèi)。好了,代碼如下:

# coding=utf-8# author: Jason# time:2018/1/16 20:00:00#version:1.0importurllib.requestasulimporturllib.parseasuzimporthttp.cookiejarascookielibfromjsonimportloadsc=cookielib.LWPCookieJar()#先把cookie對象存儲(chǔ)為cookiejar的對象cookie = ul.HTTPCookieProcessor(c)#把cookiejar對象轉(zhuǎn)換為一個(gè)handleopener = ul.build_opener(cookie)#建立一個(gè)模擬瀏覽器,需要handle作為參數(shù)ul.install_opener(opener)#安裝一個(gè)全局模擬瀏覽器,代表無論怎么訪問都是一個(gè)瀏覽器操作而不是分開獲取驗(yàn)證碼等msg

接下來就是進(jìn)入網(wǎng)絡(luò)分析部分

首先可以使用google瀏覽器或者搜狗瀏覽器(本人用的搜狗),打開F12,也就是開發(fā)者模式,登錄12306的登錄地址https://kyfw.12306.cn/otn/login/init

兩個(gè)紅圈中第二個(gè)是驗(yàn)證碼來源,此時(shí)我們只需要記錄這個(gè)網(wǎng)頁(點(diǎn)進(jìn)去)的詳細(xì)情況,寫入代碼當(dāng)中,python3中urllib.request這個(gè)模塊打開既可。

這時(shí)候多了一個(gè)很奇妙的東西,此時(shí),這里就是驗(yàn)證碼驗(yàn)證的網(wǎng)址,那么我們是不是應(yīng)該記錄下來呢?很簡單,到Headers里面就全都看得到了

上面那個(gè)是服務(wù)器驗(yàn)證網(wǎng)址,下面就是我們回復(fù)給他的東西,那么那個(gè)163,121其實(shí)就是我亂點(diǎn)的驗(yàn)證碼坐標(biāo)了。至于為啥是坐標(biāo),因?yàn)樗怯檬髽?biāo)去點(diǎn)圖片,那么他只可能是記錄坐標(biāo),除非他自己搞了一套人工智能驗(yàn)證圖片,但基于他幾年前就這么玩了,人工智能根本沒有怎么開始,他自然只能是最原始的技術(shù)而已。

那么這代表了他是先驗(yàn)證驗(yàn)證碼,那么驗(yàn)證密碼的在哪?自然是需要驗(yàn)證碼這關(guān)能過,那我們輸一個(gè)正確的驗(yàn)證碼,再寫個(gè)錯(cuò)密碼,登錄。

此時(shí)可以看到,和驗(yàn)證碼一樣的方法,我們的回復(fù)與驗(yàn)證都在這幾個(gè)圈了,還記得上面驗(yàn)證碼失敗的時(shí)候回復(fù)給我們的code是不是有個(gè)數(shù)字?這個(gè)也很重要,那么可以看看我們的驗(yàn)證成功的驗(yàn)證碼返回給我們的是什么東西。

這次我們看到了,驗(yàn)證碼成功,顯示是4,好,那我們不就可以進(jìn)行條件判斷了么?

那么如何打開一個(gè)網(wǎng)址然后把我們點(diǎn)的東西一起發(fā)過去呢?上代碼

headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'}#先寫個(gè)頭,表示我這是瀏覽器用戶登錄而不是代碼登錄,如果不寫,代碼默認(rèn)用的簽名之類的是編程語言的標(biāo)識(shí),這樣對方服務(wù)器很容易就發(fā)現(xiàn)你是個(gè)腳本了defget_code():#獲取驗(yàn)證碼的步驟req = ul.Request('https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.6758635422370105') req.headers = headers code_file = opener.open(req).read()#此時(shí)為瀏覽器的open而不再是ul.urlopen,下同withopen(r'C:\Users\Administrator\Desktop\12306自動(dòng)搶票\code.png','wb')asf: f.write(code_file)

把驗(yàn)證碼直接下載后方電腦上,后面要坐標(biāo)只需要打開這個(gè)圖既可輸入,坐標(biāo)的輸入方式我用字典表示給大家看{1:(45,45)}{2:(120,45)}{3:(180,45)}{4:(255,45)}{5:(45,120)}{6:(120,120)}{7:(180,120)}{8:(255,120)}

根據(jù)這個(gè)驗(yàn)證碼的排序,我相信讀者應(yīng)該知道順序怎么來的吧,比較坐標(biāo)就能懂了。

咱們繼續(xù)往下寫

def main_(): get_code() code =input('輸入驗(yàn)證碼:') req = ul.Request('https://kyfw.12306.cn/passport/captcha/captcha-check') req.headers = headers data = {'answer':code,'login_site':'E','rand':'sjrand'} data = uz.urlencode(data).encode()#把字典轉(zhuǎn)換為URL querystring,此時(shí)是str,要把它變?yōu)閎yts。 html = opener.open(req,data= data).read().decode()#讀取出來是byts格式,轉(zhuǎn)換為‘utf-8(默認(rèn))print(html) result = loads(html)ifresult['result_code']=='4':print('驗(yàn)證碼通過')rep= ul.Request('https://kyfw.12306.cn/passport/web/login')rep.headers = headers data = {'username':'這里就是你用戶名','password':'這里就是你的密碼','appid':'otn'} data = uz.urlencode(data).encode() #看到了嗎,這就是你給服務(wù)器回復(fù)的東西 html1 = opener.open(rep,data = data ).read().decode() result1 = loads(html1)ifresult1['result_code'] ==0:print('賬戶密碼驗(yàn)證通過')else:print(result1['result_message'])else:print('驗(yàn)證碼校驗(yàn)失敗,重來')if__name__ =='__main__': main_()

此時(shí),咱們就過了驗(yàn)證碼密碼這一關(guān),后面是不是又要查票?那么同樣的方法,我們就可以以此類推到最后一步,這里就不一一貼代碼了

ps:查代碼這幾步的信息可是很重要喔,我們要把它記錄好,并且這里面的信息包含了各種作為信息以及他們的順序,多測試幾次基本都能搞出來,這里就是提醒一點(diǎn)

找找規(guī)律,然后用split的方法完全就可以切割出來,然后一個(gè)循環(huán),就可以得到第幾個(gè)元素是我們要的,那么后面就可以標(biāo)志判斷返回值如果是無,就沒票可以繼續(xù)查詢,直到有票就可以下一步;

那么有票的話,后面一樣也是以此類推的方式,代碼我就不重現(xiàn)了,很簡單,我就把后面出現(xiàn)需要請求的網(wǎng)址都發(fā)出來供大家觀摩

查詢車票信息

url ='https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=%s&leftTicketDTO.from_station=%s&leftTicketDTO.to_station=%s&purpose_codes=ADULT'%(train_data,from_station,to_station)

req = ul.Request('https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest')#確定訂單信息

req = ul.Request("https://kyfw.12306.cn/otn/confirmPassenger/initDc")#驗(yàn)證訂單

req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs')#準(zhǔn)備跨到下單中的過度

req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo')#檢查訂單信息

req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount')#信息提交給服務(wù)器,準(zhǔn)備進(jìn)入下單步驟

req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue')#正式進(jìn)入下單步驟

req = ul.Request('https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime?random=%s&tourFlag=dc&_json_att=&REPEAT_SUBMIT_TOKEN=%s'%(numb,time.time()))#下單確認(rèn)中,此時(shí)這個(gè)網(wǎng)址一般是進(jìn)行兩次訪問,不知為何,我還是做了兩次訪問,numb是前面查詢車票點(diǎn)擊預(yù)定回復(fù)我們的信息中的一條,有點(diǎn)難找喔,我曾經(jīng)找了三天。。。當(dāng)然是因?yàn)樽约翰蛔屑?xì)而已

zreq = ul.Request("https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue")#最后的結(jié)果回執(zhí),如果一切都順利,那么票就已經(jīng)訂了。我一般是打印他返回的內(nèi)容

'''

zreq = ul.Request("https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue")

zreq.headers = headers

data ={"REPEAT_SUBMIT_TOKEN":"%s"%numb,

"_json_att": "",

"orderSequence_no":orderId

}

data = uz.urlencode(data).encode()

html = opener.open(zreq,data=data).read().decode()

result = loads(html)

print('代碼全部過完,回去登錄下是否搞定')

print(result)

print(result['data']['submitStatus'])

if result['data']['submitStatus'] == True:

print('購票成功')

return True

else:

print('購票失敗,重試其他列車')

continue

'''

最終的回執(zhí)代碼詳細(xì) 信息,讀者可以自己嘗試多次,得到自己的回復(fù)代碼確認(rèn)是否購票成功,因?yàn)閞esult['data']['submitStatus']==True只不過是確認(rèn)訂單狀態(tài)而已,這個(gè)被我改動(dòng)過,你可以多次嘗試

最后的最后,火車票預(yù)訂成功只有30分鐘支付時(shí)間,所以我為了防止訂好票但是我人不在,特意寫了qq郵件通知

qq郵件通知:

defemail():#這是我訂票后給自己發(fā)郵件的函數(shù)importsmtplibfromemail.mime.textimportMIMETextimporttime text ='已經(jīng)為%s搶到票,速度登錄12306付款,用戶名:%s,密碼:%s'%(NAME,username,password) msg = MIMEText(text,'plain','utf-8') msg_From ='2059****16@qq.com'msg_To ='5043****75@qq.com'#是的,我有兩個(gè)qq,一個(gè)發(fā)一個(gè)收smtpSever ='smtp.qq.com'# qq郵箱的smtp Sever地址smtpPort ='465'# 開放的端口sqm ='q********eghe'# 在登錄smtp時(shí)需要login中的密碼應(yīng)當(dāng)使用授權(quán)碼而非賬戶密碼msg['from'] = msg_From msg['to'] = msg_To msg['subject'] ='Python自動(dòng)郵件-%s'% time.ctime() smtp = smtplib smtp = smtplib.SMTP_SSL()'''

smtplib的connect(連接到郵件服務(wù)器)、login(登陸驗(yàn)證)、sendmail(發(fā)送郵件)

'''smtp.connect(smtpSever, smtpPort) smtp.login(msg_From, sqm) smtp.sendmail(msg_From, msg_To, str(msg))# s = smtplib.SMTP("localhost")# s.send_message(msg)smtp.quit() print('郵件已發(fā)送~你可以安心去玩了')defemailforcode():#此函數(shù)是防止查詢有票但12306賬號(hào)掉線人不在無法訂票的提醒importsmtplibfromemail.mime.textimportMIMETextimporttime text ='%s賬號(hào)下線,速度登錄驗(yàn)證12306'% NAME msg = MIMEText(text,'plain','utf-8') msg_From ='205****516@qq.com'msg_To ='50****75@qq.com'smtpSever ='smtp.qq.com'# qq郵箱的smtp Sever地址smtpPort ='465'# 開放的端口sqm ='qowa*******ghe'# 在登錄smtp時(shí)需要login中的密碼應(yīng)當(dāng)使用授權(quán)碼而非賬戶密碼msg['from'] = msg_From msg['to'] = msg_To msg['subject'] ='Python自動(dòng)郵件-%s'% time.ctime() smtp = smtplib smtp = smtplib.SMTP_SSL()'''

smtplib的connect(連接到郵件服務(wù)器)、login(登陸驗(yàn)證)、sendmail(發(fā)送郵件)

'''smtp.connect(smtpSever, smtpPort) smtp.login(msg_From, sqm) smtp.sendmail(msg_From, msg_To, str(msg))# s = smtplib.SMTP("localhost")# s.send_message(msg)smtp.quit() print('郵件已發(fā)送~')

到這里搶票程序就寫的差不多了,后面調(diào)試調(diào)試就行了。

最后再給你們看看結(jié)果吧,畢竟寫出來不容易。

記得手動(dòng)付款哦~

記得手動(dòng)付款哦~記得手動(dòng)付款哦~

付款是最重要的,其他的都不重要,你說呢?

寫在最后

不知道你看了小編的文章有沒有自己動(dòng)手的沖動(dòng)哦~

需要源碼的小伙伴看下面,即可獲得自動(dòng)搶票源碼哦~


有了源碼,你也可以做到

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 網(wǎng)絡(luò) 理論模型,分為七層物理層數(shù)據(jù)鏈路層傳輸層會(huì)話層表示層應(yīng)用層 實(shí)際應(yīng)用,分為四層鏈路層網(wǎng)絡(luò)層傳輸層應(yīng)用層 IP...
    FlyingLittlePG閱讀 960評(píng)論 0 0
  • 本文最后更新于2018年10月16日 后續(xù)接口和流程可能發(fā)生變化 一.流程分析 瀏覽器:chrome 工具:Fid...
    意夢春秋閱讀 1,417評(píng)論 0 1
  • 之前已經(jīng)說過,數(shù)據(jù)結(jié)構(gòu)是數(shù)據(jù)的一種組織形式,根據(jù)不同的需求就會(huì)出現(xiàn)不同的數(shù)據(jù)結(jié)構(gòu),棧和隊(duì)列就是兩種特殊的線性表數(shù)據(jù)...
    我想吃碗牛肉面閱讀 248評(píng)論 0 0
  • 成為VR開發(fā)者的六個(gè)基本問題 2016-05-31小小CTO未來CTO 我常被問起能否提供更多的建議,幫助其他人進(jìn)...
    JiesonFive閱讀 2,200評(píng)論 0 3
  • 一眨眼,春節(jié)已過完了,回想像是做了一個(gè)夢。終于有時(shí)間,好好寫寫過春節(jié)這件事。 春節(jié),是中國最隆重的節(jié)日。年底,總是...
    諾feiyang閱讀 381評(píng)論 6 3

友情鏈接更多精彩內(nèi)容