python3 requests 实现12306购票登录模块

12306登录模块分析


第一次写文章,记录一下学习的内容。今天先记录登录模块的分析和实现。

在博客上看见一些大佬用的是splinter  webdriver写的12306购票过程。

由于我之前学习了一阵子requests库,所以以下使用python3+requests实现12306购票。(当然也可以用python2 的urllib来实现)

  • 安装requests库
pip3 install requests

  • 基本思路

首先,我们可以使用谷歌浏览器的开发者模式,F12,来先分析一波登录12306的过程。(推荐大家一个好用的抓包工具Fiddler)

  • 打开登录界面,https://kyfw.12306.cn/otn/login/init
  • 先随意输入一个账号密码,再随意选验证码。(我们可以百度验证码类型,也可以自己尝试,可以知道12306的验证码是坐标型的验证码。)点击登录可以发现Network中多出一个xhr,点击查看(Headers  Preview  Response  Cookies  Timing都看看)可以发现Response返回的是:
{"result_message":"验证码校验失败","result_code":"5"}

answer: 91,53,107,109     为验证码坐标
login_site: E      固定值
rand: sjrand       固定值

 

  • 可以使用qq截图的坐标来输入,从红色箭头开始向正确验证码拉动。
  • 输入正确的验证码后,查看Response为:
{"result_message":"验证码校验成功","result_code":"4"}

{"result_message":"密码输入错误。如果输错次数超过4次,用户将被锁定。","result_code":1}

  • 说明验证码验证通过,现在是账号密码问题,那么我们输入自己的正确的账号密码就可以完成登录了呗。

代码:

import requests
from json import loads
from user import username,password      #user.py   里面是自己正确的账号密码
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
disable_warnings(InsecureRequestWarning)        #这三行作用是取消https警告
locate={
    '1':'44,44,',
    '2':'114,44,',
    '3':'185,44,',
    '4':'254,44,',
    '5':'44,124,',                #8个图的坐标代号
    '6':'114,124,',
    '7':'185,124,',
    '8':'254,124,',
}
head={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36',
    'Referer': 'https://kyfw.12306.cn/otn/login/init',
}                                         #加header 
session=requests.Session()            #定义session,保持一个会话,验证码post和用户post保持同一个会话,之后的下单跨域保持登录
session.verify=False                #取消验证SSL
def login():
    resp1 = session.get(
            'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&',
            headers=head)
    with open('code.png','wb') as f:
        f.write(resp1.content)
    print('请输入验证码坐标代号:')
    code=input()
    write=code.split(',')
    codes=''
    for i in write:
        codes+=locate[i]
    data={
    'answer': codes,
    'login_site': 'E',
    'rand': 'sjrand'
    }
    resp=session.post('https://kyfw.12306.cn/passport/captcha/captcha-check',headers=head,data=data)
    html=loads(resp.content)


    if html['result_code']=='4':
        print('验证码校验成功!')
        login_url='https://kyfw.12306.cn/passport/web/login'
        user={
            'username': username,
            'password': password,
            'appid': 'otn'
        }
        resp2=session.post(login_url,headers=head,data=user)
        html=loads(resp2.content)
        print(resp2.text)
        if html['result_code'] == 0:
            print('登陆成功!')
        else:
                print('登陆失败!')
    else:


        print('验证码校验失败,正在重新请求页面...')
        login()
    pass
login()
运行截图:

到这里如果只是验证登录的话已经完成,要实现下单的话还没完,因为虽然显示登录成功,但是使用Fiddler抓包可以看到,在完成上述的登录后还需要进行两次验证,才能保证session验证登录成功,保持登录,之后下单过程才不会出错。

两次验证URL分别为:

https://kyfw.12306.cn/passport/web/auth/uamtk   post参数为 appid :otn

https://kyfw.12306.cn/otn/uamauthclient    post参数为 第一次验证的Response的tk值

session保持登录代码:

import requests
from json import loads
from user import username,password
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
disable_warnings(InsecureRequestWarning)
locate={
    '1':'44,44,',
    '2':'114,44,',
    '3':'185,44,',
    '4':'254,44,',
    '5':'44,124,',
    '6':'114,124,',
    '7':'185,124,',
    '8':'254,124,',
}
head={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36'
}
now_session=requests.Session()
now_session.verify=False
def login():
    print('-----------------验证码验证-----------------')
    resp1 = now_session.get(
        'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.8430851651301317',
        headers=head)
    with open('code.png','wb') as f:
        f.write(resp1.content)
    print('请输入验证码坐标代号:')
    code=input()
    write=code.split(',')
    codes=''
    for i in write:
        codes+=locate[i]
    data={
    'answer': codes,
    'login_site': 'E',
    'rand': 'sjrand'
    }
    resp=now_session.post('https://kyfw.12306.cn/passport/captcha/captcha-check',headers=head,data=data)
    html=loads(resp.content)
    if html['result_code']=='4':
        print('验证码校验成功!')
        print('-----------------登录中-----------------')
        login_url='https://kyfw.12306.cn/passport/web/login'
        user={
            'username': username,
            'password': password,
            'appid': 'otn'
        }
        resp2=now_session.post(login_url,headers=head,data=user)
        html=loads(resp2.content)
        print(html)
        if html['result_code']==0:
            print('登陆成功!')
            yzdata={
                'appid':'otn'
            }
            tk_url='https://kyfw.12306.cn/passport/web/auth/uamtk'
            resp3=now_session.post(tk_url,data=yzdata,headers=head)
            print('-----------------第一次验证-----------------')
            print(resp3.text)
            login_message=resp3.json()['newapptk']
            print('loginMessage=',login_message)
            yz2data={
                'tk':login_message
            }
            client_url='https://kyfw.12306.cn/otn/uamauthclient'
            resp4=now_session.post(client_url,data=yz2data,headers=head)
            print('-----------------第二次验证-----------------')
            print(resp4.text)
        else:
            print('登陆失败!')
    else:
        print('验证码校验失败,正在重新请求页面...')
        login()
    pass
login()

运行效果:


备注:

python2 urllib 的session由下面定义:

cj = http.cookiejar.CookieJar()
pro = urllib.request.HTTPCookieProcessor(cj)
opener = urllib.request.build_opener(pro)
urllib.request.install_opener(opener)

写的很烂(见谅),有问题大家可以一起讨论。

猜你喜欢

转载自blog.csdn.net/nonoroya_zoro/article/details/80030284