12306登录模块分析

记录一下学习的内容。今天先记录登录模块的分析和实现。

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

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

  1. 安装requests库
  2. pip3 install requests
  3. 基本思路
  4. 首先,我们可以使用谷歌浏览器的开发者模式,F12,来先分析一波登录12306的过程。(推荐大家一个好用的抓包工具Burp Suite
  5. 打开登录界面,https://kyfw.12306.cn/otn/login/init
  6. 先随意输入一个账号密码,再随意选验证码。(我们可以百度验证码类型,也可以自己尝试,可以知道12306的验证码是坐标型的验证码。)点击登录可以发现Network中多出一个xhr,点击查看(Headers  Preview  Response  Cookies  Timing都看看)可以发现Response返回的是:
  7. {"result_message":"验证码校验失败","result_code":"5"}
  8. 再查看请求url   https://kyfw.12306.cn/passport/captcha/captcha-check   post数据为:
  • answer: 91,53,107,109     <span style="color:#ff0000;">为验证码坐标</span>  
  • login_site: E     <span style="color:#ff0000;"> 固定值</span>  
  • rand: sjrand       <span style="color:#ff0000;">固定值</span> 
  • 可以使用qq截图的坐标来输入,从红色箭头开始向正确验证码拉动。
  • 输入正确的验证码后,查看Response为:
  • {"result_message":"验证码校验成功","result_code":"4"}
  • 多处一个login的xhr,URL为  https://kyfw.12306.cn/passport/web/login Response为:
  • {"result_message":"密码输入错误。如果输错次数超过4次,用户将被锁定。","result_code":1}
  • 说明验证码验证通过,现在是账号密码问题,那么我们输入自己的正确的账号密码就可以完成登录了呗。

  1. import requests
  2. from json import loads
  3. from user import username,password      #user.py   里面是自己正确的账号密码
  4. from urllib3 import disable_warnings
  5. from urllib3.exceptions import InsecureRequestWarning
  6. disable_warnings(InsecureRequestWarning)        #这三行作用是取消https警告
  7. locate={
  8.     '1':'44,44,',
  9.     '2':'114,44,',
  10.     '3':'185,44,',
  11.     '4':'254,44,',
  12.     '5':'44,124,',                #8个图的坐标代号
  13.     '6':'114,124,',
  14.     '7':'185,124,',
  15.     '8':'254,124,',
  16. }
  17. head={
  18. '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',
  19.     'Referer''https://kyfw.12306.cn/otn/login/init',
  20. }                                         #加header 
  21. session=requests.Session()            #定义session,保持一个会话,验证码post和用户post保持同一个会话,之后的下单跨域保持登录
  22. session.verify=False                #取消验证SSL
  23. def login():
  24.     resp1 = session.get(
  25.             'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&',
  26.             headers=head)
  27.     with open('code.png','wb') as f:
  28.         f.write(resp1.content)
  29.     print('请输入验证码坐标代号:')
  30.     code=input()
  31.     write=code.split(',')
  32.     codes=''
  33.     for i in write:
  34.         codes+=locate[i]
  35.     data={
  36.     'answer': codes,
  37.     'login_site''E',
  38.     'rand''sjrand'
  39.     }
  40.     resp=session.post('https://kyfw.12306.cn/passport/captcha/captcha-check',headers=head,data=data)
  41.     html=loads(resp.content)
  42.     if html['result_code']=='4':
  43.         print('验证码校验成功!')
  44.         login_url='https://kyfw.12306.cn/passport/web/login'
  45.         user={
  46.             'username': username,
  47.             'password': password,
  48.             'appid''otn'
  49.         }
  50.         resp2=session.post(login_url,headers=head,data=user)
  51.         html=loads(resp2.content)
  52.         print(resp2.text)
  53.         if html['result_code'] == 0:
  54.             print('登陆成功!')
  55.         else:
  56.                 print('登陆失败!')
  57.     else:
  58.         print('验证码校验失败,正在重新请求页面...')
  59.         login()
  60.     pass
  61. login()
  62. 到这里如果只是验证登录的话已经完成,要实现下单的话还没完,因为虽然显示登录成功,但是使用Fiddler抓包可以看到,在完成上述的登录后还需要进行两次验证,才能保证session验证登录成功,保持登录,之后下单过程才不会出错。两次验证URL分别为:
    https://kyfw.12306.cn/passport/web/auth/uamtk   post参数为 appid :otn
    https://kyfw.12306.cn/otn/uamauthclient    post参数为 第一次验证的Response的tk值

    session保持登录代码:


    1. import requests
    2. from json import loads
    3. from user import username,password
    4. from urllib3 import disable_warnings
    5. from urllib3.exceptions import InsecureRequestWarning
    6. disable_warnings(InsecureRequestWarning)
    7. locate={
    8.     '1':'44,44,',
    9.     '2':'114,44,',
    10.     '3':'185,44,',
    11.     '4':'254,44,',
    12.     '5':'44,124,',
    13.     '6':'114,124,',
    14.     '7':'185,124,',
    15.     '8':'254,124,',
    16. }
    17. head={
    18. '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'
    19. }
    20. now_session=requests.Session()
    21. now_session.verify=False
    22. def login():
    23.     print('-----------------验证码验证-----------------')
    24.     resp1 = now_session.get(
    25.         'https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.8430851651301317',
    26.         headers=head)
    27.     with open('code.png','wb') as f:
    28.         f.write(resp1.content)
    29.     print('请输入验证码坐标代号:')
    30.     code=input()
    31.     write=code.split(',')
    32.     codes=''
    33.     for i in write:
    34.         codes+=locate[i]
    35.     data={
    36.     'answer': codes,
    37.     'login_site''E',
    38.     'rand''sjrand'
    39.     }
    40.     resp=now_session.post('https://kyfw.12306.cn/passport/captcha/captcha-check',headers=head,data=data)
    41.     html=loads(resp.content)
    42.     if html['result_code']=='4':
    43.         print('验证码校验成功!')
    44.         print('-----------------登录中-----------------')
    45.         login_url='https://kyfw.12306.cn/passport/web/login'
    46.         user={
    47.             'username': username,
    48.             'password': password,
    49.             'appid''otn'
    50.         }
    51.         resp2=now_session.post(login_url,headers=head,data=user)
    52.         html=loads(resp2.content)
    53.         print(html)
    54.         if html['result_code']==0:
    55.             print('登陆成功!')
    56.             yzdata={
    57.                 'appid':'otn'
    58.             }
    59.             tk_url='https://kyfw.12306.cn/passport/web/auth/uamtk'
    60.             resp3=now_session.post(tk_url,data=yzdata,headers=head)
    61.             print('-----------------第一次验证-----------------')
    62.             print(resp3.text)
    63.             login_message=resp3.json()['newapptk']
    64.             print('loginMessage=',login_message)
    65.             yz2data={
    66.                 'tk':login_message
    67.             }
    68.             client_url='https://kyfw.12306.cn/otn/uamauthclient'
    69.             resp4=now_session.post(client_url,data=yz2data,headers=head)
    70.             print('-----------------第二次验证-----------------')
    71.             print(resp4.text)
    72.         else:
    73.             print('登陆失败!')
    74.     else:
    75.         print('验证码校验失败,正在重新请求页面...')
    76.         login()
    77.     pass
    78. login()  
    79. 备注:python2 urllib 的session由下面定义:
    80. cj = http.cookiejar.CookieJar()
    81. pro = urllib.request.HTTPCookieProcessor(cj)
    82. opener = urllib.request.build_opener(pro)
    83. urllib.request.install_opener(opener)