车票信息的请求与显示

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm=1001.2014.3001.5501

1  发送与分析车票信息的查询请求

得到了获取车票信息的网络请求地址,然后又分析出请求地址的必要参数以及车站名称转换的文件,接下来就需要将主窗体中输入的出发地、目的地以及出发日期三个重要的参数配置到查票的请求地址中,然后分析并接收所查询车票的对应信息。具体步骤如下:

1)在浏览器中打开如下图所示的查询请求地址。

然后在浏览器中将以json的方式返回车票的查询信息,如图33所示。

图33  返回加密的车票信息

说明:在看到的加密信息后先分析数据中是否含有可用的信息,例如,网页中的预订、时间、车次,在图33中的加密信息中含有G13的字样和时间信息。然后对照浏览器中余票查询的页面,查找对应车次信息如图34所示,此时可以判断返回的json信息确实含有可用数据。

图34  对照可用数据

2)发现可用数据后,在项目中创建query_request.py文件,在该文件中首先导入get_stations文件下的所有方法,然后分别创建名称为data与type_data的列表(list)分别用于保存整理好的车次信息与分类后的车次信息。代码如下:

from get_stations import *

from fake_useragent import UserAgent  # 导入伪造头部信息的模块

'''5-7 目的地 3  车次 6  出发地 8  出发时间 9  到达时间 10 历时 26 无坐 29 硬座

   24 软座 28 硬卧 33 动卧 23 软卧 21 高级软卧 30 二等座 31 一等座 32 商务座特等座

'''

data = []  # 用于保存整理好的车次信息

type_data = []  # 保存车次分类后最后的数据

headers = {"User-Agent": UserAgent().random,

           'Cookie':'JSESSIONID=752D6B778A872D3284EE86393C07462E; BIGipServerpassport=937951498.50215.0000; route=6f50b51faa11b987e576cdb301e545c4; _jc_save_fromStation=%u5317%u4EAC%2CBJP; _jc_save_toStation=%u4E0A%u6D77%2CSHH; _jc_save_wfdc_flag=dc; BIGipServerotn=854589962.50210.0000; RAIL_EXPIRATION=1572905432654; RAIL_DEVICEID=o_JxNm2gLYQelxuRwCwhWaK2j5NgJ7lQs9oqcDri2nnS7XMbHptIMfZYPJ8mfxhFfdwJYpYKU9Khja1JBqarjGT4ayRk6mzywW7NdCi3A5bLnwjUal9MUzNW-WRPO8qfAOEM4cKZDqSzdgJQ7hRhT6FWkjU4T8P-; BIGipServerpool_passport=367854090.50215.0000; _jc_save_fromDate=2019-11-01; _jc_save_toDate=2019-11-01; BIGipServerportal=3151233290.16671.0000'}  # 随机生成浏览器头部信息

说明:由于返回的加密信息很杂乱,所以需要创建“data = []”列表(list)来保存后期整理好的车次信息,然后需要将车次分类(例如,高铁、动车等),最后创建“type_data = []”列表(list)来保存分类后的车次信息。

3)创建query()方法,在调用该方法时需要三个参数,分别为出发日期、出发地以及目的地;然后创建查询请求的完整地址,并通过format()方法格式化地址;再将返回的json数据转换为字典类型;最后通过字典类型键值的方法取出对应的数据并进行整理与分类。代码如下:

def query(date, from_station, to_station):

    data.clear()  # 清空数据

    type_data.clear()  # 清空车次分类保存的数据

    # 查询请求地址

    url = 'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(

        date, from_station, to_station)

    # 发送查询请求

    response = requests.get(url,headers=headers)

    # # 将json数据转换为字典类型,通过键值对取数据

    result = response.json()

    result = result['data']['result']

    # 判断车站文件是否存在

    if isStations() == True:

        stations = eval(read())  # 读取所有车站并转换为dic类型

        if len(result) != 0:  # 判断返回数据是否为空

            for in result:

                # # 分割数据并添加到列表中

                tmp_list = i.split('|')

                # 因为查询结果中出发站和到达站为站名的缩写字母,所以需要在车站库中找到对应的车站名称

                from_station = list(stations.keys())[list(stations.values()).index(tmp_list[6])]

                to_station = list(stations.keys())[list(stations.values()).index(tmp_list[7])]

                # 创建座位数组,由于返回的座位数据中含有空既“”,所以将空改成--这样好识别

                seat = [tmp_list[3], from_station, to_station, tmp_list[8], tmp_list[9], tmp_list[10]

                    , tmp_list[32], tmp_list[31], tmp_list[30], tmp_list[21]

                    , tmp_list[23], tmp_list[33], tmp_list[28], tmp_list[24], tmp_list[29], tmp_list[26]]

                newSeat = []

                # 循环将座位信息中的空既“”,改成--这样好识别

                for in seat:

                    if s == "":

                        s = "--"

                    else:

                        s = s

                    newSeat.append(s)  # 保存新的座位信息

                data.append(newSeat)

        return data  # 返回整理好的车次信息

说明:因为返回的Json信息顺序比较零乱,所以在获取指定的数据时通过tmp_list分割后的列表将数据与浏览器余票查询页面中的数据逐个对比后,才能找出数据所对应的位置。通过对比后找到的数据位置如下:

 '''5-7 目的地  3 车次  6 出发地  8 出发时间  9 到达时间  10 历时  26 无坐  29 硬座

   24 软座  28 硬卧  33 动卧  23 软卧  21 高级软卧  30 二等座  31 一等座  32 商务座特等座

'''

数字为数据分割后tmp_list的索引值。

4)依次创建获取高铁信息、移除高铁信息、获取动车信息、移除动车信息、获取直达信息、移除直达信息、获取特快信息、移除特快信息、获取快速信息及移除快速信息的方法。这些方法用于车次分类数据的处理,代码如下:

# 获取高铁信息的方法

def g_vehicle():

    if len(data) != 0:

        for g in data:              # 循环所有火车数据

            i = g[0].startswith('G')      # 判断车次首字母是不是高铁

            ifi:              # 如果是将该条信息添加到高铁数据中

                type_data.append(g)

# 移除高铁信息的方法

def r_g_vehicle():

    if len(data) != 0 and len(type_data) != 0:

        for g in data:

            i = g[0].startswith('G')

            ifi:              # 移除高铁信息

                type_data.remove(g)

# 获取动车信息的方法

def d_vehicle():

    if len(data) != 0:

        for d in data:              # 循环所有火车数据

            i = d[0].startswith('D')      # 判断车次首字母是不是动车

            ifi == True:          # 如果是将该条信息添加到动车数据中

                type_data.append(d)

# 移除动车信息的方法

def r_d_vehicle():

    if len(data) != 0 and len(type_data) != 0:

        for d in data:

            i = d[0].startswith('D')

            ifi == True:          # 移除动车信息

                type_data.remove(d)

'''由于代码几乎相同,此处省略部分代码可在源码中进行查询

   省略.........

'''

# 获取快速车数据的方法

def k_vehicle():

    if len(data) != 0:

        for k in data:              # 循环所有火车数据

            i = k[0].startswith('K')      # 判断车次首字母是不是快车

            ifi == True:          # 如果是将该条信息添加到快车数据中

                type_data.append(k)

# 移除快速车数据的方法

def r_k_vehicle():

    if len(data) != 0 and len(type_data) != 0:

        for k in data:

            i = k[0].startswith('K')

            ifi == True:          # 移除快车信息

                type_data.remove(k)

2  在主窗体中显示查票信息

完成了车票信息查询请求的文件后,接下来需要将获取的车票信息显示在快手爬票的主窗体当中。具体实现步骤如下:

(1)打开window.py文件,导入PyQt5.QtCore模块中的Qt类,然后导入PyQt5.QtWidgets模块与PyQt5.QtGui模块下的所有方法,再导入query_request文件中的所有方法。代码如下:

from PyQt5.QtCore import Qt            # 导入Qt类

from PyQt5.QtWidgets import *             # 导入对应模块的所有方法

from query_request import *

from PyQt5.QtGui import *

(2)在setupUi()方法中找到用于显示车票信息的tableView表格控件。然后为该控件设置相关属性,关键代码如下:

# 显示车次信息的列表

self.tableView = QtWidgets.QTableView(self.centralwidget)

self.tableView.setGeometry(QtCore.QRect(0, 320, 960, 440))

self.tableView.setObjectName("tableView")

self.model = QStandardItemModel();  # 创建存储数据的模式

# 根据空间自动改变列宽度并且不可修改列宽度

self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

# 设置表头不可见

self.tableView.horizontalHeader().setVisible(False)

# 纵向表头不可见

self.tableView.verticalHeader().setVisible(False)

# 设置表格内容文字大小

font = QtGui.QFont()

font.setPointSize(10)

self.tableView.setFont(font)

# 设置表格内容不可编辑

self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)

# 垂直滚动条始终开启

self.tableView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

(3)导入time模块,该模块提供了用于处理时间的各种方法。然后在代码块的最外层创建get_time()方法用于获取系统的当前日期,再创建is_valid_date()方法用于判断输入的日期是否是一个有效的日期字符串,代码如下:

import time

# 获取系统当前时间并转换请求数据所需要的格式

def get_time():

    # 获取当前时间的时间戳

    now = int(time.time())

    # 转换为其他日期格式,如:"%Y-%m-%d %H:%M:%S"

    timeStruct = time.localtime(now)

    strTime = time.strftime("%Y-%m-%d", timeStruct)

    return strTime

defis_valid_date(str):

    '''判断是否是一个有效的日期字符串'''

    try:

        time.strptime(str, "%Y-%m-%d")

        return True

    except:

        return False

(4)依次创建change_G、change_D、change_Z、change_T、change_K()方法,以上方法均为车次分类复选框的事件处理,由于代码几乎相同,此处提供关键代码如下:

# 高铁复选框事件处理

def change_G(self, state):

    # 选中将高铁信息添加到最后要显示的数据当中

    if state == QtCore.Qt.Checked:

        # 获取高铁信息

        g_vehicle()

        # 通过表格显示该车型数据

        self.displayTable(len(type_data), 16, type_data)

    else:

        # 取消选中状态将移除该数据

        r_g_vehicle()

        self.displayTable(len(type_data), 16, type_data)

(5)创建checkBox_default()方法,该方法用于将所有车次分类复选框取消勾选,代码如下:

def checkBox_default(self):

    self.checkBox_G.setChecked(False)

    self.checkBox_D.setChecked(False)

    self.checkBox_Z.setChecked(False)

    self.checkBox_T.setChecked(False)

    self.checkBox_K.setChecked(False)

(6)创建messageDialog()方法,用于显示主窗体非法操作的消息提示框;创建displayTable()方法,用于显示车次信息的表格与内容。代码如下:

# 显示消息提示框,参数title为提示框标题文字,message为提示信息

def messageDialog(self, title, message):

    msg_box = QMessageBox(QMessageBox.Warning, title, message)

    msg_box.exec_()

# 显示车次信息的表格

# train参数为共有多少列车,该参数作为表格的行。

# info参数为该次列车的具体信息,例如有座、无座、卧铺等。该参数作为表格的列

def displayTable(self, train, info, data):

    self.model.clear()

    for row in range(train):

        for column in range(info):

            # 添加表格内容

            item = QStandardItem(data[row][column])

            # 向表格存储模式中添加表格具体信息

            self.model.setItem(row, column, item)

    # 设置表格存储数据的模式

    self.tableView.setModel(self.model)

(7)创建on_click()方法,该方法是查询按钮的单击事件。在该方法中首先获取出发地、目的地与出发日期三个编辑框的输入内容,然后对三个编辑框中输入的内容进行合法检测,符合规范后调用query()方法提交车票查询的请求并且将返回的数据赋值给data,最后通过调用displayTable()方法实现在表格中显示车票查询的全部信息。代码如下:

# 查询按钮的单击事件

def on_click(self):

    get_from = self.textEdit.toPlainText()      # 获取出发地

    get_to = self.textEdit_2.toPlainText()      # 获取到达地

    get_date = self.textEdit_3.toPlainText()     # 获取出发时间

    # 判断车站文件是否存在

    ifisStations() == True:

        stations = eval(read())          # 读取所有车站并转换为dic类型

        # 判断所有参数是否为空,以及出发地、目的地、出发日期

        if get_from != "" and get_to != "" and get_date != "":

            # 判断输入的车站名称是否存在,以及时间格式是否正确

            if get_from in stations and get_to in stations and is_valid_date(get_date):

                # 获取输入的日期是当前年初到现在一共过了多少天

                inputYearDay = time.strptime(get_date, "%Y-%m-%d").tm_yday

                # 获取系统当前日期是当前年初到现在一共过了多少天

                yearToday = time.localtime(time.time()).tm_yday

                # 计算时间差,也就是输入的日期减掉系统当前的日期

                timeDifference = inputYearDay - yearToday

                # 判断时间差为0时证明是查询当前的查票

                # 以及29天以后的车票,12306官方要求只能查询30天以内的车票

                if timeDifference >= 0 and timeDifference <= 28:

                    # 在所有车站文件中找到对应的参数

                    from_station = stations[get_from]    # 出发地

                    to_station = stations[get_to]      # 目的地

                    # 发送查询请求,并获取返回的信息

                    data = query(get_date, from_station, to_station)

                    self.checkBox_default()         # 调用取消勾选所有车次分类复选框

                    if len(data) != 0:          # 判断返回的数据是否为空

                        # 如果不是空的数据就将车票信息显示在表格中

                        self.displayTable(len(data), 16, data)

                    else:

                        self.messageDialog('警告', '没有返回的网络数据!')

                else:

                    self.messageDialog('警告', '超出查询日期的范围内,'

                                       '不可查询昨天的车票信息,以及29天以后的车票信息!')

            else:

                self.messageDialog('警告', '输入的站名不存在,或日期格式不正确!')

        else:

            self.messageDialog('警告', '请填写车站名称!')

    else:

        self.messageDialog('警告', '未下载车站查询文件!')

(8)在retranslateUi()方法中,首先设置出发日期的编辑框中显示系统的当前日期,然后设置查询按钮的单击事件,最后分别设置高铁、动车、直达、特快以及快车复选框选中与取消事件。关键代码如下:

self.textEdit_3.setText(get_time())              # 出发日期显示当天日期

self.pushButton.clicked.connect(self.on_click)      # 查询按钮指定单击事件的方法

self.checkBox_G.stateChanged.connect(self.change_G)      # 高铁选中与取消事件

self.checkBox_D.stateChanged.connect(self.change_D)      # 动车选中与取消事件

self.checkBox_Z.stateChanged.connect(self.change_Z)      # 直达车选中与取消事件

self.checkBox_T.stateChanged.connect(self.change_T)      # 特快车选中与取消事件

self.checkBox_K.stateChanged.connect(self.change_K)      # 快车选中与取消事件

(9)在window.py文件下,单击右键,选择“Run 'window'”菜单运行主窗体,然后输入符合规范的出发地、目的地与出发日期,单击查询按钮将显示如图35所示。

图35  显示查询的查票信息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《软件测试52讲》——测试基础知识篇

1 你真的懂测试吗&#xff1f;从“用户登录”测试谈起 从“用户登录”测试谈起&#xff0c;“用户登录”功能作为测试对象 作为测试工程师&#xff0c;你的目标是要保证系统在各种应用场景下的功能是符合设计要求的&#xff0c;所以你需要考虑的测试用例就需要更多、更全面。 …

2078.两栋颜色不同且距离最远的房子

街上有 n 栋房子整齐地排成一列&#xff0c;每栋房子都粉刷上了漂亮的颜色。给你一个下标从 0 开始且长度为 n 的整数数组 colors &#xff0c;其中 colors[i] 表示第 i 栋房子的颜色。 返回 两栋 颜色 不同 房子之间的 最大 距离。 第 i 栋房子和第 j 栋房子之间的距离是 a…

Linux应用编程 - i2c-dev操作I2C

嵌入式Linux操作I2C设备&#xff0c;我们一般会在内核态编写I2C驱动程序。另外还能在用户空间编写I2C程序&#xff0c;下面介绍相关代码的实现。 i2c-dev框架在内核中封装了I2C通信所需要的所有通信细节&#xff0c;I2C适配器会在/dev目录下创建字符设备&#xff0c;例如&#…

kettle从入门到精通 第七十课 ETL之kettle kettle数据校验,脏数据清洗轻松拿捏

场景&#xff1a;输入在指定的错误(错误应涵盖数据类型不匹配的情况)行数内&#xff0c;trans不报错&#xff0c;但通过错误处理步骤捕捉&#xff0c;并记入文件&#xff0c;整个数据管线正常完成直至处理完最后一个输入行。 解决方案&#xff1a;使用步骤【数据检验】进行处理…

本周MoonBit新增Wasm1引用计数支持、语法即将添加错误恢复机制

MoonBit更新 【Wasm MVP】Wasm1 后端添加基于 Perceus 算法的引用计数支持 【语法】throw raise try catch 均被保留为关键字 为了即将添加的错误处理机制 【Core】List与sorted_map被移动至core/immut下 List被移动至core/immut/list包中&#xff0c;并被移除内置类型支持 …

哈希表、递归在二叉树中的应用-1372. 二叉树中的最长交错路径

题目链接及描述 1372. 二叉树中的最长交错路径 - 力扣&#xff08;LeetCode&#xff09; 题目分析 题目所述&#xff0c;计算在二叉树中交替遍历的最大深度【左->右->左】【右->左->右】&#xff0c;例如对于从当前根节点root出发&#xff0c;则此时遍历方向有两个…

今日成果2024-6-7 TrustZone TEE安全SDK开发指南

Rockchip Vendor Storage Application Note.pdf OK 开机下&#xff0c;可以实现Vendor Storage的读写。 0ms时同步RTC时间 OK Rockchip_Developer_Guide_TEE_SDK_CN.pdf 什么是TrustZone 此系统方法意味着可以保护安全内存、加密块、键盘和屏幕等外设&#xff0c;从而可确…

视频剪辑可以赚钱吗 快速学会视频剪辑的方法

由于视频剪辑的需求不断增长&#xff0c;学会视频剪辑成为一项自媒体必备的技能&#xff0c;这个技能可以为个人带来收入和职业发展带来机会。无论是作为自由职业者还是在公司工作&#xff0c;掌握视频剪辑技能都可以为你提供更多的工作机会和竞争优势。这篇文章将讲解视频剪辑…

2.深度学习-线性回归

文章目录 环境配置&#xff08;必看&#xff09;线性回归代码工程运行结果1.对比图2.运行结果 环境配置&#xff08;必看&#xff09; Anaconda-创建虚拟环境的手把手教程相关环境配置看此篇文章&#xff0c;本专栏深度学习相关的版本和配置&#xff0c;均按照此篇文章进行安装…

Carsim高级开发:VS Connect通讯开发指南

文章目录 前言一、VS Connect 概念引入二、VS Connect 通讯框架三、Carsim 工程配置1、车辆模型配置2、procedure配置3、Run Control配置4、受控车辆名称配置 四、VS Connect Server代码1、打开Sln工程2、代码修改 五、VS Connect Client代码1、函数的调用关系2、carsim_variab…

5G消息 x 文旅 | 一站式智慧文旅解决方案

5G消息 x 文旅 | 一站式智慧文旅解决方案 文旅 x 5G 消息将进一步强化资源整合&#xff0c;满足游客服务需求、企业营销需求、政府管理需求&#xff0c;推进文化旅游项目的智慧化、数字化&#xff0c;增强传播力、竞争力和可持续性。5G 消息的“原生入口”、“超强呈现”、“智…

帕金森病的食疗建议

帕金森病&#xff08;PD&#xff09;是一种慢性、进展性的神经退行性疾病&#xff0c;主要影响中老年人。虽然目前尚无法根治&#xff0c;但及早规范治疗可显著改善症状&#xff0c;提高患者的生活质量。饮食调理作为帕金森病综合治疗的重要组成部分&#xff0c;对于维持患者较…

接口测试详解

接口测试详解 本文主要讲软件接口 一、什么是接口&#xff1f;硬件接口&#xff1a;硬件接口指的是硬件提供给外界的一种实体。主要作用是内部数据分离出外 部的沟通方法 目的是&#xff1a;沟通外部来改变内部的数据。如&#xff1a;USB接口&#xff0c;投影仪接口 软件接口…

【CDN】逆天 CDN !BootCDN 向 JS 文件中植入恶意代码

今天在调试代码&#xff0c;突然控制台出现了非常多报错。 这非常可疑&#xff0c;报错指向的域名也证实了这一点。 因为我的 HTML 中只有一个外部开源库&#xff08;qrcode.min.js&#xff09;&#xff0c;因此只有可能是它出现了问题。 我翻看了请求记录&#xff0c;发现这…

【无线感知】【P3】无线感知手势识别-Ubicomp2022论文分享

前言&#xff1a; 本篇主要关于手势识别的方向的,主要参考 北京大学-《无线感知手势识别-Ubicomp2022论文分享》 目录&#xff1a; 技术背景 主要问题&#xff08;异质性问题&#xff09; 感知模型 EDP DPSense 实现效果 一 技术背景 基于WIFI的手势识别在智能家具,以…

ShardingSphere-proxy添加自定义分片规则(踩坑日记)

文章目录 一、新建spring boot项目二、编写代码(1) 新建一个类(2) doSharding方法详解(3) 实际例子 三、增加spi文件&#xff08;很关键&#xff09;四、打包五、把生成的文件放到ext-lib中六、yaml配置&#xff08;怎么用&#xff09;七、测试 版本环境 mysql 5.7.40 sharding…

湘潭大学信息与网络安全复习笔记2(总览)

前面的实验和作业反正已经结束了&#xff0c;现在就是集中火力把剩下的内容复习一遍&#xff0c;这一篇博客的内容主要是参考教学大纲和教学日历 文章目录 教学日历教学大纲 教学日历 总共 12 次课&#xff0c;第一次课是概述&#xff0c;第二次和第三次课是密码学基础&#x…

[渗透测试学习] Runner-HackTheBox

Runner-HackTheBox 信息搜集 nmap扫描端口 nmap -sV -v 10.10.11.13扫描结果如下 PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0) 80/tcp open http nginx 1.18.0 (Ubuntu) 8000…

中小制造业工厂要不要上MES系统

MES系统的主要功能包括制造数据管理、计划排产管理、生产调度管理、库存管理、质量管理、人力资源管理、工作中心/设备管理、工具工装管理、采购管理、成本管理、项目看板管理、生产过程控制、底层数据集成分析、上层数据集成分解等。通过这些模块&#xff0c;MES为企业打造一个…

基于springboot实现农产品直卖平台系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现农产品直卖平台系统的设计演示 摘要 计算机网络发展到现在已经好几十年了&#xff0c;在理论上面已经有了很丰富的基础&#xff0c;并且在现实生活中也到处都在使用&#xff0c;可以说&#xff0c;经过几十年的发展&#xff0c;互联网技术已经把地域信息的隔…