教你用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 相关文章推荐
Python的Flask框架与数据库连接的教程
Apr 20 Python
django实现登录时候输入密码错误5次锁定用户十分钟
Nov 05 Python
python+pillow绘制矩阵盖尔圆简单实例
Jan 16 Python
利用scrapy将爬到的数据保存到mysql(防止重复)
Mar 31 Python
flask-socketio实现WebSocket的方法
Jul 31 Python
Selenium chrome配置代理Python版的方法
Nov 29 Python
python 列表输出重复值以及对应的角标方法
Jun 11 Python
python将类似json的数据存储到MySQL中的实例
Jul 12 Python
python中列表的切片与修改知识点总结
Jul 23 Python
python3中的eval和exec的区别与联系
Oct 10 Python
用什么库写 Python 命令行程序(示例代码详解)
Feb 20 Python
Python字符串的15个基本操作(小结)
Feb 03 Python
python实现简易自习室座位预约系统
如何用Python搭建gRPC服务
python not运算符的实例用法
Jun 30 #Python
pycharm部署django项目到云服务器的详细流程
Python快速实现一键抠图功能的全过程
总结python多进程multiprocessing的相关知识
Jun 29 #Python
python 字典和列表嵌套用法详解
Jun 29 #Python
You might like
PHP生成便于打印的网页
2006/10/09 PHP
一个取得文件扩展名的函数
2006/10/09 PHP
php中的注释、变量、数组、常量、函数应用介绍
2012/11/16 PHP
解析在zend Farmework下如何创立一个FORM表单
2013/06/28 PHP
解析数组非数字键名引号的必要性
2013/08/09 PHP
php判断对象是派生自哪个类的方法
2015/06/20 PHP
yii 框架实现按天,月,年,自定义时间段统计数据的方法分析
2020/04/04 PHP
各种常用浏览器getBoundingClientRect的解析
2009/05/21 Javascript
Javascript前端UI框架Kit使用指南之kitjs事件管理
2014/11/28 Javascript
JavaScript检测实例属性, 原型属性
2015/02/04 Javascript
jQuery中通过ajax的get()函数读取页面的方法
2016/02/29 Javascript
JavaScript模板引擎Template.js使用详解
2016/12/15 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
2017/01/05 Javascript
JS实现的点击表头排序功能示例
2017/03/27 Javascript
bootstrap时间控件daterangepicker使用方法及各种小bug修复
2017/10/25 Javascript
ligerUI---ListBox(列表框可移动的实例)
2017/11/28 Javascript
vue-cli项目中使用echarts图表实例
2018/10/22 Javascript
JQuery实现ajax请求的示例和注意事项
2018/12/10 jQuery
详解vuex的简单todolist例子
2019/07/14 Javascript
通过js实现压缩图片上传功能
2020/02/25 Javascript
JavaScript代理模式原理与用法实例详解
2020/03/10 Javascript
js+canvas实现刮刮奖功能
2020/09/13 Javascript
python访问纯真IP数据库的代码
2011/05/19 Python
Python字典操作简明总结
2015/04/13 Python
python实现多层感知器
2019/01/18 Python
如何使用Python发送HTML格式的邮件
2020/02/11 Python
使用Python制作一盏 3D 花灯喜迎元宵佳节
2021/02/26 Python
快速创建 HTML5 Canvas 电信网络拓扑图的示例代码
2018/03/21 HTML / CSS
英国手工布艺沙发在线购买:Sofas & Stuff
2018/03/02 全球购物
新加坡一家在线男士皮具品牌:Faire Leather Co.
2019/12/01 全球购物
Linux如何为某个操作添加别名
2013/03/01 面试题
校园奶茶店创业计划书
2014/01/23 职场文书
群众路线教育实践活动对照检查材料
2014/09/22 职场文书
2014年保险公司工作总结
2014/11/22 职场文书
赢在执行观后感
2015/06/16 职场文书
话题作文之自信作文
2019/11/15 职场文书