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

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

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

    548 引用 • 674 回帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Notion

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

    10 引用 • 76 回帖
  • 分享

    有什么新发现就分享给大家吧!

    247 引用 • 1793 回帖
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 425 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    113 引用 • 767 回帖
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 1 关注
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 494 关注
  • OpenCV
    15 引用 • 36 回帖
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 170 关注
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 184 关注
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 600 关注
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    77 引用 • 389 回帖
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖 • 6 关注
  • sts
    2 引用 • 2 回帖 • 203 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 3 关注
  • 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.

    6 引用 • 63 回帖 • 10 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 650 关注
  • OneNote
    1 引用 • 3 回帖
  • Excel
    31 引用 • 28 回帖
  • Openfire

    Openfire 是开源的、基于可拓展通讯和表示协议 (XMPP)、采用 Java 编程语言开发的实时协作服务器。Openfire 的效率很高,单台服务器可支持上万并发用户。

    6 引用 • 7 回帖 • 101 关注
  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 263 关注
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    41 引用 • 130 回帖 • 253 关注
  • Visio
    1 引用 • 2 回帖 • 1 关注
  • 导航

    各种网址链接、内容导航。

    43 引用 • 177 回帖 • 3 关注
  • 职场

    找到自己的位置,萌新烦恼少。

    126 引用 • 1706 回帖
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖