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

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

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

    543 引用 • 672 回帖 • 1 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 5 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖 • 2 关注
  • 导航

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

    40 引用 • 173 回帖 • 1 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 52 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖 • 1 关注
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    167 引用 • 1513 回帖
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖 • 1 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3453 回帖 • 203 关注
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    5 引用 • 26 回帖 • 530 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    408 引用 • 3575 回帖 • 1 关注
  • Latke

    Latke 是一款以 JSON 为主的 Java Web 框架。

    71 引用 • 535 回帖 • 787 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 673 关注
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖 • 1 关注
  • SendCloud

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

    2 引用 • 8 回帖 • 483 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 1 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 362 关注
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 134 关注
  • 分享

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

    248 引用 • 1794 回帖
  • OnlyOffice
    4 引用 • 3 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 511 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 65 关注
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 41 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    153 引用 • 3783 回帖 • 1 关注
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 764 关注
  • Maven

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

    186 引用 • 318 回帖 • 304 关注
  • JVM

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

    180 引用 • 120 回帖 • 2 关注