1. 程式人生 > >python3爬蟲session處理12306火車票動態圖片驗證碼登入

python3爬蟲session處理12306火車票動態圖片驗證碼登入

一、 實現需求
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