您好,登錄后才能下訂單哦!
快要春節了,老板發話:'提前完成工作可以提前回家';于是老貓每天加班加點趕進度,估計提前1周回家;正當老貓沉浸在幸福之時,老板過來關心問我:'老貓,車票買了嗎,買不到晚幾天走吧,那會好買';忽然有種被算計的感覺!!
人無遠慮必有近憂,車票是個大問題,老貓要買的車票這兩天放票;于是每天發動同事幫我搶票,可是連續兩次都沒搶到;老貓有點慌了,買不到車票怎么辦?
那么多車票,為什么好幾個人搶連續兩天都搶不到;
老貓分析其中可能存在原因,分析過程如下:
1>老貓買的是比較緊張的車次,搶票人數遠遠大于出票數量;
2>每次搶票和網速,手速有一定關系;
3>雖然感覺每次手動購票速度很快,但是購票人數多,手速快的也很多,對比而言也就不快了。
老貓又仔細分析了網頁購票過程:
1>登錄,驗證碼與密碼登錄;
2>刷票,選擇始發站,終點站,日期,車次;
3>出票后點擊預購;
4>等待排隊,選擇乘車人;
理論上大家刷票過程都是一樣的,但是幾個因素會影響我們購票結果:
1>第一步登錄,這個沒有問題,老貓和大家都會提前登錄;
2>第二步:先看個示意圖:
老貓提前選擇好車次等信息,到出票時刻點擊刷票;但是網速與瀏覽器渲染頁面速度,可能會影響下一步操作;
3>刷票之后,如果出現購買車次,馬上點擊預購,這里會和自己手速有關,幾百毫秒過去了,老貓可能已經排在幾百人之后了;
4>點擊預購,出現下面頁面:
這里考驗手速:點擊購票人與訂單提交,然后憑天由命吧。
結合上面分析:搶熱點車次,真有點撞大運的感覺。如何解決問題呢?
1>使用第三方軟件代購或者購買加油包;
2>拼車回家;
出去安全考慮,還是應該選擇第一個方式。但是老貓有點好奇,為什么第三方軟件或者加油包能夠購買成功?老貓猜測可能原因:
老貓認為每個賬號就是一個購票者,這些賬號由腳本控制,到時間點開始搶票,腳本速度肯定要比人的速度快,所有購買成功幾率要大于認為操作。以上部分構成純屬瞎猜,如有雷同,純屬巧合。
這樣來看,老貓除了和幾萬個人競爭,還要和第三方軟件競爭,所以熱點車次的車票更難買到了。這樣大家也就理解為什么第三方軟件購買成功幾率更大。
為了驗證這個猜測,老貓打算使用Pyhon腳本自動登錄12306,說干就干。
12306的驗證碼是比較惡心的,每次弄得不清楚,還整一些不認識的東西;老貓曾經連續10次選擇錯誤,最后系統警告我刷碼頻繁,最后只能讓人代買。
12306網頁版登錄過程分下面幾個部分:
1>輸入用戶名與密碼,如果不輸入,登錄提示錯誤;
2>圖片驗證;
2>賬號與密碼驗證;
這里我們來看后兩個步驟:
我們先借助瀏覽器分析登錄行為;
a)輸入用戶名與密碼,界面如下:
b)點擊刷新,更新驗證碼:
為了防止失效,看到效果,我們刷新驗證碼;
請求地址:https://kyfw.12306.cn/passport/captcha/captcha-image64?
請求參數:
{
'login_site': 'E',
'module': 'login',
'rand': 'sjrand',
'1546822674059':'',#當前時間戳,
'callback': 'jQuery19109060005139400158_1546821765087',#使用固定值
'_': '1546821765097'#1546821765097,通過瀏覽器觀察:每次請求值加1
}
c)選擇驗證碼并登陸(嘗試錯誤選擇,觀察結果):
過程如下 :
查看請求信息:
驗證失敗,應答信息為:
jQuery19109060005139400158_1546821765087({"result_message":"驗證碼校驗失敗","result_code":"5"});
d)圖片驗證分析:
圖片驗證請求地址:https://kyfw.12306.cn/passport/captcha/captcha-check? ;
請求參數:
{
'callback': 'jQuery19109060005139400158_1546821765087',#與上一步請求驗證圖片相同
'answer': '111,52,109,96',#根據圖片選擇點擊位置
'rand': 'sjrand',
'login_site': 'E',
'_': '1546821765102'#每次請求值加1,
}
e)如何選擇點擊位置?
有下面幾種方式:
1>機器學習圖片識別(設計內容較多,準確率不敢保證);
2>云打碼(老貓自己沒有折騰);
3>將圖片下載下來,自己選擇位置,手動填入位置;
老貓實現方式:
1>觀察請求信息,坐標應該是正確圖片大概位置,
2>圖片信息:小圖長寬為70,
第一排坐標:(35,35),(105,35),(175,35),(245,35);
第二排坐標:(35,105),(105,105),(175,105),(245,105);
3>根據圖片提示,選擇對應位置圖片,然后返回坐標;例如選擇0,1,返回值:
35,35,105,35
如果選擇成功,應答消息中會有"驗證碼校驗成功"信息;
我們根據上面分析來使用代碼完成這一過程。
老貓將其過程分析下面幾步:
1>下載圖片,然后打開圖片查看;
2>輸入正確圖片位置,獲取坐標;
3>提交驗證;
實現需要知識點:
1>requests模塊,cookie管理;
2>Python基本知識點與面向對象編程;
實現思路:
1>通過瀏覽器獲取當前callback值;
2>請求并保存驗證碼;
3>手動打開圖片,輸入正確位置,獲取坐標;
4>請求驗證,如果驗證失敗重復2~4步驟;
驗證碼驗證代碼實現:
import re
import base64
import json
import requests
import time
class login12306:
#初始化
def __init__(self, callback, nums, headers):
self.callback = callback
self.nums = nums
self.headers = headers
self.s = requests.Session()
self.fpath = './code.jpg'
#發起請求
def do_request(self, req_type='GET', url='',pdata=None, jdata=None):
if req_type == 'POST':
req = req = requests.Request(req_type, url, data=pdata, \
json=jdata,headers=self.headers)
else:
req = requests.Request(req_type, url, params=pdata, \
headers=self.headers)
pre = self.s.prepare_request(req)
try:
resp = self.s.send(pre, timeout=3)
return resp
except:
return None
#獲取驗證碼坐標
def gen_pointlist(self):
#提示輸入位置
indexs = input('input 1~8 : \n')
width = 35
points = []
select = []
#生成圖片對應位置
for i in range(0, 8):
points.append([(i) % 4 * width * 2 + width, width * (i // 4 * 2) + width])
#根據位置后去坐標點
[select.extend(points[int(index)-1]) for index in indexs]
tmp = [str(val) for val in select]
return ','.join(tmp)
#下載驗證碼
def downimg(self):
url = 'https://kyfw.12306.cn/passport/captcha/captcha-image64?'
ts = str(int(time.time() * 1000))
pdata = {
'login_site': 'E',
'module': 'login',
'rand': 'sjrand',
ts: '',
'callback': self.callback,
'_': str(self.nums)
}
req = self.do_request('GET', url, pdata=pdata)
if not req:
return
m = re.search(r'\((.*)\)', req.text)
text = m.group()[1:-1]
jdata = json.loads(text)
img = base64.b64decode(jdata['image'])
with open(self.fpath, 'wb') as f:
f.write(img)
return True
#獲取驗證碼信息
def get_qcinfo(self):
#下載驗證碼
if self.downimg():
#下載完成之后打開圖片,并輸入位置獲取坐標
indexs = self.gen_pointlist()
return indexs
#驗證碼校驗
def qc_verify(self):
indexs = self.get_qcinfo()
if not indexs:
return False
self.nums += 1
#驗證碼輸入檢查
url = 'https://kyfw.12306.cn/passport/captcha/captcha-check?'
print(indexs)
jdata = {
'callback': self.callback,'answer': indexs,'rand': 'sjrand',
'login_site': 'E','_': self.nums
}
req = self.do_request('GET', url, pdata=jdata)
#輸入成功返回True
if ('驗證碼校驗成功') in req.text:
print('驗證碼成功')
self.indexs = indexs
return True
return False
#用戶名與密碼登錄
def user_login(self):
pass
#登錄接口
def start_login(self):
while True:
if self.qc_verify():
break
time.sleep(2)
self.user_login()
if __name__ == '__main__':
callback = 'jQuery19109060005139400158_1546821765087',
nums = 1546821765097
hds = {'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Host': 'kyfw.12306.cn',
'Cache-Control': 'no-cache',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
}
obj =login12306(callback, nums, hds)
obj.start_login()
運行輸出結果如下:
瀏覽器中,輸入正確驗證碼,用戶名與密碼;點擊登錄,登錄過程如下圖:
我們完善user_login方法,代碼如下:
def user_login(self):
url = 'https://kyfw.12306.cn/passport/web/login'
jdata = {
'username': 'myusername',#更換自己用戶名
'password': 'mypwd',#更換成自己密碼
'appid': 'otn',
'answer': self.indexs,
}
req = self.do_request('POST', url, pdata=jdata)
items = [
{'url':'https://kyfw.12306.cn/otn/login/userLogin', 'f':'GET'},
{'url':'https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin','f':'GET'},
]
for item in items:
url = item.get('url')
f = item.get('f')
req = self.do_request(f, url)
url = 'https://kyfw.12306.cn/passport/web/auth/uamtk'
info = {'appid': 'otn'}
req = self.do_request('POST', url, pdata=info)
url = 'https://kyfw.12306.cn/otn/uamauthclient'
jdata = req.json()
info = {'tk': jdata['newapptk']}
req = self.do_request('POST', url, pdata=info)
req_items = [
{'url':'https://kyfw.12306.cn/otn/login/userLogin','f':'GET'},
{'url':'https://kyfw.12306.cn/otn/login/conf','f':'POST'},
{'url':'https://kyfw.12306.cn/otn/index/initMy12306Api','f':'post'},
]
for item in req_items:
url = item.get('url')
f = item.get('f')
req = self.do_request(f, url)
print(req.text)
return req
再次運行代碼結果如下:
登錄成功了,我們可以提取應答消息中的信息,判斷是否登錄成功。
對于用戶名密碼請求地址,我們可以不用關心具體作用,只需要記錄請求地址與參數,有的數據可能需要在應答中提取。基于這個基礎,我們可以使用Python完成預定車次選擇,查找賬戶中聯系人,購票這一系列操作。
經過分析,可以看到使用腳本操作,省去了頁面渲染與人為點擊這兩個操作,節省了時間,這樣訂單提交速度就比其他人快,購買成功幾率明顯增加。
但是老貓不打算使用,因為使用的人越多,這種現象越猖獗;
但是,老貓怎么回老家呢?老貓一天心不在焉,沒有一點工作狀態。老板看在心里也十分為我著急。
大家如果想學習Python及爬蟲技術,可以查看下面兩個專欄:
Python爬蟲專欄地址:https://blog.51cto.com/cloumn/detail/17 ;
Python入門專欄地址:https://blog.51cto.com/cloumn/detail/34 ;
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。