python3爬蟲session處理12306火車票動態圖片驗證碼登入
阿新 • • 發佈:2019-01-07
一、 實現需求
1、 登入12306
使用者名稱與密碼是明碼登入,無需處理
2、 動態圖片驗證碼
是8張動態圖片,圖片很小
可能要選擇圖片中的1—3個不等圖片
3、 查票與購票
要定位到登入url,及要提交的引數
二、 實現原理
1、 採用session技術
儘管cookie與session本質上是一回事,但不能混用,要麼採用cookie,要麼採用session
2、 採用PIL處理圖片
response下載位元組儲存到本地圖片檔案,用PIL顯示圖片
3、 12306驗證碼圖片
1) 是一張圖片,要找出其中的1—3張圖片
2) 這張圖片中有8張小圖片
分2排
上一排序號為0,1,2,3,
下一排序號為4,5,6,7
3) 這8張小圖片相對中心座標
[‘35,35’,’105,35’,’175,35’,’245,35’,’35,105’,’105,105’,’175,105’,’245,105’]
4) 假設要提交第2,4,6張圖片,則提交資料為
175,35,35,105,175,105
分別對應第2,4,6圖片座標位置
4、 登入
同一個session驗證通過後,即可以登入
三、 完整示例如下
# -*- coding: utf-8 -*-
"""
2018-06-22 15:49:34
作者:劉明
"""
import requests
from PIL import Image
from json import loads
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# 禁用安全請求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
headers = {
"User-Agent" :"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"
}
session = requests.session()
def getCheckImgIndex():
url = "https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand";
response = session.get(url=url,headers=headers,verify=False )
# 把驗證碼圖片儲存到本地
f=open('12306.jpg','wb') #也可以是其他任何檔名,圖片儲存在當前目錄下
f.write(response.content)
f.close
img=Image.open('12306.jpg')
img.show()
img.close() #關閉後,不關閉顯示圖片
#=======================================================================
# 根據開啟的圖片識別驗證碼輸入圖片索引序號,有可以是1張、2張、3張圖片的序號,序號之間用逗號隔開
#例如2,4,6,表示第1排第2,第2排第4,6張
# ---------------------------------------
# | | |
# 0 | 1 | 2 | 3
# | | |
# ---------------------------------------
# | | |
# 4 | 5 | 6 | 7
# | | |
# ---------------------------------------
#=======================================================================
checkindex = input('請輸入驗證碼位置,以","分割(例如2,4,6):')
return checkindex
#提交驗證圖片索引位置,並返回驗證結果True/False
def postcheckImage(checkindex):
# 分割使用者輸入的驗證碼位置
indexs = checkindex.split(',')
# 由於12306官方驗證碼是驗證正確驗證碼的座標範圍,我們取每個驗證碼中點的座標(大約值)
imgcentor_position = ['35,35','105,35','175,35','245,35','35,105','105,105','175,105','245,105']
checkokList = [] #例如得到:['175,35', '35,105', '175,105']
for index in indexs:
checkokList.append(imgcentor_position[int(index)])
# 正確驗證碼的座標拼接成字串,作為網路請求時的引數
checkokImgStr = ','.join(checkokList) #生成的資料例如:175,35,35,105,175,105
checkUrl = "https://kyfw.12306.cn/passport/captcha/captcha-check"
data = {
'login_site':'E', #固定的
'rand':'sjrand', #固定的
'answer':checkokImgStr #驗證碼對應的中心座標字串序號,例如175,35,35,105,175,105
}
# 傳送驗證
response = session.post(url=checkUrl,data=data,headers=headers,verify=False)
# 返回json格式的字串,用json模組解析 -->dict
checkResult = loads(response.content)
print(checkResult)
checkcode = checkResult['result_code']
print(checkcode,type(checkcode)) #數字型別的字串
# 取出驗證結果,4:成功 5:驗證失敗 7:過期
if checkcode == '4':
print('驗證碼提交成功!')
return True
else:
print('驗證碼提交失敗!')
return False
def login12306():
#輸入使用者名稱
username = input('使用者名稱:')
# 輸入密碼
password = input('密碼:')
loginUrl = "https://kyfw.12306.cn/passport/web/login"
data = {
'username':username,
'password':password,
'appid':'otn' #固定的標誌
}
response = session.post(url=loginUrl,data=data,headers=headers,verify=False)
result = loads(response.content)
print (result)
isLoginOK = result['result_message']
# 結果的編碼方式是Unicode編碼,所以對比的時候字串前面加u,或者mes.encode('utf-8') == '登入成功'進行判斷,否則報錯
if isLoginOK == '登入成功':
print ('登入成功,可以購票!')
else:
print ('登入失敗!' )
if __name__ == '__main__':
imgindex=getCheckImgIndex()
check=postcheckImage(imgindex)
login12306()
'''
#輸出結果如下
請輸入驗證碼位置,以","分割[例如2,5]:0,3
{'result_message': '驗證碼校驗成功', 'result_code': '4'}
4 <class 'str'>
驗證碼提交成功!
使用者名稱:xxxx(在此輸入你的使用者id)
密碼:yyyy(在此輸入的登入密碼)
{'result_message': '登入成功', 'result_code': 0, 'uamtk': '0gFZ3cDiqqy2UuG0310dDMFyW0uMHHNnJ84KoAbcb2b0'}
登入成功,可以購票!
'''
created by 劉明
www.isscollege.com