教你用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实现模拟登录及表单提交的方法
Jul 25 Python
python访问mysql数据库的实现方法(2则示例)
Jan 06 Python
Python深入06——python的内存管理详解
Dec 07 Python
Python调用C# Com dll组件实战教程
Oct 12 Python
Python编程django实现同一个ip十分钟内只能注册一次
Nov 03 Python
浅谈python中的占位符
Nov 09 Python
Python给你的头像加上圣诞帽
Jan 04 Python
python thrift搭建服务端和客户端测试程序
Jan 17 Python
Python中常见的异常总结
Feb 20 Python
对Python的zip函数妙用,旋转矩阵详解
Dec 13 Python
Python可以实现栈的结构吗
May 27 Python
PyQt5实现画布小程序
May 30 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 压缩文件夹的类代码
2009/11/05 PHP
PHP 计算代码执行耗时的代码修正网上普遍错误
2011/05/14 PHP
php函数与传递参数实例分析
2014/11/15 PHP
PHP将Excel导入数据库及数据库数据导出至Excel的方法
2015/06/24 PHP
CI框架无限级分类+递归的实现代码
2016/11/01 PHP
PHP实现中国公民身份证号码有效性验证示例代码
2017/05/03 PHP
PHP基于ORM方式操作MySQL数据库实例
2017/06/21 PHP
[Web]防止用户复制页面内容和另存页面的方法
2009/02/06 Javascript
JavaScript学习点滴 call、apply的区别
2010/10/22 Javascript
javascript for循环从入门到偏门(效率优化+奇特用法)
2012/08/01 Javascript
Javascript 多浏览器兼容总结(实战经验)
2013/10/30 Javascript
基于javascript实现右下角浮动广告效果
2016/01/08 Javascript
jquery form表单获取内容以及绑定数据
2016/02/24 Javascript
Bootstrap禁用响应式布局的实现方法
2017/03/09 Javascript
JS实现直接运行html代码的方法
2017/03/13 Javascript
Angular使用 ng-img-max 调整浏览器中的图片的示例代码
2017/08/17 Javascript
vue2实现搜索结果中的搜索关键字高亮的代码
2018/08/29 Javascript
vue中node_modules中第三方模块的修改使用详解
2019/05/31 Javascript
解决layui的form里的元素进行动态生成,验证失效的问题
2019/09/14 Javascript
Vue退出登录时清空缓存的实现
2019/11/12 Javascript
Vue实现图片轮播组件思路及实例解析
2020/05/11 Javascript
python双向链表实现实例代码
2013/11/21 Python
基于Python实现的扫雷游戏实例代码
2014/08/01 Python
Python函数中的函数(闭包)用法实例
2016/03/15 Python
Python贪吃蛇游戏编写代码
2020/10/26 Python
python pandas.DataFrame选取、修改数据最好用.loc,.iloc,.ix实现
2018/06/11 Python
浅谈Python中的异常和JSON读写数据的实现
2020/02/27 Python
一文轻松掌握python语言命名规范规则
2020/06/18 Python
Python+Dlib+Opencv实现人脸采集并表情判别功能的代码
2020/07/01 Python
Pycharm2020最新激活码|永久激活(附最新激活码和插件的详细教程)
2020/09/29 Python
元旦晚会活动总结
2014/07/09 职场文书
工作态度不好检讨书
2015/05/06 职场文书
债务纠纷起诉书
2015/05/20 职场文书
铁人纪念馆观后感
2015/06/16 职场文书
python实现A*寻路算法
2021/06/13 Python
常用的MongoDB查询语句的示例代码
2021/07/25 MongoDB