前言
各位掘金上的大佬们你们好,我是一个在校大学生,第一次在掘金上发文章。
今天带来的第一篇文章是关于12306的。
为什么要写这篇文章
首先我是一名铁路迷其次是一个还未入行的程序员。我在学习前端的过程中,我发现市面上没有几个教程是关于12306的,大多都是后端的大佬们基于12306的业务进行后端的"抢票","并发","库存扣减"的一些文档。前端仿佛就变成了搭建一个页面而已。(内心OS:其实前端本质就是个切图仔)
这篇文章能干什么
这篇文章能够解析 kyfw.12306.cn/otn/leftTic...? 这一个接口返回的所有值的意思,我将从铁路的角度来给大家说明清楚,他为什么会这样设计,其中的规律也是我喜欢了这么多年铁路摸索出来的。
开始解析
第一步:发请求 / 重点电报码
- 无论你是用地址栏发请求,还是使用postman/apifox这一类的工具向12306发起请求,都可以。
- 我首先用浏览器地址栏向这一个接口发送请求。
- 大家可以看到12306成功返回了我需要的车次信息,我们首先来分析这一个接口需要的参数。 kyfw.12306.cn/otn/leftTic...
参数 | 意义 | 值 | 值的意义 |
---|---|---|---|
leftTicketDTO.train_date | 出发时间 | 2024-04-12 | 日期 |
leftTicketDTO.from_station | 出发车站 | ICW | 成都东 |
leftTicketDTO.to_station | 到达车站 | NKW | 内江北 |
purpose_codes | 乘客类型 | ADULT | 成人 |
- DTO我不用说了吧,好像是后端的一种概念(我前端也解释不清楚)
- leftTicket 机器翻译,离开的票,那其实就是车票的意思
- ICW/NKW 中国铁路站名电报码 (路内好像是叫这个)
ChatGPT的解释: 中国铁路站名电报码是一种简化的编码系统,用于表示中国各个铁路车站的名称。这个编码系统通常用于电报和其他简化通讯中,以减少通讯所需的字符数量,提高传输效率。
每个铁路车站都被分配了一个独特的电报码,通常是由车站名称的拼音首字母组成。这些电报码通常只包含大写字母,不包含数字或特殊字符。这样的编码系统使得在电报等通讯中,可以用更少的字符来表示车站名称,提高了通讯的效率和速度。
- 明白了电报码的概念之后,我们就可以在一个地方拿到这个数据
- 同时可以看到现在的station.js版本是10042版本,每一条新铁路线开通,中国铁路就会有一批新的站名(电报码)进行更新,不然旅客是查不到新开通的线路的。
- 但目前这个版本是2024年4月铁路调图的固定版本,大家可以等待一会儿,比如下一次调图(2024年6月30日)就会进行改变有很多新线加入(比如四川汉巴南等)
第二步:看响应 / 重点同城概念
- result很长,我就不展开,先从外层json说起。
js
//响应回来的数据
{
"httpstatus": 200,//这个不用说吧,我觉得会写代码的都知道
"data": {//票务信息[本次文章的重点]
"result": [//票务核心信息[我主要就对这个数据进行解析]
"3FJ%2BfRg6tWcoD%2BEUR148ogASVmc7e1uINrOF0L%2BsBmhxWi13pILpUnOatWdU%2BwZAr6VM29758ztW%0AnhnO1SXoomOk%2BXcq79O6xpqFGSa1XQ3sR4u80PIu0X0WBMsSFdlq5oqHcPbSAZuMpcqJGHw8DHhY%0Af%2B9KpoixLCFOggWGXzYR16mnPWyPkYt%2Bk4%2FSsehsjertRgZuwDanhnxTAFCZrXSThFz7WrrFUPsN%0AiSfkASTmZbOfOjwDZdIkE1mGQaMdNAnL9c1zaZrgOaUMop246d7bRR3dFp84F8Nv2yauIpplY3oO%0AepRjLbqtGcFUJfmn4GhIGu86OHz%2B%2BTIx0f%2F9kA%3D%3D|预订|76000G877102|G8771|ICW|LUE|ICW|NKW|06:12|06:52|00:40|Y|LC7ZygFdrCHzveNg7n5L%2FL9Spx7AkGGzhSJdlTUUoJHgWuL6|20240412|3|W3|01|02|1|0|||||||||||有|12|无||90M0O0|9MO|0|1||9022200000M010500012O006600021|0|||||1|5#1#0#0#z#0#z|||CHN,CHN|||N#N#||90076M0078O0079|202403290830|",
"JJsJ8hSdqE9hlcF%2BEGUqyE8BqwbJwSAyRmK9rtnQ9Qa42nwGz%2F9ubEM4KZ2FAITRAZOmNye024zC%0A0nEJE9IpyeWSsARAFZwip0PCVkoZ9h2EaQs%2FLYPvdmJ5INGrzsVaj1FB3q9jEB0RpQTiq3gjdR%2Fr%0AhfqB%2FsD%2FfYZr3Mm2OiRWndtOVgJFMUxKPopdTwaKVUROF72JjSXjee0lKkNYZGxAw%2BI2ubjh8jIn%0AThAl6FwkQ%2BignTfXle%2BIXbwK1UHaCpXJsyjgyD0l1ClqL6MJRj%2BplD%2FTeqU0Fu151Q821IWnrU5F%0AsCR7zrL7N5NekBh%2FWYwCQcxC%2FGkE3RDPIyfLoQ%3D%3D|预订|76000G873750|G8737|ICW|WEI|ICW|NDE|06:42|09:44|03:02|Y|5B0XuNRm0F%2FkofrP1N56UBE2S2wPCanKg%2B9VkpEIooz7we5%2B|20240412|3|W2|01|11|1|0|||||||||||有|16|无||90M0O0|9MO|1|1||9044100000M022100016O013800021|0|||||1|0#0#0#0#z#0#z|||CHN,CHN|||N#N#||90081M0081O0081|202403290830|",
],
"flag": "1",//不知道
"level": "0",//不知道
"map": {//同城-通查车站[铁路概念]
"NKW": "内江北",
"ICW": "成都东",
"CNW": "成都南",
"NDE": "内江东"
}
},
"messages": "",//不解释
"status": true//不解释
}
- 我们先说同城-通查车站这个概念
我在写这个概念的时候,特意去圈子里查询了一下,首先还是GPT怎么说
中国铁路同城车站是指位于同一个城市内的多个铁路车站,这些车站之间相对距离较近,服务范围通常也集中在该城市及其周边地区。这些车站可能分布在城市不同的区域,为乘客提供更便捷的出行选择。
在中国,一些大型城市拥有多个铁路车站,这些车站通常分布在城市的不同地区,为乘客提供更多的出行方便。例如,北京市拥有北京站、北京西站、北京南站等多个铁路车站,上海市拥有上海站、上海南站、上海虹桥站等多个铁路车站。这些车站之间通常有地铁、公交等交通工具连接,为乘客提供便捷的换乘和出行服务。
中国铁路同城车站的存在,旨在满足城市居民和来往旅客的出行需求,提高交通运输效率,促进城市发展和旅游业的繁荣。
其实这个概念中国铁路也没有明确的对外发声,但是部分铁路迷总结出他的浅显定义(近似于GPT这种概念)
- 但是我们从12306接收到的这些数据,这个map中的站点属于什么呢?
答案:其实是通查站
为什么是通查站,通查站是什么,我用下面的解释来简单告诉你。
通查站一定是同城站,同城站不一定是通查站
通查站,其实就是一个地理大范围能够在12306铁路系统中买得到的车票车站
同城站,其实就是一个地理大范围内能够在短时间相互换乘的同城市区域车站
不明白很正常,我用地图给你解释。
在这里我又查询了一个区间(湖北孝感至湖北武汉,其间最短不过50Km)
但是出现了8个车站,请大家注意孝感北这一个车站。
如果从铁路的角度来解释,为什么这么远又要写很多了,那么开发人员明白这样一个概念就行了。
第三步:开始解析 / 重点票务信息
- 这是刚刚我们请求到的一个票务信息字符串 data-result中的第一个元素 result是一个字符串数组
js
"3FJ%2BfRg6tWcoD%2BEUR148ogASVmc7e1uINrOF0L%2BsBmhxWi13pILpUnOatWdU%2BwZAr6VM29758ztW%0AnhnO1SXoomOk%2BXcq79O6xpqFGSa1XQ3sR4u80PIu0X0WBMsSFdlq5oqHcPbSAZuMpcqJGHw8DHhY%0Af%2B9KpoixLCFOggWGXzYR16mnPWyPkYt%2Bk4%2FSsehsjertRgZuwDanhnxTAFCZrXSThFz7WrrFUPsN%0AiSfkASTmZbOfOjwDZdIkE1mGQaMdNAnL9c1zaZrgOaUMop246d7bRR3dFp84F8Nv2yauIpplY3oO%0AepRjLbqtGcFUJfmn4GhIGu86OHz%2B%2BTIx0f%2F9kA%3D%3D|预订|76000G877102|G8771|ICW|LUE|ICW|NKW|06:12|06:52|00:40|Y|LC7ZygFdrCHzveNg7n5L%2FL9Spx7AkGGzhSJdlTUUoJHgWuL6|20240412|3|W3|01|02|1|0|||||||||||有|11|无||90M0O0|9MO|0|1||9022200000M010500012O006600021|0|||||1|5#1#0#0#z#0#z|||CHN,CHN|||N#N#||90076M0078O0079|202403290830|",
为了方便,我先帮大家进行格式化,这一个字符串是以 | 进行分割
值 | 意义 | 值 | 意义 |
---|---|---|---|
3FJ%2BfRg6tWcoD%2BEUR148ogASVmc7e1uINrOF0L%2BsBmhxWi13pILpUnOatWdU%2BwZAr6VM29758ztW%0AnhnO1SXoomOk%2BXcq79O6xpqFGSa1XQ3sR4u80PIu0X0WBMsSFdlq5oqHcPbSAZuMpcqJGHw8DHhY%0Af%2B9KpoixLCFOggWGXzYR16mnPWyPkYt%2Bk4%2FSsehsjertRgZuwDanhnxTAFCZrXSThFz7WrrFUPsN%0AiSfkASTmZbOfOjwDZdIkE1mGQaMdNAnL9c1zaZrgOaUMop246d7bRR3dFp84F8Nv2yauIpplY3oO%0AepRjLbqtGcFUJfmn4GhIGu86OHz%2B%2BTIx0f%2F9kA%3D%3D | 无意义或加密 | 预订 | 预订 |
76000G877102 | 车次号G8771 | G8771 | 车次号 |
ICW | 始发站:成都东 | LUE | 终点站:泸州 |
ICW | 旅程出发站:成都东 | NKW | 旅程终到站:内江北 |
06:12 | 出发时间 | 06:52 | 旅程到达时间 |
00:40 | 旅行乘车时长 | Y | 无意义或加密 |
LC7ZygFdrCHzveNg7n5L%2FL9Spx7AkGGzhSJdlTUUoJHgWuL6 | 加密字符串 | 20240412 | 日期 |
接下来一连串值到||| | 无意义或加密 | 有 | 二等座/二等包座票务情况 |
11 | 一等座票务情况 | 无 | 商务座/特等座票务情况 |
90M0O0开始一直到|| | 无意义或加密 | 9022200000M010500012O006600021 | 票务价格字符串(接下来解释) |
余下字符串 | 无意义或加密 |
- 大家看到这里,多多少少都懂了,但是在余票查询的时候,列车种类的不同会影响每一个值的组成位置。
这个问题再往下看,我用价格字符串来解释这个问题怎么办。
第三步:解析价格字符串 / 重点列车类型
- 现在我们已经解析了很多信息了,我有了车次信息,时刻信息,车票余额信息。仿佛还差个东西,就是每一张票卖多少钱这个信息我还没有。
- 那么我们就开始解析这个票务价格字符串
js
const price = "9022200000M010500012O006600021"
- 我直接开始解析,不说原因。
js
const price = "9 02220 0000M 01050 0012O 00660 0021"
- 我相信大家已经明白了。
本质上就是把这个字符串按照一定的规律进行切割 中间的五个数字就能转换为具体的票价 就这么简单
- 理论已经知道了,我来说程序员不知道的事情
中国铁路到底有多少种不同的列车种类呢?
答案: 我直接上图。
- 车次号分类
- 特殊车次类
- 旅游列车及特殊列车
大概就只有这几类,如果你写代码来解析,可以按照车次号来进行先分大类,然后再处理特殊情况。
- 那么接下来我就大致写一下中国铁路有哪些种类的列车
车次类型 | 描述 | 描述 |
---|---|---|
G | 时速在250Km-350Km的高速列车 | 常常只有3种席位 pringString长度为30 |
D | 时速在160Km-350Km的列车 | 常常只有1-4种席位是最复杂的一种车次类型 pringString长度为10-40之间 |
C | 时速在160Km-350Km的列车 | 常常只有2-4种席位也是一种复杂的车次类型 pringString长度为20-40之间 |
KTZ | 时速在80Km-160Km的普速列车 | 常常只有2-5种席位 pringString长度为20-50之间 |
SY | 市郊列车与旅游列车 | 常常只有1-4种席位比较特殊 pringString长度为10-40之间 |
看明白了吗,价格字符串解析,怎么解析,其实就是用长度来进行判断,所以我发现这个规律后,发现了一件事情。
当我写到这里的时候,我发现成都西-南宁这个K144出现了我原先写的项目中一种没有的情况,就是特殊的KTZ车,这个车在我开发我自己的查票网站的时候是正常的4-5种席位的(长度40-50),但是经过此次调图之后,变成了只有硬卧与软卧(长度20),所以这种情况大家就只能特殊处理。
第四步:整合数据
这个东西不用我说,大家都会,我给大家看我自己写的成品就是了。
结语
这个技术很简单,有可能我发出来过段时间12306就改掉了,很正常的一个事情,但是我作为一个学生,一个前端准备入门的人来说,写一下锻炼一下,无所谓的,还请大家指正错误,广泛讨论。
最后升华一下:买票到12306,发货到95306,不要相信任何第三方平台抢票业务。
谢谢大家。