作为一名编程新手的项目,其内容正在不断充实之中,欢迎提出Issue,同时也非常期待您的Star。
这个项目的函数包装几乎不存在,我已经忍不了半年前写出来的史山了
这篇文档比较详细,快速上手建议阅读简明指南。
联网导入 数据管理
按车次查询 按站点查询 按起止站查询
跳转和回溯 补充说明
自动接入12306,以列车字头为单元爬取时刻表。默认读取查询当天的车次,如果要更改查询日期,请参照第2节。
命令格式为Import加车次头。纯数字用P代替。可以多个车次头连续,如Import GDC
自2025年2月21日更新之后,联网导入采用了多线程操作,请留意请求被拒绝的次数和导入之后的车次总量情况。你也可以在原有命令之后加上一个数字1或2指定模式,如Import A 1,Import GDC 2,用降低请求速度的方式降低反爬可能性。
需要说明的是,有部分车次的时刻表无法通过时刻表查询得到,大约占全部的2-3%。这些车次大部分实际上确实会开行,但是直接从12306主页搜索框里却无法得到存储其时刻表的url,范围不定,原因未知,暂无修复思路。
联网导入时,开启网络代理服务可能会导致异常的中断。
Sample input #1
Import PZTK
# 纯数字和Z、T、K字头
Import A
# 一次导入G/D/C/K/T/Z/S/Y/纯数字
Sample output #1
Starting threads...
0 / 531 0 success, 0 failed
41 / 531 41 success, 0 failed
88 / 531 88 success, 0 failed
...
527 / 531 527 success, 0 failed
531 / 531 531 success, 0 failed
------------------------------------------------------------
Train sum: 15154 ( 10484 )
G prefix 5523 ( 3943 )
D prefix 3394 ( 2229 )
C prefix 3034 ( 2431 )
Z prefix 311 ( 201 )
T prefix 213 ( 150 )
K prefix 1941 ( 1305 )
S prefix 807 ( 783 )
Y prefix 14 ( 5 )
Pure number 329 ( 262 )
# 导入后共有15154条车次信息,去除车次切换和当日不开行后是10484条
这是正常导入。
下面则是被12306反爬的情况,数据总览中带有 ? 的行表示导入出现了错误(按照数量简单判断)。可能还会伴随着一些请求超时的控制台报错。遇到这种情况,说明此次爬取结果无效,建议不要保存。12306的反爬机制难以捉摸,有时仅仅爬取十几条 Y 字头车次的数据就会触发反爬,而有时连续爬取数千条 G、D、C 字头车次的数据却能顺利完成。
Sample output #2
Input instruction: import a
0 / 531 0 success, 0 failed
61 / 531 61 success, 0 failed
75 / 531 75 success, 0 failed
83 / 531 83 success, 0 failed
...
211 / 531 209 success, 2 failed: C98 G76
248 / 531 242 success, 6 failed: T2 Z8 K12 Z7 C98 ...
267 / 531 243 success, 24 failed: C48 S89 G17 S52 D67 ...
...
------------------------------------------------------------
Train sum: 9280 ( 6568 )
? G prefix 2460 ( 1801 )
? D prefix 2254 ( 1575 )
? C prefix 2752 ( 1834 )
? Z prefix 165 ( 99 )
? T prefix 39 ( 27 )
? K prefix 740 ( 435 )
? S prefix 691 ( 655 )
Y prefix 10 ( 4 )
? Pure number 169 ( 138 )
如果一直被反爬,可以考虑更改请求中的User-Agent设置。
你可以从源代码层面去修改,把headers中的User-Agent替换成自己浏览器的即可(我用的是我自己电脑上的Firefox),也可以输入命令agent,然后输入新的User-Agent。
从12306上导入数据很费时间,而且由于12306的反爬机制,短时间内请求次数过多可能导致得不到数据,因此建议每次运行程序时先读取,每次导入之后都保存。
保存数据的命令为Save,读取数据的命令为Load。
在测试程序的时候你也可以读取我已经导入的数据。例如,仓库中train_data/no_list20250223.json和train_data/train_list20250223.json两个文件包括了2025年2月23日的全部车次数据(其他几个日期的数据可能并不完整)。
本工具并不支持直接处理归属于不同日期的数据,但是可以采用下面给出的间接办法。
按照2025-01-01的格式输入一个日期,或者先输入命令Time或Date再输入日期,可以更改日期设置。
数据管理的底层逻辑是这样的:每次使用命令Load,就是把运行内存中的数据完全同步为当前时间设置指向的外部数据,而命令Save则会按当前时间设置把数据保存。
如果存在更改后日期的数据包,更改日期之后会自动读取。
输入命令Sum,可以总览目前数据库中的车次。这个命令也会在Load之后自动调用,方便了解目前数据库中已经包含了哪些字头的车次数据,如果有需要再导入新的。
Sample input & output
Welcome to the Rail Rhythm railway timetable query tool
Current date setting: 2025-02-15
# 更改日期设置,自动读取
Input instruction: 2025-02-23
Date has been changed from 2025-02-15 to 2025-02-23
Load over
Train sum: 15504 ( 11914 )
G prefix 5548 ( 4280 )
D prefix 3300 ( 2486 )
C prefix 3034 ( 2431 )
Z prefix 311 ( 201 )
T prefix 213 ( 150 )
K prefix 1941 ( 1305 )
S prefix 807 ( 783 )
Y prefix 14 ( 8 )
Pure number 336 ( 270 )
# 可以看到所有类型车次数量都在正常范围,显然成功导入了
# 两列数字,分别是在重复和不重复计算车次变更下的计数
按车次查询,即输入车次,查询经过的车站及各站时刻。提供以下两种输入的格式。
- 输入
Code,间隔一个空格,再加车次号 - 输入
.后紧跟车次号
Sample input #1
Code C2025
Sample output #1
C2025 高速 北京南 - 天津
01 北京南 ---- 18:47
02 亦庄 18:57 18:59 2'
03 武清 19:15 19:20 5'
04 天津 19:34 ----
# 每一行依次显示序号、站名、到点、开点、停站时间
Sample input #2
.Z33
Sample output #2
Z32 / Z33 直特 宁波 - 武昌
01 宁波 ---- 21:03
02 余姚 21:40 21:44 4'
03 绍兴 22:24 22:28 4'
04 诸暨 23:21 23:24 3' switch to Z33
05 金华 00:13 00:20 7' Day 2
06 黄石 05:29 05:38 9' switch to Z32
07 鄂州 05:53 06:06 13'
08 武昌 06:55 ----
# 由于存在上下行切换,车次有两个。在最后还可以看到车次切换和日期变化
查询经停一个车站的所有车次信息,按开点排序(终到车按到点计)。同样也有两种输入的格式。
Station加一个空格,后随站点中文名(不带“站”字)- 直接输入站点中文名(带“站”字)
如果要对车次的方向、性质进行筛选,需要在上面的基础上,后加一个+符号,然后再输入关键字。关键字和筛选条件的对应关系如下。
st始发ed终到ps中间经停dn下行,即车次尾号奇数up上行,即车次尾号偶数
如果要对车次的类型进行筛选,需要在最后加一个*,后加一个或多个字头(纯数字车次用P表示)。
Sample input #1
Station 绍兴北
Sample output #1
绍兴北 00:00 - 24:00 136 results
1 G7659 06:43 06:46 3' 杭州东 - 温州南 高速
2 G7711 06:48 06:50 2' 杭州东 - 温岭 高速
3 G1866 07:01 07:03 2' 宁波 - 郑州东 高速
...
134 D3124 21:59 22:06 7' 广州东 - 杭州东 动车
135 G4272 22:10 22:12 2' 宁海 - 新余北 高速
136 G7526 22:28 22:30 2' 温州南 - 杭州东 高速
绍兴北 136 results, 136 visible: ST ED PS UP DN
# 每一行依次显示序号、车次、到点、开点、停站时间、始发终到站、车次类型
Sample input #2
拉萨站+st*Z
# 查找拉萨站始发的直特列车
Sample output #2
拉萨 00:00 - 24:00 22 results
1 Z8982 ---- 09:25 拉萨 - 西宁 直特 ST
2 Z8901 ---- 10:50 拉萨 - 林芝 直特 ST
3 Z166 ---- 11:50 拉萨 - 上海 直特 ST
4 Z266 ---- 12:35 拉萨 - 广州 直特 ST
5 Z22 ---- 15:50 拉萨 - 北京西 直特 ST
6 Z8992 ---- 17:30 拉萨 - 西宁 直特 ST
7 Z324 ---- 19:00 拉萨 - 成都西 直特 ST
拉萨 22 results, 7 visible: ST UP DN
# 拉萨站共有22个车次,其中7个满足条件
按照起止站查询,只需要把站名用-连接即可。如果起止站有多个选择,则用/分隔开。注意这里所有的输入都不应当有“站”字,也不应当有空格。
如果同一车次在选择范围内有不同的起止点搭配,那么查询结果会优先匹配顺序在前的站点。
Sample input #1
广州/广州白云-海口
Sample output #1
广州/广州白云 -> 海口 5 results
1 Z384 广州白云 04:57 海口 16:30 < 11:33 > 长春 - 海口 直特
2 K514 广州白云 15:21 海口 05:50 < 14:29 > 上海松江 - 海口 快速
3 Z504 广州白云 18:26 海口 07:00 < 12:34 > 北京西 - 三亚 直特
4 Z8006 广州 20:38 海口 10:10 < 13:32 > 深圳东 - 海口 直特
5 Z114 广州白云 21:25 海口 08:50 < 11:25 > 哈尔滨西 - 海口 直特
广州/广州白云 -> 海口 5 results, 5 visible
# 每一行依次显示序号、车次、出发站、出发时间、到达站、到达时间、用时、始发终到站、车次类型
如果要对结果进行筛选,和按站点查询类似,需要在原命令的基础上连上一个*,后加一个或多个字头(纯数字车次用P表示)。
车次是默认按照出发时间从早到晚排序的。如果要改变查询结果的排序,需要在原命令的基础上连上一个+,随后加上st ed或v,分别代表着按出发时间从早到晚、按到达时间从早到晚、按耗时从短到长排序。
Sample input #2
上海/上海虹桥-长春/长春西+v*GZ
# 表示查询了上海到长春的G和Z字头列车,并且按速度排序
Sample output #2
上海/上海虹桥 -> 长春/长春西 9 results
1 G1236 上海虹桥 09:04 长春 19:49 < 10:45 > 上海虹桥 - 吉林 高速
2 G1214 上海虹桥 10:05 长春西 21:15 < 11:10 > 上海虹桥 - 长春西 高速
3 G1204 上海虹桥 09:33 长春西 20:45 < 11:12 > 上海虹桥 - 哈尔滨西 高速
4 G1258 上海虹桥 09:31 长春西 21:32 < 12:01 > 上海虹桥 - 长春西 高速
5 Z516 上海 15:32 长春 13:18 < 21:46 > 上海 - 吉林 直特
6 Z172 上海 19:34 长春 17:31 < 21:57 > 上海 - 哈尔滨西 直特
上海/上海虹桥 -> 长春/长春西 9 results, 6 visible
# 可以看到,9个结果中只有6个车次满足筛选条件,其余3个K字头车次被隐藏了
如果想要按同城车站查找,可以用--连接两个城市的名称,程序将自动把城市名替换为同城车站的列表。
Sample input #3
成都--昆明+st*GD
# 查找成都到昆明的G和D字头列车,按出发时间排序
Sample output #3
成都/成都东/成都西/成都南/犀浦 -> 昆明/昆明南 22 results
1 D251 成都南 07:06 昆明 15:19 < 8:13 > 成都南 - 昆明 动车
2 G2837 成都东 07:29 昆明 13:25 < 5:56 > 成都东 - 大理 高速
3 D271 成都南 08:21 昆明 15:59 < 7:38 > 成都南 - 西双版纳 动车
...
18 G2821 成都东 16:09 昆明南 22:39 < 6:30 > 成都东 - 昆明南 高速
19 D261 成都南 16:38 昆明 23:40 < 7:02 > 成都南 - 昆明 动车
20 G2825 成都东 17:27 昆明南 23:44 < 6:17 > 成都东 - 昆明南 高速
成都/成都东/成都西/成都南/犀浦 -> 昆明/昆明南 22 results, 20 visible
你可以输入命令city_station,随后对默认的同城车站字典进行编辑,每一次的编辑永久有效。输入0表示一个城市的车站输入完毕,输入save或exit表示退出同城车站的编辑并保存编辑结果。
目前已经上传的同城车站数据涵盖全国地级以上城市。
前述查询方式的每一行中,最前面的一个数字即为索引,可以直接作为下一次的命令使用。这可以完成从起止站到按车次的跳转,以及车次和站点之间的跳转。
我们可能会好奇某一车次的时刻表中,某个区间还有哪些列车可以乘坐,隐藏跳转实现了这一功能。在索引跳转的基础上,如果用-连接两个站的索引,就相当于对这两个站点作了起止站查询。
输入<<或《《可以恢复到上一个查询操作,输入>>或》》可以回到恢复前的查询操作。
查询操作包括按车次、按站点、按起止站查询三种。
有些用户可能会把本时刻表查询工具和其他工具的结果作对照,而结果往往不完全一致。可能有以下原因:
- 数据不全:本工具通过12306主站爬取时刻表,一些特殊性质的铁路(例如宁波/绍兴城际、台州城际等)无法查询到。
另外,最近还发现本工具无法爬取到 - 数据混淆:没有遵循严格数据管理(参见第2节),导致不同日期车次重叠显示。其实提供的2025年1月22日数据已经犯了这个错误,先将就着用吧。
- 数据未更新:如果有一边没有及时更新临时加开车次,那么就会遗漏,这尤其在春运期间常见。
- 排序方式不同:在按站点查询车次时,本工具始终按照列车的开车时间进行排序,对于终到车次则按照到达时间排序,而其他工具可能采用不同的排序规则,例如路路通时刻表是按到达时间排序。
所有的输入都不必区分大小写。
最后,由于代码不太熟练,最初项目的框架考虑的也比较简单,变量都是全局的,所有函数也全部写在了main.py里,望不要嫌弃。