使用 Python 在 12306 查询火车票余票

本贴最后更新于 2139 天前,其中的信息可能已经事过景迁

实现原理比较简单,就是调用 12306 的查票接口获取 json 数据再重新组装,取出合适的数据。配合发送邮件模块,就能实现实时获取余票数据。

由于发现 12306 经常进行查票接口部分参数的更换,下面就以谷歌浏览器为例寻找一个查票接口:

如图,在谷歌浏览器的调试窗口 network 标签页下点击网页上的查询按钮可以看到一个 get 请求,其请求的数据就是我们需要的 json 数据。

QQ20181015235126png

看一下原生数据,在浏览器中打开这个链接:

imagepng

包含了我们需要的数据
再看一下这个链接:https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date=2018-10-17&leftTicketDTO.from_station=BJP&leftTicketDTO.to_station=KMM&purpose_codes=ADULT (会存在变动,非实时可用)

可以看出需要我们传递三个参数:

查询日期,如:2018-10-17
出发地火车站电报码,如:BJP (北京)
到达地火车站电报码,如:KMM (昆明)

不知道电报码的话百度一下就 ok 了。

好,现在就处理数据,看代码:
我们需要循环遍历每辆车的信息,原始数据 result 中每一条就是一个车次信息,其间采用竖线分隔。
使用 python 取子串获取的信息如下:

  item = {}
  # 循环遍历每辆列车的信息
  data_list = raw_train.split('|')

  train_type = data_list[3][0]
  print data_list
  
  # 车次号码
  item['train_no'] = data_list[3]
  # 出发站
  from_station_code = data_list[6]
  item['from_station_name'] = stations_list[from_station_code]
  # 终点站
  to_station_code = data_list[7]
  item['to_station_name'] = stations_list[to_station_code]
  # 出发时间
  item['start_time'] = data_list[8]
  # 到达时间
  item['arrive_time'] = data_list[9]
  # 总耗时
  item['time_fucked_up'] = data_list[10]
  # 商务特等
  item['business_class_seat'] = data_list[25] or '--'
  # 一等座
  item['first_class_seat'] = data_list[31] or '--'
  # 二等座
  item['second_class_seat'] = data_list[30] or '--'
  print item['second_class_seat']
  # 软卧
  item['soft_sleep'] = data_list[23] or '--'
  # 硬卧
  item['hard_sleep'] = data_list[28] or '--'
  # 硬座
  item['hard_seat'] = data_list[29] or '--'
  # 无座
  item['no_seat'] = data_list[26] or '--'

代码就自己看吧,很简单的 python 基础。

经过简单的组装,就得到了简单的示例程序,下面是完整代码:

# coding=utf-8

from time import sleep
import datetime
import requests

import smtplib
from email.mime.text import MIMEText
import sys

reload(sys)

sys.setdefaultencoding('utf-8')

def query_trains(data):
    url = 'https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date={}&leftTicketDTO.from_station={}&leftTicketDTO.to_station={}&purpose_codes=ADULT'.format(
        data.date, data.form, data.to
    )
    jsondata = ""
  #print requests.get(url).text
  while jsondata=="" or jsondata==None:
        try:
            print(url)
            print("try get json")
            jsondata = requests.get(url).json()
           # print jsondata
  except:
            jsondata = ""
  print("get json error")
            sleep(7)
    return jsondata

def sort_trains(raw,data):
    flag=0
  for_sale = []
    not_for_sale = []
    raw_trains = raw['data']['result']
    stations_list = raw['data']['map']
    content = "有新的车票啦!!\r\n车票信息如下:\r\n-------------------------\r\n"
  content+="运行区间:"+stations_list[data.form]+"---"+stations_list[data.to]+"---"+data.date+"\r\n"

  for i in raw_trains:
        train_data=i.split("|")

        if int(str(train_data[8])[0:2])<18 and int(str(train_data[8])[0:2])>0: #查找下午18点以前的火车

  if train_data[0]=="":
               print str(train_data[3]+"--"+train_data[8]+"-"+train_data[10]+"-已售空")

            else:

                if train_data[26] != "" and train_data[26]!="无":  # 无座
  # print(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] +  "-"+train_data[26])+ "-无座有票")
  content+=(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] +  "-"+train_data[26])+ "-无座有票"+"\r\n")
                    flag = 1

  if train_data[29] != "" and train_data[29]!="无":  # 硬座
  # print(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] +  "-"+train_data[29])+ "-硬座有票")
  content +=(str(train_data[3] + "--" + train_data[8] + "-" + train_data[10] +  "-"+train_data[29])+ "-硬座有票"+"\r\n")
                    flag = 1

  if train_data[30]!="" and train_data[30]!="无":  #二等座
  # print(str(train_data[3]+"--"+train_data[8]+"-"+train_data[10]+  "-"+train_data[30]) + "-二等座有票")
  content +=(str(train_data[3]+"--"+train_data[8]+"-"+train_data[10]+  "-"+train_data[30]) + "-二等座有票"+"\r\n")
                    flag = 1

  content+="-------------------------\n"
  content += "时间:"+datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')+"\r\n"
  content += "Powered By:xynling"

  if flag==1:
        print content

class TrainData:
    def __init__(self,form,to,date):
        self.form = form
        self.to=to
        self.date=date

def main():
  while True:
        if (int(datetime.datetime.now().strftime('%H'))>=6):
            td=TrainData('BJP','KMM','2018-10-17')
            sort_trains(query_trains(td),td)
            sleep(30) #休眠30s继续执行
  else:
            print(int(datetime.datetime.now().strftime('%H')))
            sleep(5)

if __name__ == '__main__':
    main()

是循环 30 秒进行查询的。

查询结果如图:

imagepng

结合邮箱进行微信提醒:

imagepng

如果放在服务器上运行就能很方便的收到车票提醒啦!

实现原理部分摘自网络,文章原创,转载请注明转载自 ynlflixin 的个人博客!

😄

  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    540 引用 • 672 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 1 关注
  • 安装

    你若安好,便是晴天。

    131 引用 • 1184 回帖 • 1 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 22 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 457 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    4 引用 • 7 回帖 • 2 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    163 引用 • 473 回帖
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    54 引用 • 85 回帖
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 401 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    21 引用 • 140 回帖 • 2 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 1 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    138 引用 • 268 回帖 • 102 关注
  • 强迫症

    强迫症(OCD)属于焦虑障碍的一种类型,是一组以强迫思维和强迫行为为主要临床表现的神经精神疾病,其特点为有意识的强迫和反强迫并存,一些毫无意义、甚至违背自己意愿的想法或冲动反反复复侵入患者的日常生活。

    15 引用 • 161 回帖
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 31 关注
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    19 引用 • 7 回帖 • 3 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 615 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 42 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    487 引用 • 908 回帖
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 621 关注
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    5 引用 • 26 回帖
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    28 引用 • 66 回帖 • 1 关注
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    43 引用 • 208 回帖
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    11 引用 • 54 回帖 • 146 关注
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    5 引用 • 62 回帖 • 10 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    19 引用 • 31 回帖
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    75 引用 • 258 回帖 • 634 关注
  • danl
    98 关注