教你用python实现12306余票查询


Posted in Python onJune 30, 2021

python实现12306余票查询

我们说先在浏览器中打开开发者工具(F12),尝试一次余票的查询,通过开发者工具查看发出请求的包

教你用python实现12306余票查询

余票查询界面

可以看到红框框中的URL就是我们向12306服务器发出的请求,那么具体是什么呢?我们来看看

[
https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2019-01-21&leftTicketDTO.from_station=CDW&leftTicketDTO.to_station=SZQ&purpose_codes=ADULT](https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2019-01-21&leftTicketDTO.from_station=CDW&leftTicketDTO.to_station=SZQ&purpose_codes=ADULT)

可以看到发出请求的几个字段:

leftTicketDTO.train_date:查询的日期
leftTicketDTO.from_station:查询的出发地
leftTicketDTO.to_station:查询的目的地
purpose_codes:不太清楚这个字段是用来做什么的,就默认吧

可以从我们递交的URL请求看出,我们输入的成都,深圳都变成了对应的编号,比如,成都(CDW)、深圳(SZQ),所以当我们程序进行输入的时候要进行一下处理,12306的一个地方存储着这些城市名与编码对应的文档:

[
https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971](https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971)

教你用python实现12306余票查询

站点编码对应

下面我们就编写一个小程序,将这些城市名与编号提取出来:

import re,requests
    url = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971"
    response = requests.get(url,verify=False)
    #将车站的名字和编码进行提取
    chezhan = re.findall(r'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
    chezhan_code = dict(chezhan)
    #进行交换
    chezhan_names = dict(zip(chezhan_code.values(),chezhan_code.keys()))
    #打印出得到的车站字典
    print(chezhan_names)

得到的打印结果如下(只截取部分显示):

{‘VAP': ‘北京北', ‘BOP': ‘北京东', ‘BJP': ‘北京', ‘VNP': ‘北京南', ‘BXP': ‘北京西', ‘IZQ':
‘广州南', ‘CUW': ‘重庆北', ‘CQW': ‘重庆', ‘CRW': ‘重庆南', ‘CXW': ‘重庆西', ‘GGQ': ‘广州东',
‘SHH': ‘上海', ‘SNH': ‘上海南', ‘AOH': ‘上海虹桥', ‘SXH': ‘上海西', ‘TBP': ‘天津北', ‘TJP':
‘天津', ‘TIP': ‘天津南', ‘TXP': ‘天津西', ‘XJA': ‘香港西九龙', ‘CCT': ‘长春', ‘CET': ‘长春南',
‘CRT': ‘长春西', ‘ICW': ‘成都东', ‘CNW': ‘成都南', ‘CDW': ‘成都', ‘CSQ': ‘长沙', ‘CWQ':
‘长沙南',}

接下来我们就动手开始程序的主要代码编写:

def main():
      date     = input("请输入时间(如2019-01-22):\n")
      from_station = chezhan_code[input("请输入起始站点:\n")]
      to_station  = chezhan_code[input("请输入目的站点:\n")]
      url     = "https://kyfw.12306.cn/otn/leftTicket/queryZ?"
      headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5702.400 QQBrowser/10.2.1893.400"
      }
      url=url+"leftTicketDTO.train_date="+date+"&leftTicketDTO.from_station="+from_station+"&leftTicketDTO.to_station="+to_station+"&purpose_codes=ADULT"
      #print(url) 已经检查过生成的URL是正确的
      #request请求获取主页
      r = requests.get(url,headers=headers)
      r.raise_for_status()  #如果发送了一个错误的请求,会抛出异常
      r.encoding = r.apparent_encoding
      showTicket(r.text)

用户输入时间、起始站点、目的站点,然后通过get来请求,然后我们对返回的网页信息进行解析。我们现将上面代码的r.text进行打印,看看我们请求之后,返回了什么样的信息,然后决定我们应该如何解析

教你用python实现12306余票查询

运行结果

这样看着不方便,我们粘贴到记事本中,进行详细的分析:

教你用python实现12306余票查询

请求返回的结果信息

可以与12306显示的信息进行对比,K829是车次,CDW与BJQ是出发地和目的地,10:10是出发时间,06:13是到达时间,44:21是历时时间,20190123为查询的日期,剩下的就是一系列票的各种信息。

下面就是对这些返回的信息进行解析,其实这也是python爬虫的关键,就是解析!!!

我们先把信息转化为json格式,可以看到都是用“|”隔开的,那么我们就用split函数分割出来,下面是主要功能代码:

def showTicket(html):
      html = json.loads(html)
      table = PrettyTable([" 车次 ","出发车站","到达车站","出发时间","到达时间"," 历时 ","商务座"," 一等座","二等座","高级软卧","软卧","动卧","硬卧","软座","硬座","无座","其他","备注"])
      for i in html['data']['result']:
        name = [
              "station_train_code",
              "from_station_name",
              "to_station_name",
              "start_time",
              "arrive_time",
              "lishi",
              "swz_num",
              "zy_num",
              "ze_num",
              "dw_num",
              "gr_num",
              "rw_num",
              "yw_num",
              "rz_num",
              "yz_num",
              "wz_num",
              "qt_num",
              "note_num"
            ]
        data = {
              "station_train_code": '',
              "from_station_name": '',
              "to_station_name": '',
              "start_time": '',
              "arrive_time": '',
              "lishi": '',
              "swz_num": '',
              "zy_num": '',
              "ze_num": '',
              "dw_num": '',
              "gr_num": '',
              "rw_num": '',
              "yw_num": '',
              "rz_num": '',
              "yz_num": '',
              "wz_num": '',
              "qt_num": '',
              "note_num": ''
            }
        #将各项信息提取并赋值
        item = i.split('|')                 #使用“|”进行分割
        data["station_train_code"] = item[3]        #获取车次信息,在3号位置
        data["from_station_name"]  = item[6]        #始发站信息在6号位置
        data["to_station_name"]   = item[7]        #终点站信息在7号位置
        data["start_time"]     = item[8]        #出发时间在8号位置
        data["arrive_time"]     = item[9]        #抵达时间在9号位置
        data["lishi"]        = item[10]       #经历时间在10号位置
        data["swz_num"]       = item[32] or item[25] #特别注意,商务座在32或25位置
        data["zy_num"]       = item[31]       #一等座信息在31号位置
        data["ze_num"]       = item[30]       #二等座信息在30号位置
        data["gr_num"]       = item[21]       #高级软卧信息在21号位置
        data["rw_num"]       = item[23]       #软卧信息在23号位置
        data["dw_num"]       = item[27]       #动卧信息在27号位置
        data["yw_num"]       = item[28]       #硬卧信息在28号位置
        data["rz_num"]       = item[24]       #软座信息在24号位置
        data["yz_num"]       = item[29]       #硬座信息在29号位置
        data["wz_num"]       = item[26]       #无座信息在26号位置
        data["qt_num"]       = item[22]       #其他信息在22号位置
        data["note_num"]      = item[1]        #备注信息在1号位置
        color = Colored()
        data["note_num"] = color.white(item[1])
        #如果没有信息,那么就用“-”代替
        for pos in name:
          if data[pos] == "":
            data[pos] = "-"
        tickets = []
        cont = []
        cont.append(data)
        for x in cont:
          tmp = []
          for y in name:
            if y == "from_station_name":
              s = color.green(chezhan_names[data["from_station_name"]])
              tmp.append(s)
            elif y == "to_station_name":
              s = color.red(chezhan_names[data["to_station_name"]])
              tmp.append(s)
            elif y == "start_time":
              s = color.green(data["start_time"])
              tmp.append(s)
            elif y == "arrive_time":
              s = color.red(data["arrive_time"])
              tmp.append(s)
            elif y == "station_train_code":
              s = color.yellow(data["station_train_code"])
              tmp.append(s)
            else:
              tmp.append(data[y])
          tickets.append(tmp)
        for ticket in tickets:
          table.add_row(ticket)
      print(table)

那么我们程序就成功啦!!!

教你用python实现12306余票查询

运行结果

但是在编译器里面Prettytable的格子没有对齐,不要担心,我们到终端运行一下脚本,就可以看到很好看的输出啦:

教你用python实现12306余票查询

终端运行结果

教你用python实现12306余票查询

完成!!!下面是完整代码

main.py

# -*- coding: utf-8 -*-
    import re,requests,datetime,time,json
    from prettytable import PrettyTable
    from colorama import init,Fore
    from stationinfo import chezhan_code,chezhan_names
    init(autoreset=False)
    class Colored(object):
      def yeah(self,s):
        return Fore.LIGHTCYAN_EX + s + Fore.RESET
      def green(self,s):
        return Fore.LIGHTGREEN_EX + s + Fore.RESET
      def yellow(self,s):
        return Fore.LIGHTYELLOW_EX + s + Fore.RESET
      def white(self,s):
        return Fore.LIGHTWHITE_EX + s + Fore.RESET
      def blue(self,s):
        return Fore.LIGHTBLUE_EX + s + Fore.RESET
    def showTicket(html):
      html = json.loads(html)
      table = PrettyTable([" 车次 ","出发车站","到达车站","出发时间","到达时间"," 历时 ","商务座"," 一等座","二等座","高级软卧","软卧","动卧","硬卧","软座","硬座","无座","其他","备注"])
      for i in html['data']['result']:
        name = [
              "station_train_code",
              "from_station_name",
              "to_station_name",
              "start_time",
              "arrive_time",
              "lishi",
              "swz_num",
              "zy_num",
              "ze_num",
              "dw_num",
              "gr_num",
              "rw_num",
              "yw_num",
              "rz_num",
              "yz_num",
              "wz_num",
              "qt_num",
              "note_num"
            ]
        data = {
              "station_train_code": '',
              "from_station_name": '',
              "to_station_name": '',
              "start_time": '',
              "arrive_time": '',
              "lishi": '',
              "swz_num": '',
              "zy_num": '',
              "ze_num": '',
              "dw_num": '',
              "gr_num": '',
              "rw_num": '',
              "yw_num": '',
              "rz_num": '',
              "yz_num": '',
              "wz_num": '',
              "qt_num": '',
              "note_num": ''
            }
        #将各项信息提取并赋值
        item = i.split('|')                 #使用“|”进行分割
        data["station_train_code"] = item[3]        #获取车次信息,在3号位置
        data["from_station_name"]  = item[6]        #始发站信息在6号位置
        data["to_station_name"]   = item[7]        #终点站信息在7号位置
        data["start_time"]     = item[8]        #出发时间在8号位置
        data["arrive_time"]     = item[9]        #抵达时间在9号位置
        data["lishi"]        = item[10]       #经历时间在10号位置
        data["swz_num"]       = item[32] or item[25] #特别注意,商务座在32或25位置
        data["zy_num"]       = item[31]       #一等座信息在31号位置
        data["ze_num"]       = item[30]       #二等座信息在30号位置
        data["gr_num"]       = item[21]       #高级软卧信息在21号位置
        data["rw_num"]       = item[23]       #软卧信息在23号位置
        data["dw_num"]       = item[27]       #动卧信息在27号位置
        data["yw_num"]       = item[28]       #硬卧信息在28号位置
        data["rz_num"]       = item[24]       #软座信息在24号位置
        data["yz_num"]       = item[29]       #硬座信息在29号位置
        data["wz_num"]       = item[26]       #无座信息在26号位置
        data["qt_num"]       = item[22]       #其他信息在22号位置
        data["note_num"]      = item[1]        #备注信息在1号位置
        color = Colored()
        data["note_num"] = color.white(item[1])
        #如果没有信息,那么就用“-”代替
        for pos in name:
          if data[pos] == "":
            data[pos] = "-"
        tickets = []
        cont = []
        cont.append(data)
        for x in cont:
          tmp = []
          for y in name:
            if y == "from_station_name":
              s = color.green(chezhan_names[data["from_station_name"]])
              tmp.append(s)
            elif y == "to_station_name":
              s = color.yeah(chezhan_names[data["to_station_name"]])
              tmp.append(s)
            elif y == "start_time":
              s = color.green(data["start_time"])
              tmp.append(s)
            elif y == "arrive_time":
              s = color.yeah(data["arrive_time"])
              tmp.append(s)
            elif y == "station_train_code":
              s = color.yellow(data["station_train_code"])
              tmp.append(s)
            else:
              tmp.append(data[y])
          tickets.append(tmp)
        for ticket in tickets:
          table.add_row(ticket)
      print(table)
    def main():
      date     = input("请输入时间:\n")
      from_station = chezhan_code[input("请输入起始站点:\n")]
      to_station  = chezhan_code[input("请输入目的站点:\n")]
      url     = "https://kyfw.12306.cn/otn/leftTicket/queryZ?"
      headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.5702.400 QQBrowser/10.2.1893.400"
      }
    url=url+"leftTicketDTO.train_date="+date+"&leftTicketDTO.from_station="+from_station+"&leftTicketDTO.to_station="+to_station+"&purpose_codes=ADULT"
      #print(url) 已经检查过生成的URL是正确的
      #request请求获取主页
      r = requests.get(url,headers=headers)
      r.raise_for_status()  #如果发送了一个错误的请求,会抛出异常
      r.encoding = r.apparent_encoding
      showTicket(r.text)
      #print(r.text)
    main()

stationinfo.py

import re,requests
    url = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.8971"
    response = requests.get(url,verify=False)
    #将车站的名字和编码进行提取
    chezhan = re.findall(r'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
    chezhan_code = dict(chezhan)
    chezhan_names = dict(zip(chezhan_code.values(),chezhan_code.keys()))
    #print(chezhan_names)

到此这篇关于教你用python实现12306余票查询的文章就介绍到这了,更多相关python实现12306余票查询内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python3中多线程编程的队列运作示例
Apr 16 Python
详解python 字符串和日期之间转换 StringAndDate
May 04 Python
tensorflow实现KNN识别MNIST
Mar 12 Python
Python实现重建二叉树的三种方法详解
Jun 23 Python
python 实现读取一个excel多个sheet表并合并的方法
Feb 12 Python
Python神奇的内置函数locals的实例讲解
Feb 22 Python
python函数装饰器之带参数的函数和带参数的装饰器用法示例
Nov 06 Python
Python 函数绘图及函数图像微分与积分
Nov 20 Python
详解python环境安装selenium和手动下载安装selenium的方法
Mar 17 Python
Python多线程threading创建及使用方法解析
Jun 17 Python
python 决策树算法的实现
Oct 09 Python
python Polars库的使用简介
Apr 21 Python
python实现简易自习室座位预约系统
如何用Python搭建gRPC服务
python not运算符的实例用法
Jun 30 #Python
pycharm部署django项目到云服务器的详细流程
Python快速实现一键抠图功能的全过程
总结python多进程multiprocessing的相关知识
Jun 29 #Python
python 字典和列表嵌套用法详解
Jun 29 #Python
You might like
层叠菜单的动态生成
2006/10/09 PHP
PHP实现将浏览历史页面网址保存到cookie的方法
2015/01/26 PHP
详解WordPress中添加和执行动作的函数使用方法
2015/12/29 PHP
php使用正则验证中文
2016/04/06 PHP
php写app接口并返回json数据的实例(分享)
2017/05/20 PHP
PHP迭代器和迭代的实现与使用方法分析
2018/04/19 PHP
TP3.2.3框架文件上传操作实例详解
2020/01/23 PHP
PHP Trait功能与用法实例分析
2020/06/03 PHP
TP5多入口设置实例讲解
2020/12/15 PHP
javascript在事件监听方面的兼容性小结
2010/04/07 Javascript
jQuery回车实现登录简单实现
2013/08/20 Javascript
js数组去重的5种算法实现
2015/11/04 Javascript
JS如何判断是否为ie浏览器的方法(包括IE10、IE11在内)
2015/12/13 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
2016/05/16 Javascript
Javascript简写条件语句(推荐)
2016/06/12 Javascript
关于Node.js中Buffer的一些你可能不知道的用法
2017/03/28 Javascript
AngularJS实现动态添加Option的方法
2017/05/17 Javascript
jQuery实现的简单日历组件定义与用法示例
2018/12/24 jQuery
vue2.0结合Element-ui实战案例
2019/03/06 Javascript
javascript 关于赋值、浅拷贝、深拷贝的个人理解
2019/11/01 Javascript
小程序实现背景音乐播放和暂停
2020/06/19 Javascript
在Django中使用Sitemap的方法讲解
2015/07/22 Python
在pycharm中使用git版本管理以及同步github的方法
2019/01/16 Python
Flask教程之重定向与错误处理实例分析
2019/08/01 Python
python中的反斜杠问题深入讲解
2019/08/12 Python
Python中lru_cache的使用和实现详解
2021/01/25 Python
css3学习心得分享
2013/08/19 HTML / CSS
澳大利亚男士西服品牌:M.J.Bale
2018/02/06 全球购物
行政主管岗位职责
2013/11/18 职场文书
《乡下孩子》教学反思
2014/04/17 职场文书
项目合作协议书
2014/09/23 职场文书
2014年酒店前台工作总结
2014/11/14 职场文书
2015年度高中教师工作总结
2015/05/26 职场文书
城南旧事电影观后感
2015/06/16 职场文书
职位证明模板
2015/06/23 职场文书
创业计划书之网吧
2019/10/10 职场文书