12306自动刷票下单-登录篇

12306网站推出图片验证码以后,对于抢票软件就提出了更高的要求,本篇并不涉及自动识别验证码登录(主要是博主能力所限),提供一个途径-打码平台,这个几乎是可以破解所有验证码了,本篇主要是分享一下12306网站登录的流程的学习,勿吐槽,有问题请指正,博主也是刚开始接触爬虫,大家共勉共勉。

废话不多说了,直接干吧

这里写图片描述

首先打开12306登录页面https://kyfw.12306.cn/otn/login/init

这里写图片描述

输入账号密码直接登录,会转入到下面的页面https://kyfw.12306.cn/otn/index/initMy12306

这里写图片描述

红线划掉的就是用户名,那么我们最终就是要访问这个网页查找到我们的用户名,简单吧

这里写图片描述

好了,不闹了,看一下我们整个登录过程中的请求吧

这里写图片描述

这里缺少了打开登录页面的请求,如果你没有发现,那我刚说了你就应该发现,这个登录页面是必须的,这里说一下我的理解,登录过程中我们是要发送验证码的,验证码作为独立的请求发送,那么服务器是要知道这个验证码是由张三发过来的还是由李四发过来的,所以当我们打开登录页面的时候,服务器会记录session或者cookie,我们之后的请求都通过携带cookie让服务器知道是我张三发送的请求,而不是李四。大概就是这么回事,可能说的不太对,我也就理解了这么点,见谅见谅。

这里我们使用requests库,不要太方便

import requests# 一个提供UserAgent的库,不用自己再去搞那么多了,方便from fake_useragent import UserAgent# 禁用安全请求警告from urllib3 import disable_warningsfrom urllib3.exceptions import InsecureRequestWarning
disable_warnings(InsecureRequestWarning)

session = requests.session()# 设置不验证SSL,你应该看到了HTTPSsession.verify = Falseua = UserAgent(verify_ssl=False)# 请求头,最最基础的反爬伪装headers = {    "User-Agent": ua.random,    "Host":"kyfw.12306.cn",    "Referer":"https://kyfw.12306.cn/otn/passport?redirect=/otn/"}# 打开登录页面url = "https://kyfw.12306.cn/otn/login/init"session.get(url, headers=headers)

requests库的session会为我们保存cookie信息,只要我们继续使用session请求即可。

这里要先解释一下,我使用的是Chrome浏览器,但是很多请求里面确看不到response数据,真的很操蛋,我写的时候每一个请求都用代码打印出来,很痛苦,因为想写篇博客,要给大家截图,所有装了个虚拟机Windows xp,安装了Fiddler才看到一些信息,我还是习惯用Chrome,我尽量按照Chrome的方式去说明。

这里写图片描述

在所有的请求里面,我们主要关注Type等于document和xhr的请求,按照从上到下的方式就是整个流程中请求的先后顺序。我们可以看到init后面uamtk和captcha_js.js?_=1510993251087,

这里写图片描述

很明显这个是我们打开登录页面时发送的请求,服务端告诉我们:你还没登录呢,废话我只是打开登录界面,当然没登录了。不过我们大概知道了,发送https://kyfw.12306.cn/passport/web/auth/uamtk这个请求,服务器会给我们反馈一些登录信息。后面那个请求很明显是js,我们暂时不用管。

下面是这个xhr请求:https://kyfw.12306.cn/passport/captcha/captcha-check

这里写图片描述

这个是发送验证码的请求,12306的验证码属于坐标型验证码,所有我们看到发送的是一段坐标,在这个请求上面我们看到https://kyfw.12306.cn/passport/captcha/captcha-image?login_site=E&module=login&rand=sjrand&0.9919795512111436

这里写图片描述

哦,这个是请求验证码的,要发送验证码请求,自然要先获取验证码喽,多请求几次发现表单里除了最后一个随机数以外,其他的数据没有变化。接下来就是验证码的坐标了

这里写图片描述

首先是找原点坐标,这个跟正常登录发送的坐标对比一下,大概就能确定,然后是确定坐标的拼接,x1,y1还是y1,x1,这个也是和正常登录发送的坐标大概对比一下就能确定了,我这里只说大概原理,具体情况自己去尝试一下。下面上代码

验证码函数

def captcha():
    # 请求数据是不变的,随机数可以使用random.random()
    data = {        "login_site": "E",        "module": "login",        "rand": "sjrand",        "0.17231872703389062":""
    }    # 获取验证码
    param = parse.urlencode(data)
    url = "https://kyfw.12306.cn/passport/captcha/captcha-image?{}".format(param)
    response = session.get(url, headers=headers)    if response.status_code == 200:        # 获取验证码并打开,然后...手动找一下坐标吧,我开始就说了不涉及自动识别验证码的
        file = BytesIO(response.content)
        img = Image.open(file)
        img.show()

    positions = input("请输入验证码: ")    # 发送验证码
    data = {        "answer": positions,        "login_site": "E",        "rand": "sjrand"
    }

    url = "https://kyfw.12306.cn/passport/captcha/captcha-check"
    response = session.post(url, headers=headers, data=data)    if response.status_code == 200:
        result = json.loads(response.text)
        print(result.get("result_message"))        # 请求成功以后返回的code是4,这个看请求信息就知道了
        return True if result.get("result_code") == "4" else False
    return False

验证码通过以后,就要发送账号登录了,继续看下面的请求 https://kyfw.12306.cn/passport/web/login

这里写图片描述

账号密码登录成功,看到没?好了

这里写图片描述

还没完呢,为啥捏?还没看到initMy12306这个请求呢 继续往下撸吧,https://kyfw.12306.cn/passport/web/auth/uamtk,这个请求熟悉不?不熟悉的去翻前面

这里写图片描述

对比一下,前后不一样吧,验证通过,开心吧,哈哈! 咦!好像还多了点东西哦,newapptk什么鬼呢?不明白,继续看下面 敲黑板!!!是看后面的请求,你在看哪个下面,睡着了吗? https://kyfw.12306.cn/otn/uamauthclient

这里写图片描述

验证通过,不过重点我都圈起来了,还看不见吗?tk,你再看看上面newapptk,明白了吗?上面的请求服务器返回了newapptk数据,我们通过下面的请求把这个值赋给tk,再发送给服务器,然后服务器告诉我们验证通过,apptk和前面的tk一样,有什么用呢?不知道,那就往下看,哎呀,到站了 https://kyfw.12306.cn/otn/index/initMy12306

这里写图片描述

已经成功了,有我们的账号名了,就是红点的地方,我当然不会给你看我的账号名了,到这里就真的完了,apptk没用到?没用就没用呗,终于结束了

这里写图片描述

我还要贴一下代码,差点忘了

完整的代码

# -*- coding: utf-8 -*-import jsonfrom urllib import parsefrom io import BytesIOfrom config import *import requestsfrom PIL import Imagefrom fake_useragent import UserAgent# 禁用安全请求警告from urllib3 import disable_warningsfrom urllib3.exceptions import InsecureRequestWarning
disable_warnings(InsecureRequestWarning)

session = requests.session()
session.verify = Falseua = UserAgent(verify_ssl=False)
headers = {    "User-Agent": ua.random,    "Host":"kyfw.12306.cn",    "Referer":"https://kyfw.12306.cn/otn/passport?redirect=/otn/"}def login():
    # 打开登录页面
    url = "https://kyfw.12306.cn/otn/login/init"
    session.get(url, headers=headers)    # 发送验证码
    if not captcha():        return False

    # 发送登录信息
    data = {        "username":USER_NAME,        "password":PASSWORD,        "appid":"otn"
    }
    url = "https://kyfw.12306.cn/passport/web/login"
    response = session.post(url, headers=headers, data=data)    if response.status_code == 200:
        result = json.loads(response.text)
        print(result.get("result_message"), result.get("result_code"))        if result.get("result_code") != 0:            return False

    data = {        "appid":"otn"
    }
    url = "https://kyfw.12306.cn/passport/web/auth/uamtk"
    response = session.post(url, headers=headers, data=data)    if response.status_code == 200:
        result = json.loads(response.text)
        print(result.get("result_message"))
        newapptk = result.get("newapptk")

    data = {        "tk":newapptk
    }
    url = "https://kyfw.12306.cn/otn/uamauthclient"
    response = session.post(url, headers=headers, data=data)    if response.status_code == 200:
        print(response.text)

    url = "https://kyfw.12306.cn/otn/index/initMy12306"
    response = session.get(url, headers=headers)    if response.status_code == 200 and response.text.find("用户名") != -1:        return True
    return Falsedef captcha():
    data = {        "login_site": "E",        "module": "login",        "rand": "sjrand",        "0.17231872703389062":""
    }    # 获取验证码
    param = parse.urlencode(data)
    url = "https://kyfw.12306.cn/passport/captcha/captcha-image?{}".format(param)
    response = session.get(url, headers=headers)    if response.status_code == 200:
        file = BytesIO(response.content)
        img = Image.open(file)
        img.show()

    positions = input("请输入验证码: ")    # 发送验证码
    data = {        "answer": positions,        "login_site": "E",        "rand": "sjrand"
    }

    url = "https://kyfw.12306.cn/passport/captcha/captcha-check"
    response = session.post(url, headers=headers, data=data)    if response.status_code == 200:
        result = json.loads(response.text)
        print(result.get("result_message"))        return True if result.get("result_code") == "4" else False
    return Falseif __name__ == "__main__":    if login():
        print("Success")    else:
        print("Failed")

执行结果添一下,好累,我要去吃饭了

原文发布于微信公众号 - python爬虫实战之路(gh_f26a568fdea8)

原文发表时间:2018-05-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的django

Django REST framework+Vue 打造生鲜超市(六) 七、用户登录与手机注册

七、用户登录与手机注册 7.1.drf的token (1)INSTALL_APP中添加 INSTALLED_APPS = ( ... 'rest...

2.9K80
来自专栏惨绿少年

ssh密钥创建分发(端口号非22)&脚本实现自动创建分发密钥

1.1 服务端端口号变化了,如何基于秘钥连接 1.1.1 环境准备 实验环境: [root@test ~]# cat /etc/redhat-release C...

32300
来自专栏Python中文社区

使用python实现后台系统的JWT认证

專 欄 ❈ 茶客furu声,Python中文社区专栏作者 博客: http://www.jianshu.com/p/537b356d34c9 ❈ ...

96450
来自专栏cloudskyme

跟我一起云计算(4)——lucene

了解lucene的基本概念 这一部分可以参考我以前写的博客: http://www.cnblogs.com/skyme/tag/lucene/ lucene是什...

34960
来自专栏小樱的经验随笔

利用 John the Ripper 破解用户登录密码

看到这个标题,想必大家都很好奇,John the Ripper 是个什么东西呢?如果直译其名字的话就是: John 的撕裂者(工具)。 相比大家都会觉得摸不着头...

38420
来自专栏小狼的世界

SMTP的相关命令

邮件的发送,主要是通过SMTP协议来实现的。SMTP协议最早在RFC 821(1982年)中定义,最后更新是在RFC 5321(2008年)中,更新中包含了扩展...

21720
来自专栏程序员宝库

基于 Token 的 WEB 后台认证机制

作者:红心李(https://home.cnblogs.com/u/xiekeli/) 链接:http://www.cnblogs.com/xiekeli/p...

808100
来自专栏Kubernetes

聊聊你可能误解的Kubernetes Deployment滚动更新机制

Author: xidianwangtao@gmail.com 定义Deployment时与rolling update的相关项 以下面的frontend...

52480
来自专栏Kubernetes

原 荐 从一次集群雪崩看Kubelet资源预

Author: xidianwangtao@gmail.com Kubelet Node Allocatable Kubelet Node Allocat...

766100
来自专栏青蛙要fly的专栏

Android技能树 — 网络小结(3)之HTTP/HTTPS

介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看,最好可以指出我的错误,让我也能纠正。

10930

扫码关注云+社区

领取腾讯云代金券