• 第一篇 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_warnings
    from urllib3.exceptions import InsecureRequestWarning
    disable_warnings(InsecureRequestWarning)
    
    session = requests.session()
    # 设置不验证SSL,你应该看到了HTTPS
    session.verify = False
    
    ua = 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 json
    from urllib import parse
    from io import BytesIO
    from config import *
    
    import requests
    from PIL import Image
    from fake_useragent import UserAgent
    
    # 禁用安全请求警告
    from urllib3 import disable_warnings
    from urllib3.exceptions import InsecureRequestWarning
    disable_warnings(InsecureRequestWarning)
    
    session = requests.session()
    session.verify = False
    
    ua = 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 False
    
    def 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 False
    
    if __name__ == "__main__":
        if login():
            print("Success")
        else:
            print("Failed")
    

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

     这里写图片描述

    我讨厌写文章,真的,这是我的第一篇爬虫文章了,写代码过程用了两个小时,写文档用了整整一个下午,是的,一个下午。哎,我果然还是不擅长写文章,之前想要写python微信公众号二次开发,结果写了好几次都是开头就删掉了,文才真的很烂,而且通篇逻辑混乱,我自己都看不下去。大家凑合看吧,希望多提意见,我一定虚心接受,慢慢改正。

     这里写图片描述

  • 相关阅读:
    spring 自定义事件发布及监听(简单实例)
    解析spring中的BeanFactory(看完会有收获)
    如何提高锁的性能
    spring MVC模式拦截所有入口方法的入参出参打印
    java基于feemarker 生成word文档(超级简单)
    数据库事务特性汇总
    如何让window.open()以post请求方式调用(巧妙解法)
    a标签添加背景图片的解决办法
    深入理解Django Admin的list_display, list_filter和raw_id_fields,filter_horizontal选项
    django配置log日志
  • 原文地址:https://www.cnblogs.com/xukun588/p/9313693.html
Copyright © 2020-2023  润新知