Python爬虫技术及PyQt5界面编程实现12306火车票查询

1 篇文章 0 订阅
订阅专栏

界面设计

界面设计使用了Qt 设计师(使用方法请自行探索)实现拖拽生成:
在这里插入图片描述
设计保存后会生成一个后缀位ui的文件,将这个文件放进项目中,此时我们还不能直接运行这个文件,也看不到界面,此时在PyCharm中做如下配置:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
程序:python.exe所在的目录

实参:-m PyQt5.uic.pyuic$FileName$ -o $FileNameWithoutExtension$.py

工作目录:$FileDir$

添加好之后返回项目界面,右键刚才的ui后缀文件

在这里插入图片描述
选择External Tools—>PyUIC
执行后同级目录下会生成一个同名的py文件在这里插入图片描述
此时的py文件运行是不能出现界面的,在刚才生成的py文件中添加如下代码:

# 显示主窗体
def show_MainWindow():
    app = QtWidgets.QApplication(sys.argv)  # 实例化QApplication,作为GUI主程序入口
    MainWindow = QtWidgets.QMainWindow()  # 创建QMainWindow
    ui = Ui_MainWindow()  # 实例UI类
    ui.setupUi(MainWindow)  # 设置窗体UI
    MainWindow.show()  # 显示窗体
    sys.exit(app.exec_())  # 当窗口创建完成后需要结束主循环
if __name__ == '__main__':
	show_MainWindow()  # 调用显示窗体的方法

此时则可以实现运行出界面。(设计时的图片等路径可能需要更改才能正确显示

技术实现

1、12306网页车票查询分析

此处需要具备爬虫知识
经过分析得知:

url=‘https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9050’

这个链接就是获取车站的链接(输入车站名时怎么进行查询的?分析发现是根据 中文名对应的英文缩写,而这个链接就是获取这种对应关系的)

获取车站信息代码:

# -*- coding: utf-8 -*-
"""
-------------------------------------------------
  File Name:    get_stations.py
  Author:        lenovo
  Date:         2021/12/20
  Create by:     PyCharm
  Description :  获取车站信息---中文和对应英文缩写
-------------------------------------------------
"""
import os
import re

import requests

"""
1、”utf-8“ 是以字节为编码单元,它的字节顺序在所有系统中都是一样的,
    没有字节序问题,因此它不需要BOM,所以当用"utf-8"编码方式读取带有BOM的文件时,
    它会把BOM当做是文件内容来处理, 也就会发生类似上边的错误.
2、“utf-8-sig"中sig全拼为 signature 也就是"带有签名的utf-8”, 
    因此"utf-8-sig"读取带有BOM的"utf-8文件时"会把BOM单独处理,
    与文本内容隔离开,也是我们期望的结果.
"""


def getStation():
    # 发送请求获取所有车站名称,通过输入的站名称转化查询地址的参数
    url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9050'
    response = requests.get(url, verify=True)  # 请求并进行验证
    stations = re.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)  # 获取需要的车站名称
    stations = dict(stations)  # 转换为dic
    stations = str(stations)  # 转换为字符串类型否则无法写入文件
    write(stations)  # 调用写入方法


def write(stations):
    if not os.path.exists('station/'):  # 如果文件目录不存在则创建
        os.makedirs('station/')

    with open('station/stations.text', 'w', encoding='utf_8_sig') as f:  # w文本写入
        f.write(stations)
        f.close()


def read():
    file = open('station/stations.text', 'r', encoding='utf_8_sig')  # 以写模式打开文件
    data = file.readline()  # 读取文件
    file.close()
    return data


def isStations():
    isExist = os.path.exists('station/stations.text')  # 判断车站文件是否存在
    return isExist

获取查询结果

# -*- coding: utf-8 -*-
"""
-------------------------------------------------
  File Name:    query_data.py
  Author:        lenovo
  Date:         2021/12/20
  Create by:     PyCharm
  Description :  查询车辆信息
-------------------------------------------------
"""
from get_stations import *

'''
5-7 目的地 3  车次 6  出发地 8  出发时间 9  到达时间 10 历时 26 无坐 29 硬座
24 软座 28 硬卧 33 动卧 23 软卧 21 高级软卧 30 二等座 31 一等座 32 商务座特等座
'''
data = []  # 用于保存整理好的车次信息
type_data = []  # 保存车次分类后最后的数据


def query(date, from_station, to_station):
    """
    根据传入的日期,起始车站,目的车站返回查询结果
    :param date: 出发日期
    :param from_station: 起始车站
    :param to_station: 目的车站
    :return: 查询数据
    """
    data.clear()  # 清空数据
    type_data.clear()  # 清空车次分类保存的数据
    headers = {
        'Cookie': "_uab_collina=163999108472034091142832; JSESSIONID=C5C4C5E7526DC0B7BFC6A5717D1F8380; BIGipServerotn=368050698.24610.0000; BIGipServerpool_passport=115606026.50215.0000; RAIL_EXPIRATION=1640270981777; RAIL_DEVICEID=lbec11dld1VeM-sTt-5XFnXTNwhNgpCur_gC8sJjGNMKKBV3uSi0ISD97wfIwWm3kwTRoZUeiv4uB7BtHpBl_bA_6px32mcN8aNpC6MMoP9VmpMINrZxxaQM_KNWIV7rZ7mND7kKrQxv5MTYmOMh6-I-KYFHkTvj; guidesStatus=off; highContrastMode=defaltMode; cursorStatus=off; route=495c805987d0f5c8c84b14f60212447d; _jc_save_fromDate=2021-12-20; _jc_save_toDate=2021-12-20; _jc_save_wfdc_flag=dc; _jc_save_fromStation=%u5317%u4EAC%2CBJP; _jc_save_toStation=%u4E0A%u6D77%2CSHH",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62"
    }
    # 查询请求地址
    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=url, headers=headers)
    response.encoding = response.apparent_encoding
    # # 将json数据转换为字典类型,通过键值对取数据
    if response.status_code != 200:  # 直接返回空
        return data

    result = response.json()['data']['result']
    # for i in result:
    #     print(i)

    if isStations():
        stations = eval(read())  # 读取所有车站并转换为dic类型
        if len(result) != 0:  # 判断返回数据是否为空
            for i 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 s in seat:
                    if s == "":
                        s = "--"
                    else:
                        s = s
                    newSeat.append(s)  # 保存新的座位信息
                data.append(newSeat)
        return data  # 返回整理好的车次信息


# 获取高铁信息的方法
def g_vehicle():
    if len(data) != 0:
        for g in data:  # 循环所有火车数据
            i = g[0].startswith('G')  # 判断车次首字母是不是高铁
            if i:  # 如果是将该条信息添加到高铁数据中
                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')
            if i:  # 移除高铁信息
                type_data.remove(g)


# 获取动车信息的方法
def d_vehicle():
    if len(data) != 0:
        for d in data:  # 循环所有火车数据
            i = d[0].startswith('D')  # 判断车次首字母是不是动车
            if i == 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')
            if i == True:  # 移除动车信息
                type_data.remove(d)


# 获取直达车信息的方法
def z_vehicle():
    if len(data) != 0:
        for z in data:  # 循环所有火车数据
            i = z[0].startswith('Z')  # 判断车次首字母是不是直达
            if i == True:  # 如果是将该条信息添加到直达数据中
                type_data.append(z)


# 移除直达车信息的方法
def r_z_vehicle():
    if len(data) != 0 and len(type_data) != 0:
        for z in data:
            i = z[0].startswith('Z')
            if i == True:  # 移除直达车信息
                type_data.remove(z)


# 获取特快车信息的方法
def t_vehicle():
    if len(data) != 0:
        for t in data:  # 循环所有火车数据
            i = t[0].startswith('T')  # 判断车次首字母是不是特快
            if i == True:  # 如果是将该条信息添加到特快车数据中
                type_data.append(t)


# 移除特快车信息的方法
def r_t_vehicle():
    if len(data) != 0 and len(type_data) != 0:
        for t in data:
            i = t[0].startswith('T')
            if i == True:  # 移除特快车信息
                type_data.remove(t)


# 获取快速车数据的方法
def k_vehicle():
    if len(data) != 0:
        for k in data:  # 循环所有火车数据
            i = k[0].startswith('K')  # 判断车次首字母是不是快车
            if i == 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')
            if i == True:  # 移除快车信息
                type_data.remove(k)

在主界面综合爬虫实现查询并展示结果

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'main.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.
import datetime
import sys
import time

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from query_data import *


# UI类
class Ui_MainWindow(object):
    # 设置UI方法
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")  # 设置窗体对象名称
        MainWindow.resize(960, 786)  # 设置窗体大小
        MainWindow.setMinimumSize(QtCore.QSize(960, 786))  # 主窗体最小值
        MainWindow.setMaximumSize(QtCore.QSize(960, 786))  # 主窗体最大值
        # MainWindow.setStyleSheet("*{border:1px solid blue}")
        self.centralwidget = QtWidgets.QWidget(MainWindow)  # 主窗体的widget控件
        self.centralwidget.setObjectName("centralwidget")  # 设置对象名称

        # --------------通过label控件setStyleSheet显示顶部图片-------------
        self.label_title_img = QtWidgets.QLabel(self.centralwidget)
        self.label_title_img.setGeometry(QtCore.QRect(0, 0, 960, 141))
        font = QtGui.QFont()
        font.setPointSize(20)
        self.label_title_img.setFont(font)
        self.label_title_img.setStyleSheet("background-image: url(img/bg1.png);")
        self.label_title_img.setText("")
        self.label_title_img.setObjectName("label_title_img")

        # ----------------选择车次类型的widget----------------------------
        self.widget_checkBox = QtWidgets.QWidget(self.centralwidget)
        self.widget_checkBox.setGeometry(QtCore.QRect(0, 220, 961, 35))
        self.widget_checkBox.setAutoFillBackground(False)
        self.widget_checkBox.setStyleSheet("background-image: url(img/bg3.png);")
        self.widget_checkBox.setObjectName("widget_checkBox")
        # 选择特快
        self.checkBox_T = QtWidgets.QCheckBox(self.widget_checkBox)
        self.checkBox_T.setGeometry(QtCore.QRect(580, 5, 80, 25))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.checkBox_T.setFont(font)
        self.checkBox_T.setObjectName("checkBox_T")
        # 选择快速
        self.checkBox_K = QtWidgets.QCheckBox(self.widget_checkBox)
        self.checkBox_K.setGeometry(QtCore.QRect(720, 5, 80, 25))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.checkBox_K.setFont(font)
        self.checkBox_K.setObjectName("checkBox_K")
        # 选择直达
        self.checkBox_Z = QtWidgets.QCheckBox(self.widget_checkBox)
        self.checkBox_Z.setGeometry(QtCore.QRect(440, 5, 80, 25))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.checkBox_Z.setFont(font)
        self.checkBox_Z.setObjectName("checkBox_Z")
        # 选择动车
        self.checkBox_D = QtWidgets.QCheckBox(self.widget_checkBox)
        self.checkBox_D.setGeometry(QtCore.QRect(300, 5, 80, 25))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.checkBox_D.setFont(font)
        self.checkBox_D.setObjectName("checkBox_D")
        # 选择高铁
        self.checkBox_G = QtWidgets.QCheckBox(self.widget_checkBox)
        self.checkBox_G.setGeometry(QtCore.QRect(160, 5, 80, 25))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.checkBox_G.setFont(font)
        self.checkBox_G.setObjectName("checkBox_G")
        # 显示车次类型文字
        self.label_type = QtWidgets.QLabel(self.widget_checkBox)
        self.label_type.setGeometry(QtCore.QRect(20, 5, 80, 25))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label_type.setFont(font)
        self.label_type.setObjectName("label_type")

        # -----------------------通过label控件显示火车信息图片--------------------
        self.label_train_img = QtWidgets.QLabel(self.centralwidget)
        self.label_train_img.setGeometry(QtCore.QRect(0, 256, 960, 62))
        self.label_train_img.setStyleSheet("background-image: url(img/bg4.png);")
        self.label_train_img.setText("")
        self.label_train_img.setObjectName("label_train_img")

        # -------------------------查询部分widget--------------------------------------
        self.widget_query = QtWidgets.QWidget(self.centralwidget)
        self.widget_query.setGeometry(QtCore.QRect(0, 140, 960, 80))
        self.widget_query.setStyleSheet("background-image: url(img/bg2.png);")
        self.widget_query.setObjectName("widget_query")
        # 出发地与对应的编辑框控件
        self.label = QtWidgets.QLabel(self.widget_query)
        self.label.setGeometry(QtCore.QRect(30, 20, 70, 30))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.textEdit = QtWidgets.QTextEdit(self.widget_query)
        self.textEdit.setGeometry(QtCore.QRect(100, 20, 110, 30))
        font = QtGui.QFont()  # 创建QFont()对象
        font.setPointSize(13)  # 设置编辑框字体大小的值
        self.textEdit.setFont(font)  # 设置编辑框字体
        self.textEdit.setStyleSheet("background:white;")  # 背景颜色
        # self.textEdit.setTextBackgroundColor(QtGui.QColor("red")) #设置字体背景颜色
        self.textEdit.setObjectName("textEdit")  # 出发地对应编辑框对象名称
        # 目的地与对应的编辑框
        self.label_2 = QtWidgets.QLabel(self.widget_query)
        self.label_2.setGeometry(QtCore.QRect(270, 20, 70, 30))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label_2.setFont(font)
        self.label_2.setObjectName("label_2")
        self.textEdit_2 = QtWidgets.QTextEdit(self.widget_query)
        self.textEdit_2.setGeometry(QtCore.QRect(340, 20, 110, 30))
        font = QtGui.QFont()
        font.setPointSize(13)
        self.textEdit_2.setFont(font)
        self.textEdit_2.setStyleSheet("background:white;")  # 背景颜色
        self.textEdit_2.setObjectName("textEdit_2")

        # 出发日与有对应的日期选择框
        self.label_3 = QtWidgets.QLabel(self.widget_query)
        self.label_3.setGeometry(QtCore.QRect(510, 20, 70, 30))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label_3.setFont(font)
        self.label_3.setObjectName("label_3")
        # 日期选择框
        self.dateEdit = QtWidgets.QDateEdit(self.widget_query)
        self.dateEdit.setGeometry(QtCore.QRect(580, 20, 111, 30))
        font = QtGui.QFont()
        font.setPointSize(-1)
        self.dateEdit.setFont(font)
        self.dateEdit.setStyleSheet("*{font-size:16px}")
        self.dateEdit.setTimeSpec(QtCore.Qt.LocalTime)
        # -------显示时间是当前时间------------
        self.dateEdit.setDate(datetime.date.today())
        # --------设置允许弹出下拉框-----------
        self.dateEdit.setCalendarPopup(True)
        self.dateEdit.setObjectName("dateEdit")

        # 查询按钮
        self.pushButton = QtWidgets.QPushButton(self.widget_query)
        self.pushButton.setGeometry(QtCore.QRect(820, 20, 90, 30))
        self.pushButton.setObjectName("pushButton")

        # -----------------------显示车次信息的列表--------------------------------
        self.tableView = QtWidgets.QTableView(self.centralwidget)
        self.tableView.setGeometry(QtCore.QRect(0, 318, 960, 468))
        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)
        # 主窗体设置主Widget
        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)  # 调用retranslateUi方法显示窗体文字
        QtCore.QMetaObject.connectSlotsByName(MainWindow)  # 关联信号槽

        MainWindow.setTabOrder(self.checkBox_G, self.checkBox_D)
        MainWindow.setTabOrder(self.checkBox_D, self.checkBox_Z)
        MainWindow.setTabOrder(self.checkBox_Z, self.checkBox_T)
        MainWindow.setTabOrder(self.checkBox_T, self.checkBox_K)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "12306车票查询-小组成员:王冬、尹翀、卢正刚、王赢杰"))
        self.checkBox_T.setText(_translate("MainWindow", "T-特快"))
        self.checkBox_K.setText(_translate("MainWindow", "K-快速"))
        self.checkBox_Z.setText(_translate("MainWindow", "Z-直达"))
        self.checkBox_D.setText(_translate("MainWindow", "D-动车"))
        self.checkBox_G.setText(_translate("MainWindow", "G-高铁"))
        self.label_type.setText(_translate("MainWindow", "车次类型:"))
        self.label.setText(_translate("MainWindow", "出发地:"))
        self.label_2.setText(_translate("MainWindow", "目的地:"))
        self.label_3.setText(_translate("MainWindow", "出发日:"))
        self.pushButton.setText(_translate("MainWindow", "查询"))
        self.dateEdit.setDisplayFormat(_translate("MainWindow", "yyyy-MM-dd"))

        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)  # 快车选中与取消事件

    # 查询按钮的单击事件
    def on_click(self):
        get_from = self.textEdit.toPlainText()  # 获取出发地
        get_to = self.textEdit_2.toPlainText()  # 获取到达地
        get_date = self.dateEdit.text()  # 获取出发时间

        # 判断车站文件是否存在
        if isStations():
            stations = eval(read())  # 读取所有车站并转换为dic类型
            # 判断所有参数是否为空,出发地、目的地、出发日期
            if get_from != "" and get_to != "" and get_date != "":
                # 判断输入的车站名称是否存在,以及时间格式是否正确
                if get_from in stations and get_to in stations:
                    # 获取输入的日期是当前年初到现在一共过了多少天
                    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 0 <= 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('警告', '未下载车站查询文件!')

    # 将所有车次分类复选框取消勾选
    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)

    # 高铁复选框事件处理
    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)

    # 动车复选框事件处理
    def change_D(self, state):
        # 选中将动车信息添加到最后要显示的数据当中
        if state == QtCore.Qt.Checked:
            # 获取动车信息
            d_vehicle()
            # 通过表格显示该车型数据
            self.displayTable(len(type_data), 16, type_data)

        else:
            # 取消选中状态将移除该数据
            r_d_vehicle()
            self.displayTable(len(type_data), 16, type_data)

    # 直达复选框事件处理
    def change_Z(self, state):
        # 选中将直达车信息添加到最后要显示的数据当中
        if state == QtCore.Qt.Checked:
            # 获取直达车信息
            z_vehicle()
            self.displayTable(len(type_data), 16, type_data)
        else:
            # 取消选中状态将移除该数据
            r_z_vehicle()
            self.displayTable(len(type_data), 16, type_data)

    # 特快复选框事件处理
    def change_T(self, state):
        # 选中将特快车信息添加到最后要显示的数据当中
        if state == QtCore.Qt.Checked:
            # 获取特快车信息
            t_vehicle()
            self.displayTable(len(type_data), 16, type_data)
        else:
            # 取消选中状态将移除该数据
            r_t_vehicle()
            self.displayTable(len(type_data), 16, type_data)

    # 快速复选框事件处理
    def change_K(self, state):
        # 选中将快车信息添加到最后要显示的数据当中
        if state == QtCore.Qt.Checked:
            # 获取快速车信息
            k_vehicle()
            self.displayTable(len(type_data), 16, type_data)
        else:
            # 取消选中状态将移除该数据
            r_k_vehicle()
            self.displayTable(len(type_data), 16, type_data)

    # 显示消息提示框,参数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)


# 显示主窗体
def show_MainWindow():
    app = QtWidgets.QApplication(sys.argv)  # 实例化QApplication,作为GUI主程序入口
    MainWindow = QtWidgets.QMainWindow()  # 创建QMainWindow
    ui = Ui_MainWindow()  # 实例UI类
    ui.setupUi(MainWindow)  # 设置窗体UI
    MainWindow.show()  # 显示窗体
    sys.exit(app.exec_())  # 当窗口创建完成后需要结束主循环


if __name__ == '__main__':
    if not isStations():  # 判断是否有所有车站的文件,没有就下载,有就直接显示窗体
        getStation()  # 下载所有车站文件
        show_MainWindow()  # 调用显示窗体的方法
    else:
        show_MainWindow()  # 调用显示窗体的方法

在这里插入图片描述
在这里插入图片描述
打包为exe方法

PyQt5编辑 12306车票信息爬取程序
czh2637750821的博客
05-11 1972
1、搭载QT环境 按win+R输入 pip install pyqt5 下载QT5 当然也可以去Qt的官网的下载 ,使用命令行更快捷方便 所以建议使用命令行 ,去官网下载安装有它的好处就是不用自己安装 toosl 作者使用的是pyCharm 完成后期的后台程序设置,使用pyCharm 外部工具链接把Designer,pyUIC,qrcTopy程序加进去 2、主窗体设置 打Qt5主程序设置主窗体,设计完成保存为windows 添加到创建好的python项目中,然后选中单击右键-》External too
爬取12306中全国的列车时刻表和车站信息
weixin_66326991的博客
07-22 9396
爬取12306全国的列车时刻表和车站信息
python实现12306查票以及购票功能
最新发布
m0_73511684的博客
04-11 1220
用driver来模拟人的操作,对应的账号密码以及身份证号后四位记得改成自己需要的,send_keys函数可以向对应位置填入内容,click函数可以点击对应位置,id需要使用开发者工具自己去找,这一步还需要在控制台中输入手机收到的验证码即可。7.最后就是一路输入出发地目的地,出发时间,然后点击确认即可,值得注意的就是预定那里的点击比较难搞,预定点击的定位方式也有所不同,这个位置是可以用之前result里面的信息通过拼接字符串的方式拼出来,三个列表用来储存查询到的车次的一些信息,方便我们后面执行购票这个操作。
从零开始写python爬虫_从零开始写Python爬虫 --- 爬虫应用: 12306火车票信息查询...
weixin_39616071的博客
12-04 147
好久没更新了,我才不会 告诉你们我沉迷django开发了 话说昨在知乎上看到了这个: 想想自己也有好长时间没有写爬虫了,就去听了一波, 顺便吧这个功能增加到自己的公众号里。 实验楼的代码君小哥哥貌似是第一次直播,还有点小紧张呢!先看一下效果图:说一下实现的原理:其实非常简单,主要是调用了 12306查询接口,得到返回数据后,再格式化输出步骤如下:寻找查询接口理解接口的调用找到调用时的城市名代码编...
python编写12306窗体抢票软件(一)
Jiyinsheng的博客
02-28 4559
python编写12306窗体抢票软件(一) 第一次写博客,拿写过的软件练个手~ 12306是学习爬虫的比较好的一个练手网站。本文带你重零开始编写一个python窗体,十分简单,小白进来看哈~这节只说怎么编写窗体界面,下节介绍12306的登录 准备环境:win10 ,python3.5,pycharm 1.先看下最后成果,能够抢票哦 这是登录界面,用QtDesigner设计的十分方便 这是登录...
pyQt5实时刷新界面例子
热门推荐
岁月静好
01-21 2万+
from PyQt5.QtCore import QThread , pyqtSignal, QDateTime , QObject from PyQt5.QtWidgets import QApplication, QDialog, QLineEdit import time import sys class BackendThread(QObject): # 通过类成员对象定...
python实现好看的GUI界面pyqt5
04-30
本资源基于网络的参考实现了好看的GUI界面,并带有样式截图,下载下来即可看见各种截图和py文件,可直接在python环境运行,基于pyqt5实现
Python Gui编程,PyQt5下载安装教程
03-02
Python Gui编程,PyQt5下载安装教程 Python Gui编程,PyQt5下载安装教程 Python Gui编程,PyQt5下载安装教程 Python Gui编程,PyQt5下载安装教程 Python Gui编程,PyQt5下载安装教程 Python Gui编程,PyQt5下载安装教程 ...
Python3.x+Pyqt5实现界面编程浏览网页
07-05
Python3.x+Pyqt5实现界面编程浏览网页。仔细阅读代码中的注释。里面有3个程序,每个都可以单独运行。
Python3+PyQt5基础:实现QListView搜索过滤及获取多列数据
05-05
具体内容参见我的博文: Python3+PyQt5基础(一)实现QListView搜索过滤问题 https://blog.csdn.net/gui818/article/details/124583708 Python3+PyQt5基础(二)如何通过QListView当前所在行获得其背后的多列信息 ...
12306订票客户端,QT版,代码跨平台
02-09
本想0分,无奈帐号,没分了,唉,希望大家理解,有任何bug请send email即可
pyqt5 的自动化界面开发例子
12-03
本例子,给了一个一个连接数据库,加密,自动化界面生成的案列
基于Qt开发的12306汽车售票系统
07-07
基于Qt平台的简易互联网汽车售票系统,使用MySql数据库开发,编程语言是c++,图形库是Qt界面良好,因为是初学者,所以程序可能有累赘之处,希望和大家一起交流,欢迎指正,共同进步。文件中附有sql文件。
pythonQt Designer 高铁火车票查询工具
zhaochongsi的博客
02-18 776
一、制作UI界面 创建一个widget,从Widget Box工具箱中拖拽3个label、3个line Edit、1个Push Button、1个tableWidget。修改控件名后效果如下图,保存并命名为get_stationtrain.ui Qt Designer工具的使用方法:pythonQt Designer工具的使用方法 get_stationtrain.ui的程序代码如下: <?xml version="1.0" encoding="UTF-8"?> <ui versi
使用超级鹰登录12306网站
m0_56521031的博客
08-16 338
12306网站登录界面:https://kyfw.12306.cn/otn/resources/login.html 代码如下 from selenium.webdriver import Chrome from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.chrome.options import Options from chaojiying import Chaoj.
Python3.8+Qt5.0感知哈希算法实现图像检索系统
zswzjl2009的博客
05-20 467
点击查看:Python3.8+Qt5.0感知哈希算法实现图像检索系统 文件大小:13M 操作系统:Windows10旗舰版 开发工具:Python3.8、Qt5 开发语言:.py 简要概述: 基于感知哈希算法实现图像检索 使用 Python3 & Qt5 实现,其中 UI 部分使用 qt designer 实现 依赖有:imagehash, pyqt5, pillow 命令行输入:python index.py即可运行 ...
【新年返程离不开Python】最新12306抢票源程序Python版就此分享给大家啦!
xiangxueerfei的博客
11-24 646
本代码采用selenium 自动化测试模块,这里用于操作浏览器,就是通过selenium 自动化测试模块让浏览器模拟人来操作浏览器,从而实现购票。本程序操作的chrom浏览器,需要提前下载浏览器驱动chromedriver.exe,浏览器驱动需与浏览器版本一致,并与抢票程序置于同一目录。在chrom浏览器里输入:chrome://version/查看浏览器版本。下载对应用操作系统的,并将浏览器驱动与主程序置于同一目录。
PyQtPython+Qt)学习随笔:QListWidget查找项的findItems方法
老猿Python
02-07 4210
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListWidget列表部件的findItems方法用于查找列表部件是否有满足条件的项,调用语法如下: list findItems( str label, Qt.MatchFlags flag) findItems用于列表部件中查找文本内容与label参数匹配的项,查找过程的匹配模式由fl...
使用pythonQT写一个搜索框功能
qq_44774828的博客
03-29 1416
在本例中,我们将使用Python编写该应用程序,并使用QT库创建GUI界面
pythongui界面编程pyqt
10-14
好的,关于pyqt界面编程,我可以给你一些简单的介绍。 PyQt是一个用于创建GUI应用程序的Python模块,它是基于Qt库的Python接口。PyQt包含了超过620个类和6000个函数和方法,可以用于创建复杂的图形用户界面PyQt...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
167
原创
171
点赞
789
收藏
339
粉丝
关注
私信
写文章

热门文章

  • HttpServletResponse应用(三)sendRedirect()实现请求重定向 12069
  • HttpServletRequest应用——获取请求参数与通过Request对象传递数据 7074
  • JSP概述——什么是JSP、JSP运行原理 6567
  • mybatis-plus 物理删除和逻辑删除 6394
  • java执行cmd命令 5703

分类专栏

  • OSS 1篇
  • CSS
  • VUE 26篇
  • 前端小项目 2篇
  • Mybatis 2篇
  • 编译原理 1篇
  • 前端 1篇
  • Lombok 1篇
  • 软件技巧、教程笔记 3篇
  • 各类异常问题 2篇
  • Python小项目 1篇
  • C 43篇
  • Python 2篇
  • SpringBoot 2篇
  • Mybatis-Plus 11篇
  • Bootstrap5 19篇
  • js 6篇
  • java基础 8篇
  • 计算机操作系统 1篇
  • JavaWeb程序设计 4篇
  • 第三章Servlet基础 5篇
  • 第四章请求和响应 10篇
  • 第五章会话及其会话技术 4篇
  • 第六章JSP技术 4篇
  • 第七章EL表达式和JSTL 2篇

最新评论

  • VUE+EmelentUI实现-OSS前端直传后端签名

    零妖大盗 V8: 大佬,前端源码还在吗

  • 检查宿舍卫生 Time Limit: 1000 ms Memory Limit: 65536 KiB

    181s773: 为什么要int s[101]啊

  • RequestDispatcher对象的应用——RequestDispatcher接口、请求转发、请求包含

    松坡岗: 讲的好不好就看图配的多不多!

  • Mybatis-Plus数据安全保护-及其使用方法

    笑天打七七: 我也试了,不能用

  • Mybatis-Plus数据安全保护-及其使用方法

    心醉瑶瑾前: 写了挺长时间了,都忘了呀表情包

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • Vue3 自动引入组件及函数、动态生成侧边栏路由
  • java执行cmd命令
  • java获取系统变量和环境变量
2023年1篇
2022年33篇
2021年86篇
2020年47篇

目录

目录

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心醉瑶瑾前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值

深圳SEO优化公司德州网站设计模板哪家好鹰潭品牌网站设计多少钱黄冈网页制作公司荆州网络营销永湖建网站哪家好钦州网络营销推荐西安百度关键词包年推广推荐永州网站关键词优化价格连云港网站搜索优化价格海南SEO按天计费多少钱大浪至尊标王哪家好开封网站搭建呼和浩特关键词排名包年推广多少钱观澜SEO按效果付费多少钱榆林设计网站哪家好高端网站设计价格孝感企业网站设计报价鸡西推广网站哪家好宝安百度网站优化排名多少钱咸宁网站关键词优化价格贵港推广网站公司大理外贸网站设计报价许昌百度标王哪家好玉林百度seo公司杭州建设网站阜新网站搭建价格南昌百姓网标王推广推荐长治建网站报价石家庄设计公司网站推荐长沙百度网站优化歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化