12306购票处理验证码并完成登陆

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了12306购票处理验证码并完成登陆相关的知识,希望对你有一定的参考价值。

学习目标:

  1. 了解 使用打码平台处理验证图片
  2. 了解 实现12306登陆实现

1. 获取前置cookie

根据抓包过程完成前置cookie的获取;使用requests.session()自动处理cookie;注意Referer

# 12306.funk12306

class Funk12306():
    def __init__(self, username, password):
        self.username = username
        self.password = password
        self.s = requests.session()
        self.s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/67.0.3396.87 Safari/537.36'

    def get_cookies(self):
        print('获取登录前的cookies')

        """以上都为获取cookies"""

        url = 'https://www.12306.cn/index/'
        self.s.get(url)

        url = 'https://kyfw.12306.cn/otn/login/conf'
        self.s.headers['Referer'] = 'https://kyfw.12306.cn/otn/resources/login.html'
        self.s.post(url)

        url = 'https://kyfw.12306.cn/otn/index12306/getLoginBanner'
        resp = self.s.get(url)
        print(resp.text)

        # 检查用户是否登录
        url = 'https://kyfw.12306.cn/passport/web/auth/uamtk-static'
        resp = self.s.post(url, data={'appid': 'otn'})
        print(resp.text)

        # 获取登录二维码
        url = 'https://kyfw.12306.cn/passport/web/create-qr64'
        resp = self.s.post(url, data={'appid': 'otn'})
        print(resp.text)
        uuid = json.loads(resp.text)['uuid']

        # 查询二维码状态
        url = 'https://kyfw.12306.cn/passport/web/checkqr'
        resp = self.s.post(url, data={'appid': 'otn', 'uuid': uuid})
        print(resp.text)

2. 获取图片验证码并处理

  • 2.2.1 获取图片验证码
  • 2.2.2 使用打码平台处理验证图片
  • 2.2.3 添加手动处理验证图片功能

2.2.1 获取图片验证码

图片保存到本地

# 12306.funk12306.Funk12306.get_cookies
# 获取验证码图片
temp = str(time.time() * 1000)[:-5]  # 15421 76058 853
url = 'https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&_={}'.format(temp)
resp = self.s.get(url)
print(resp.text)
captcha_img_b64 = json.loads(resp.text)['image']
captcha_img = base64.b64decode(captcha_img_b64)
with open('./imgs/{}.png'.format(temp), 'wb') as f:
    f.write(captcha_img)

2.2.2 使用打码平台处理验证图片

使用 若快 打码 http://www.ruokuai.com,注册账号并充值

# 12306_92.funk12306.utils.captcha

# THE WINTER IS COMING! the old driver will be driving who was a man of the world!
# -*- coding: utf-8 -*- python 3.6.7, create time is 18-11-29 下午6:18 GMT+8

import hashlib
import requests
from datetime import datetime

RUOUSER = 'xxx'
RUOPASS = 'xxx'

# 若快 12306打码 直接传入本地文件路径
def getCode(img):
    url = "http://api.ruokuai.com/create.json"
    fileBytes = open(img, "rb").read()
    paramDict = {
        'username': RUOUSER,
        'password': RUOPASS,
        'typeid': 6113, # 专门用来识别12306图片验证的类型id
        'timeout': 90,
        'softid': 117157, # 推广用的
        'softkey': '70acaa1e477a4374a7736264a24b974b' # 推广用的
    }
    paramKeys = ['username',
                 'password',
                 'typeid',
                 'timeout',
                 'softid',
                 'softkey'
                 ]
    result = http_upload_image(url, paramKeys, paramDict, fileBytes)
    return result['Result']


# 若快12306打码 上传图片
def http_upload_image(url, paramKeys, paramDict, filebytes):
    timestr = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    boundary = '------------' + hashlib.md5(timestr.encode("utf8")).hexdigest().lower()
    boundarystr = '\\r\\n--%s\\r\\n' % (boundary)

    bs = b''
    for key in paramKeys:
        bs = bs + boundarystr.encode('ascii')
        param = "Content-Disposition: form-data; name=\\"%s\\"\\r\\n\\r\\n%s" % (key, paramDict[key])
        # print param
        bs = bs + param.encode('utf8')
    bs = bs + boundarystr.encode('ascii')

    header = 'Content-Disposition: form-data; name=\\"image\\"; filename=\\"%s\\"\\r\\nContent-Type: image/gif\\r\\n\\r\\n' % ('sample')
    bs = bs + header.encode('utf8')

    bs = bs + filebytes
    tailer = '\\r\\n--%s--\\r\\n' % (boundary)
    bs = bs + tailer.encode('ascii')

    headers = {'Content-Type': 'multipart/form-data; boundary=%s' % boundary,
               'Connection': 'Keep-Alive',
               'Expect': '100-continue',
               }
    response = requests.post(url, params='', data=bs, headers=headers)
    return response.json()


if __name__ == '__main__':
    # 测试
    ret = getCode('../imgs/1544627949970.png')
    print(ret)

2.3 添加手动处理验证图片功能

用截图工具量取图片坐标(范围或单一坐标)

# 12306.funk12306.Funk12306.get_cookies       
        
        # 选择打码方式并获取结果
        create_type = input(' 1 为手动打码 or 2 为收费平台自动打码,请选择:')
        if create_type == '1': # 手动打码
            answer_num = input('输入图片编号,从1开始:')
        elif create_type == '2': # 接入打码平台
            answer_num = getCode('./imgs/{}.png'.format(temp))  # 23
        else:
            raise Exception('输入错误! 1 为手动打码 or 2 为收费平台自动打码')

        # 改图片名字并获取点击坐标
        answer_dict = { '1': '37,46,',
                        '2': '110,46,',
                        '3': '181,46,',
                        '4': '253,46,',
                        '5': '37,116,',
                        '6': '110,116,',
                        '7': '181,116,',
                        '8': '253,116,' }
        os.rename('./imgs/{}.png'.format(temp),
                  './imgs/{}_{}.png'.format(temp, answer_num))
        answer = ''
        for i in answer_num:
            answer += answer_dict[i]
        answer = answer[:-1]
        print(answer)
        
        # 验证图片验证码
        url = 'https://kyfw.12306.cn/passport/captcha/captcha-check?answer={}&rand=sjrand&login_site=E&_={}'.format(
            answer, str(time.time() * 1000)[:-4])
        resp = self.s.get(url)
        print(json.loads(resp.text))

3. 完成登陆

注意其中的跳转

# 12306.funk12306.Funk12306.get_cookies  

        # 登录
        url = 'https://kyfw.12306.cn/passport/web/login'
        data = {'username': self.username,
                'password': self.password,
                'appid': 'otn',
                'answer': answer}
        resp = self.s.post(url, data=data)
        print(resp.text)
        uamtk = json.loads(resp.text)['uamtk']

        # 进入登录后的页面 发生302跳转
        url = 'https://kyfw.12306.cn/otn/login/userLogin' # 302跳转
        self.s.get(url)
        url = 'https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin'
        self.s.get(url)

        # 获取newapptk
        url = 'https://kyfw.12306.cn/passport/web/auth/uamtk'
        self.s.headers['Referer'] = 'https://kyfw.12306.cn/otn/passport?redirect=/otn/login/userLogin'
        resp = self.s.post(url, data={'appid': 'otn'})
        print(json.loads(resp.text))
        newapptk = json.loads(resp.text)['newapptk']

        # 登录后验证
        url = 'https://kyfw.12306.cn/otn/uamauthclient'
        resp = self.s.post(url, data={'tk': newapptk})
        print(json.loads(resp.text))

4. 运行测试效果


小结

  1. 了解 使用打码平台处理验证图片
  2. 了解 实现12306登陆实现

以上是关于12306购票处理验证码并完成登陆的主要内容,如果未能解决你的问题,请参考以下文章

假如12306的验证码要你辨认自行车

12306已用验证码打败了全国99%用户!内心几乎崩溃!

网络爬虫之12306-验证码验证

使用深度学习模型识别12306图片验证码

12306购票构造时间参数以及下单购票

12306怎么在线选座位 12306动车购票在线选座位的方法