PyQt5+网络爬虫----打造自己的12306抢票软件

本文介绍了如何使用Python的PyQt5库和网络爬虫技术,模拟12306的购票流程,包括登录、查询余票和订票。通过Chrome浏览器和Charles抓包工具分析12306的网络请求,详细阐述了每个步骤的关键操作。强调理解原理的重要性,以应对12306网址的动态变化。
摘要由CSDN通过智能技术生成

郑重申明:该文章介绍的技术仅供用于学习,不可恶意攻击12306网站。对12306服务器造成的任何损失,后果自负。

导语:由于12306服务器访问量巨大,并且官方为防止黄牛恶意刷票、以及一些非法攻击。12306各模块的 Url地址可能随时会改变。我在看各位前辈代码的时候很多代码已经不合适在现在的时间。所以,重在原理的学习,掌握了原理,不管12306的相关url变成什么样,都可以以不变应万变。

本文将使用以下工具来分析12306购票的过程,然后使用python语言,使用PyQt5实现购票界面的搭建,最终购票。
软件购票视频:

12306.mp4

1、Chrome浏览器(其他的浏览器也可以,都有类似的界面,如Chrome,装了httpwatch的IE浏览器等)+ charles(个人很喜欢)
2、一个可以登录12306网址并且可以购票的12306账号
3. Pycharm

其实在12306软件的实现过程中,我个人认为一般是分为以下三个步骤的:
1。个人账户的登录及授权
2。火车票的余票查询
3。火车票购买

一、个人账户的登录及授权
1.我们首先打开如下地址,进入个人账户的登录界面。网址:https://kyfw.12306.cn/otn/login/init。界面如下图所示
在这里插入图片描述
2.我们需要打开谷歌浏览器自带的抓包来对我们请求的各种数据进行获取并分析。(做法:在页面中右键菜单中选择【检查】菜单,打开后,选择【网络】选项卡。如下图所示:)
在这里插入图片描述
在这里插入图片描述打开后页面变成二分窗口了,左侧是正常的网页页面,右侧是浏览器自带的控制台,当我们在左侧页面中进行操作后,右侧会显示我们浏览器发送的各种http请求和应答。我们在登录界面输入我们需要登录的个人账号(请注意:我们在点击登录以前要先勾选掉Preserve log,便于我们进行URL的分析)
在这里插入图片描述
在我们点击登录后我们回看到出现很多小条目,其实这就是我们在这一过程中发送的各个网络请求。当我们能够拿到我们的个人信息的时候,就表明登录这一块我们已经完全实现了,但是我们使用爬虫的时候需要经历哪些步骤呢?这里就需要引出我用到的charles抓包软件,个人觉得它能够对以上步骤进行层级划分。

在这里插入图片描述
在这里插入图片描述
1.1 获取验证码并进行验证
我们怎么获取验证码呢? 其实我们在进入网站的时候,验证码已经自动进行加载了,你想知道获取验证码的地址只需要进行刷新一下登录界面即可。通过Charles抓包我们能够获得以下界面。
在这里插入图片描述
得到验证码以后,我们就需要将验证码的答案传递给12306的服务器进行检测。(12306怎么知道我们传递的图片是不是正确的呢?–这里就是cookie sessionde原理了,后面讲)检查的地址:https://kyfw.12306.cn/passport/captcha/captcha-check
在这里插入图片描述
上图的四个数值是什么意思呢? 其实这里是你所选择的答案在验证码图片上的坐标位置(x,y)
在这里插入图片描述

我在UI上的设计思路:创建一个标签用于显示验证码,当我鼠标在我的答案上点击时,产生一个原点,并获取原点的坐标。


```python
from PyQt5.Qt import *

class HfLabel(QLabel):
    def clear_points(self):
        '''
        作用:清除验证码标签上的点
        :return: 
        '''
        [child.deleteLater() for child in self.children() if child.inherits("QPushButton")]



    def get_result(self):
        '''
        获取按钮的坐标点
        :return: 
        '''
        result = ",".join(["{},{}".format(child.x()+10,child.y()-20) for child in self.children() if child.inherits("QPushButton")]) # 搞清楚为什么这里要分别减10 和20 是由于控件的位置坐标来决定的
        # result =",".join(["{},{}".format(btn.x() + 15, btn.y() - 15) for btn in self.children() if btn.inherits("QPushButton")])  # 搞清楚为什么这里要分别减10 和20 是由于控件的位置坐标来决定的
        return result

    def mousePressEvent(self,evt):
        super(HfLabel, self).mousePressEvent(evt)
        if evt.x()<0 and evt.y()<=30:
            return None
        point_btn = QPushButton(self)
        point_btn.setStyleSheet("background-image:../Images/yzm_label.png")
        point_btn.resize(20,20)
        point_btn.move(evt.pos()-QPoint(10,10))
        point_btn.show()
        point_btn.clicked.connect(lambda x,Btn=point_btn:Btn.deleteLater())  # 双击取消

1.2 登录账号

当我们解决验证码的获取以及验证以后,我们应该获取输入的账号和密码,并发送至12306服务器进行验证。
验证地址:https://kyfw.12306.cn/passport/web/login![
有朋友看到 登录成功以为就结束,其实到这一步还是不能哪去到自己的用户信息,我们还需要进行授权有效。

授权网址:https://kyfw.12306.cn/passport/web/auth/uamtk
传递的参数:
在这里插入图片描述

在这里插入图片描述
上面提到的utmark在我们授权这里会用到,我们请求头的cookies中除开有 utmark以外还有上面验证码的cookies信息(这是12306向比以前改进的地方) 如果只是单纯的使用request中的session对象是不能够完成的。所以在这里我取出其中需要的信息,自己传递cookies.

def Authorclient(self):
    # 先向 Uamtk 请求最新的数据
    headers = {
   
        "User-Agent": "Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko) Chrome/80.0.3987.122Safari/537.36",
        "Connection": "keep-alive",
        "Content-Length": "60",
        "Accept": "application/json,text/javascript,*/*;q=0.01",
        "Sec-Fetch-Dest": "empty",
        "X-Requested-With": "XMLHttpRequest",
        "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
        "Origin": "https://kyfw.12306.cn",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-Mode": "cors",
        "Referer": "https://kyfw.12306.cn/otn/login/init",
        "Accept-Encoding": "gzip,deflate,br",
        "Accept-Language": "zh-CN,zh;q=0.9",
    }
    cookies = {
   
        "Cookie": "{};{};jc_save_wfdc_flag=dc;"
                  "RAIL_DEVICEID=FYQF27FM-hDGTl8bZAdL0k1DC6z4E7IgqIB6drUkWbGpOzzR3ROgaoV2_QutZUcPDywhQJE7klUQNBMZjX_EjszINQsMa0ftgfA1O2jxWVEjRjZDm4lovBeZj4A-7b2R5jy3DOtkN5uC5s_SnOcK4GG7FVWgYfAa;"
                  "RAIL_EXPIRATION=1585143263381;_jc_save_fromStation=%u5317%u4EAC%2CBJP;_jc_save_showIns=true;"
                  "route=495c805987d0f5c8c84b14f60212447d;BIGipServerotn=535298314.24610.0000;"
                  "BIGipServerpassport=971505930.50215.0000".format(self.Author_list[0], self.Author_list[1])
    }
    data = {
   
        "appid": "otn"
    }
    new_tk_resp = self.session.post(API_URL.Uamtk_URL, data=data,headers = headers,cookies = cookies,verify = False)
    tk = new_tk_resp.json()["newapptk"]

    # 拿到 tk 以后再向另一个网站请求数据
    # res2 = requests.request(method="POST",url=API_URL.Uamauthliect_URL, data={"tk":tk},headers = headers,verify = False)
    res2 = self.session.post(url=API_URL.Uamauthliect_URL
  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值