本期导读
火车票查询的平台有很多,比如携程、去哪儿,飞猪等等,但是万变不离其宗,所有平台的数据都需要从12306官网获取,只是通过前端的渲染以不同的形式展现出来而已,本期通过分析12306官网网页结构,利用python进行火车票信息查询,并将信息格式化输出、保存到本地Excel文件。
01
打开12306官网,输入出发地、目的地、出发日期进行查询,这里我们查询 2021-02-21 北京-武汉的车票信息。
右键选择审查元素,查看所有车次信息都在一个表格(table)标签中:
02
接下来我们直接把网址复制出来用python请求测试一下返回结果:
url = 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E5%8C%97%E4%BA%AC,BJP&ts=%E6%AD%A6%E6%B1%89,WHN&date=2021-02-21&flag=N,N,Y' headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", 'Cookie': '你的 cookie' } r = requests.get(url, headers=headers, timeout=10) r.raise_for_status() r.encoding = r.apparent_encoding print(r.text)
在返回信息中任意查询一个车次,比如G507:
很奇怪,明明在页面table中可以看到,但是网页请求返回信息中却没有,所以猜测可能是异步请求,真正的车次信息在其它接口中返回。
03
重新分析一下网页源码,在Network的XHR(为什么会直接找XHR,其实XHR是XMLHttpRequest的缩写,我们与网页的交互记录都在这里面,所以我们直接找请求的XHR信息)中看到如下一条交互信息:
再次在返回信息中查询车次G507:
果不其然,G507车次信息在这里,搜索其他车次,发现也可以找得到,仔细分析一下这个返回信息会发现车次,出发站到达站,出发时间到达时间等等信息都在这里,简直是意外收获!
04
检查Header信息,实际请求网址为:
根据新的域名和参数再次请求:
这样我们就拿到了所有车次的信息,接下来就是解析这个json格式的数据,获取详细的车次信息了。
05
全部车次的信息在data关键字的result列表中,result共有52条(包含停运列车)信息和12306网站上显示的信息一致,遍历result列表即可获取每个车次的车票信息。
r = requests.get(url, headers=headers, timeout=10) r.raise_for_status() r.encoding = r.apparent_encoding print(r.text) raw_trains = json.loads(r.text)['data']['result'] allinfo = [] for raw_train in raw_trains: oneinfo = [] # split切割之后得到的是一个列表 data_list = raw_train.split("|") # 车次 train_no = data_list[3] # 出发站 from_station_code = data_list[6] # 到达站 to_station_code = data_list[7] from_station_name = stations.get_name(from_station_code) to_station_name = stations.get_name(to_station_code) # 出发时间 start_time = data_list[8] # 到达时间 arrive_time = data_list[9] # 历时 time_duration = data_list[10] # 商务座 business_seat = data_list[32] or '--' # 一等座 first_class_seat = data_list[31] or "--" # 二等座 second_class_seat = data_list[30] or "--" # 高级软卧 g_soft_sleep = data_list[21] or "--" # 软卧 soft_sleep = data_list[23] or "--" # 动卧 d_soft_sleep = data_list[27] or "--" # 硬卧 hard_sleep = data_list[28] or "--" # 软座 soft_seat = data_list[24] or "--" # 硬座 hard_seat = data_list[29] or "--" # 无座 no_seat = data_list[26] or '--' if time_duration == '99:59' and start_time == '24:00' and arrive_time == '24:00': train_no = train_no + '(列车停运)' continue oneinfo.append(train_no) oneinfo.append(from_station_name) oneinfo.append(to_station_name) oneinfo.append(start_time) oneinfo.append(arrive_time) oneinfo.append(time_duration) oneinfo.append(business_seat) oneinfo.append(first_class_seat) oneinfo.append(second_class_seat) oneinfo.append(g_soft_sleep) oneinfo.append(soft_sleep) oneinfo.append(d_soft_sleep) oneinfo.append(hard_sleep) oneinfo.append(soft_seat) oneinfo.append(hard_seat) oneinfo.append(no_seat) allinfo.append(oneinfo)
上面对应的信息编号需要根据返回列表比对确认,代码是解析全部信息,如果只需要部分信息的话直接筛选即可,注意处理过程中我们将停运列车信息去掉(根据自己需要也可以保留,将continue注释掉即可)。
06
格式化输出车次信息:
strr = "车次 车站 时间 经历时 商务座 一等座 二等座 高级软卧 软卧 动卧 硬卧 软座 硬座 无座" lst = strr.split() pt = PrettyTable(field_names=lst) pt.add_row([ # 对特定文字添加颜色 Fore.LIGHTYELLOW_EX + train_no + Fore.RESET, '\n'.join([Fore.GREEN + stations.get_name(from_station_code) + Fore.RESET, Fore.RED + stations.get_name(to_station_code) + Fore.RESET]), '\n'.join([Fore.GREEN + start_time + Fore.RESET, Fore.RED + arrive_time + Fore.RESET]), time_duration, business_seat, first_class_seat, second_class_seat, g_soft_sleep, soft_sleep, d_soft_sleep, hard_sleep, soft_seat, hard_seat, no_seat ]) print(pt)
输出如下:
提示:prettytable 这个库对中文兼容性不算太友好,所以内容中包含中文时,文本对齐会出现一定偏差,如果替换成相应英文名称的话会更美观,大家也可以尝试用print制表符的方式来格式化输出。
07
保存车次信息到本地Excel文件:
def Insert2Excel(allinfo,xlname): tableTitle = ['车次','出发站','到达站','出发时间','到站时间','经历时','商务座','一等座','二等座','高级软卧','软卧','动卧','硬卧','软座','硬座','无座'] wb = Workbook() ws = wb.active ws.title = 'sheet1' # 添加表头 ws.append(tableTitle) work_name = xlname + '.xlsx' # 设置格式 for i in range(1, ws.max_column + 1): ws[get_column_letter(i)+'1'].font = Font( bold=True) ws.column_dimensions[get_column_letter(i)].width = 10 ws.column_dimensions[get_column_letter(i)].alignment = Alignment(horizontal='left', vertical='center') # 插入数据 for info in allinfo : ws.append(info) ws.freeze_panes = 'A2' # 保存文件 wb.save(work_name)
Excel 文件的首行做了加粗和冻结的简单处理,更多方法可以查阅openpyxl库的使用方法。
大功告成!大家也可以将出发站、到达站和查询日期以input输入的方式来操作,注意请求url需要进行拼接处理。
END
以上就是本期为大家整理的全部内容了,码字不易,喜欢的朋友可以点赞、点在看也可以分享到朋友圈让更多人知道哦