1. 程式人生 > >Python-requests-12306-登陸

Python-requests-12306-登陸

好久沒有更新了,今天週一困得要命,更新篇文章提提神。 本來想用requests寫個12306購票,但是感覺寫起來會很長,想想還是分開寫好點 想想把12306分為2部分: 1.登陸 2.購票

  • 首先,我們先來看下12306網站 image.png

  • 問題1:網站連線不安全 可能要跳過ssl驗證 image.png

  • 問題2:登陸時的驗證碼問題

  • 然後,我們來手動真正的登陸一次12306 看看登陸時需要提交哪些data image.png 通過chrome瀏覽器抓包後能發現一共需要3個引數 1)username: 你的賬號 2)password:你的密碼 3)appid:otn

  • 但是我們沒發現任何關於驗證碼有關的引數,可見是在我們登陸之前網站就提前驗證了我們提交的驗證碼引數

  • 在login上面有個captcha_check應該就是驗證碼的驗證,我們來看下 image.png

  • 也是3個引數 1)answer:就是你登陸時選擇的答案的對應的座標 2)login_site:E 3)rand:sjrand

  • 這裡我介紹兩種方法破解這個驗證碼: A)手動輸入 B)打碼平臺:超級鷹

  • 先來說下手動輸入的這種方法,這種方法就需要我們去測試這個座標怎麼得來的。

  • 先來看下我登陸時驗證的驗證碼圖片 image.png

  • 找出圖片中的儀表盤和中國結 提交的正確座標有3個都用逗號隔開 32,42,256,46,35,122 我們來測試下看看這3個座標都是哪裡 我們以圖中箭頭標記處為起點 範圍為圖片部分 image.png

  • 分別來看下這3個座標(微信的ALT+A 或者QQ的CTRL+ALT+A截圖) 1)32,42 image.png

2)256,46 image.png

3)35,122 image.png

  • 不用說大家也都明白了,座標該怎麼得到了,而且答案也不是唯一的 按照格式提交就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我們再來登陸一次 image.png
  • 登陸成功…

#總結:

  • 12306更新的頻率很快,動不動就改動一些地方,其實這個12306我2個禮拜前寫過一次,今天執行時候就各種報錯,重新抓包對比了一下,發現所有的URL全都修改了!!!=– 所以 我這程式碼可能過段時間就又用不了了 ,主要過程。

  • 最後,登陸後購票的部分,會寫到下篇文章,《Python-requests-12306-購票》