Python-requests-12306-登陸
好久沒有更新了,今天週一困得要命,更新篇文章提提神。 本來想用requests寫個12306購票,但是感覺寫起來會很長,想想還是分開寫好點 想想把12306分為2部分: 1.登陸 2.購票
-
首先,我們先來看下12306網站
-
問題1:網站連線不安全 可能要跳過ssl驗證
-
問題2:登陸時的驗證碼問題
-
然後,我們來手動真正的登陸一次12306 看看登陸時需要提交哪些data 通過chrome瀏覽器抓包後能發現一共需要3個引數 1)username: 你的賬號 2)password:你的密碼 3)appid:otn
-
但是我們沒發現任何關於驗證碼有關的引數,可見是在我們登陸之前網站就提前驗證了我們提交的驗證碼引數
-
在login上面有個captcha_check應該就是驗證碼的驗證,我們來看下
-
也是3個引數 1)answer:就是你登陸時選擇的答案的對應的座標 2)login_site:E 3)rand:sjrand
-
這裡我介紹兩種方法破解這個驗證碼: A)手動輸入 B)打碼平臺:超級鷹
-
先來說下手動輸入的這種方法,這種方法就需要我們去測試這個座標怎麼得來的。
-
先來看下我登陸時驗證的驗證碼圖片
-
找出圖片中的儀表盤和中國結 提交的正確座標有3個都用逗號隔開 32,42,256,46,35,122 我們來測試下看看這3個座標都是哪裡 我們以圖中箭頭標記處為起點 範圍為圖片部分
-
分別來看下這3個座標(微信的ALT+A 或者QQ的CTRL+ALT+A截圖) 1)32,42
2)256,46
3)35,122
-
不用說大家也都明白了,座標該怎麼得到了,而且答案也不是唯一的 按照格式提交就OK了 每個數字用逗號隔開32,42,256,46,35,122
-
B)第二種方法我這裡使用超級鷹打碼平臺,說實話,我寫程式碼測試的時候這個打碼平臺,簡直沒法說,準確率太低…(http://www.chaojiying.com) 大家去超級鷹官網上去下載python的對應檔案然後進行修改就OK了 這裡不再介紹打碼平臺的配置,直接貼上程式碼
#!/usr/bin/env python # coding:utf-8 import requests from hashlib import md5 class Chaojiying_Client(object): def __init__(self, username, password, soft_id): #平臺賬號 self.username = username #平臺密碼 self.password = md5(password.encode('utf-8')).hexdigest() self.soft_id = soft_id self.base_params = { 'user': self.username, 'pass2': self.password, 'softid': self.soft_id, } self.headers = { 'Connection': 'Keep-Alive', 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', } def PostPic(self, im, codetype): """ im: 圖片位元組 codetype: 題目型別 參考 http://www.chaojiying.com/price.html """ params = { 'codetype': codetype, } params.update(self.base_params) files = {'userfile': ('ccc.jpg', im)} r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers) return r.json() def ReportError(self, im_id): """ im_id:報錯題目的圖片ID """ params = { 'id': im_id, } params.update(self.base_params) r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers) return r.json()
-
我們只需要把驗證碼圖片傳到平臺對應連結就OK 他會返回一個json資料 {‘err_no’: 0, ‘err_str’: ‘OK’, ‘pic_id’: ‘6032817371507400001’, ‘pic_str’: ‘107,92’, ‘md5’:‘2797d0254014d9a136cabf4888fdf380’} 我們要提交的引數就是pic_str 取它的值就OK 座標多的情況下,每個座標之間是用 | 隔開的我們replace為逗號即可。
-
不羅嗦 直接上程式碼
# -*- coding: utf-8 -*-
import json
import re
import time
import requests
import logging
logging.captureWarnings(True)
#my_txt我的賬號密碼等資訊檔案
from ticket_12306.my_txt import *
from urllib.parse import unquote
#驗證碼平臺檔案
from chaojiying.chaojiying_Python.chaojiying import Chaojiying_Client
class order_ticket_12306:
def __init__(self):
#建立session會話
self.sess = requests.Session()
#跳過ssl驗證
self.sess.verify = False
#驗證碼圖片地址
self.captcha_url = 'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand'
#驗證碼圖片儲存路徑
self.captcha_file_path = 'captcha.jpg'
#打碼平臺
self.chaojiying = Chaojiying_Client(chaojiying_user, chaojiying_passwd, '96001')
def captcha_download(self):
'''
下載驗證碼圖片
:return:
'''
with open(self.captcha_file_path, 'wb') as f:
image = self.sess.get(self.captcha_url)
if image.status_code == 200:
f.write(image.content)
else:
print('驗證碼下載失敗, 正在重試...')
self.captcha_download()
def get_captcha(self):
'''
提交圖片到打碼平臺,獲取座標
:return:
'''
self.captcha_download()
im = open(self.captcha_file_path, 'rb').read()
print('chaojiying111111111',self.chaojiying.PostPic(im, 9004))
res = self.chaojiying.PostPic(im, 9004)
return res
def captcha_check(self):
'''
提交答案,進行驗證
會返回一個json資料裡面有result_code
如果result_code==4的話為成功,否則進行重新驗證
:return:
'''
captcha_res = self.get_captcha()
captcha_code = captcha_res.get('pic_str').replace('|', ',')
check_data = {
'answer': captcha_code,
'login_site': 'E',
'rand': 'sjrand',
}
check_url = 'https://kyfw.12306.cn/passport/captcha/captcha-check'
res = self.sess.post(check_url, data=check_data).text
print(res)
check_result = str(json.loads(res).get('result_code'))
print(check_result)
if check_result!='4':
print('驗證碼校驗失敗, 正在重試...')
try:
print('驗證碼驗證報錯....')
pic_id = captcha_res.get('pic_id')
#報錯到打碼平臺
self.chaojiying.ReportError(pic_id)
except:
print('驗證碼驗證報錯失敗...')
self.captcha_check()
print(11111, res)
def login(self):
'''
12306登陸
:return:
'''
login_headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
login_data = {
'username': user_12306,
'password': passwd_12306,
'appid': 'otn'
}
login_url = 'https://kyfw.12306.cn/passport/web/login'
res = self.sess.post(login_url, data=login_data, headers = login_headers).text
print(22222, res)
return res
- OK我們再來登陸一次
- 登陸成功…
#總結:
-
12306更新的頻率很快,動不動就改動一些地方,其實這個12306我2個禮拜前寫過一次,今天執行時候就各種報錯,重新抓包對比了一下,發現所有的URL全都修改了!!!=– 所以 我這程式碼可能過段時間就又用不了了 ,主要過程。
-
最後,登陸後購票的部分,會寫到下篇文章,《Python-requests-12306-購票》