查看原文
其他

查询12306车次信息

爬虫俱乐部 Stata and Python数据分析 2022-03-15

本文作者:张延丰(兰州财经大学)

文字编辑:孙晓玲

技术总编:张   邯

导读



今天,我们为大家介绍查询12306车次信息的方法,步骤如下:分析url构成,从而构建爬取任意时间和站点的车次信息的框架,封装成get_data函数。出发地和目的地两个参数需要使用官方英文缩写,所以爬取汉字地点与英文缩写的对应字典,封装成input_value函数。主函数加入input函数,从而通过键入参数查询任意需要的时间和始末站点的车次信息。




1



根据我们所构建的爬取步骤,首先我们要做的就是先构建一个爬取当前页面,也就是固定的日期和始末站点的车次信息的框架。第一步,我们先要找到数据所存放的位置,我们打开12306车次查询页面,右击查看网页的源代码,发现页面内容并没有在网页源码中,12306查询车次信息网页,如下图:

我们再通过右击点击检查,点击network下的xhr数据,通过刷新网页,在xhr数据下发现查询请求,如下图:

由此,我们判断网站使用的是AJAX技术,即异步的JavaScript和XML,不是新的编程语言,而是一种使用现有标准的新方法。AJAX最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,且不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。判断网页是否使用AJAX
技术可以通过查看该请求的请求头,如果请求头中含有x-requested-with项,则可以判断请求是异步请求的条件。接下来,我们再通过查看response,
发现里面包含我们需要查询的信息。至此,完成了爬取前的准备工作。通过定义函数来完成任意时间和站点的车次信息来爬取,函数为get_data(date,start_place,end_place)。

def get_data(date,start_place,end_place): #加入Host,cookie,Accept - Language,User-Agent请求头,只加入user-agent请求头反馈信息不足。 headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko)' ' Chrome/80.0.3987.132 Safari/537.36', 'Host':'kyfw.12306.cn', 'cookie':'JSESSIONID=D9BD1700C3BED9A58C5BD901471B0D85; RAIL_EXPIRATION=1584949299017; RAIL_DEVICEID=lODITS11BKWQtqzQXeXuxT-uqnv67ccyw2EwXBIzBqjjME9qSUF4pVqGRzoP118wYzJ-1-CSpMmo-JN4q56JVivPERWhnUHeIyg81OOqP8-Ds4XPFwz4ca1b1NEnzr6fvcxdmeC2EqD5EK7OB4mpF6F7zBOUeZe-; _jc_save_fromDate=2020-03-20; BIGipServerpassport=854065418.50215.0000; route=9036359bb8a8a461c164a04f8f50b252; _jc_save_toDate=2020-03-20; _jc_save_fromStation=%u4E0A%u6D77%2CSHH; _jc_save_toStation=%u5929%u6D25%2CTJP; _jc_save_wfdc_flag=dc; BIGipServerotn=1977155850.50210.0000', 'Accept - Language': 'zh - CN, zh;q = 0.9' } #通过在XHR捕捉的get请求的Headers最下方,查看url需要加入到参数, Params = {'leftTicketDTO.train_date':date, 'leftTicketDTO.from_station':start_place, 'leftTicketDTO.to_station':end_place, 'purpose_codes':'ADULT' } base_url = 'https://kyfw.12306.cn/otn/leftTicket/query?' url = base_url+urlencode(params) #通过print(type(response))发现结果为列表形式 Responses = requests.get(url,headers=headers).json()['data']['result'] ps=[] #通过遍历列表,排除已停运车次,建立发车信息列表 for response in responses: if '停运' in response: pass else: ps.append(response) #将数据存为csv格式 with open('12306.csv', 'a') as f: writer = csv.writer(f) writer.writerow(['车次', '始发站', '终点站', '发车时间', '到达时间', '历时', '商务座', '一等座', '二等座', '软卧', '硬卧', '硬座', '无座']) for p in ps: #通过观察response,发现每个内容都用|隔开,因此用string.split()将字符串分割为列表,再用list[]进行定位。 train_list = p.split('|') train_number = train_list[3] start_station = train_list[6] arrived_station = train_list[7] go_time = train_list[8] arrived_time = train_list[9] cost_time = train_list[10] special_class_seat = train_list[32] or '--' # 商务/特等座 first_class_seat = train_list[31] or '--' # 一等座 second_class_seat = train_list[30] or '--' # 二等座 soft_sleep = train_list[23] or '--' # 软卧 hard_sleep = train_list[28] or '--' # 硬卧 hard_seat = train_list[29] or '--' # 硬座 no_seat = train_list[26] or '--' # 无座 with open ('12306.csv','a') as f: writer = csv.writer(f)writer.writerow([train_number,start_station,arrived_station,go_time,arrived_time,cost_time,special_class_seat,first_class_seat,second_class_seat,soft_sleep,hard_sleep,hard_seat,no_seat])

2



因为发起查询的请求的url中的参数必须是地点的英文缩写,因此我们还需要将汉语地点转移为英文缩写。通过在js里面查找station_name地址,从而找到数据。

def input_value(): headers={'Referer': 'https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=%E4%B8%8A%E6%B5%B7,SHH&ts=%E5%A4%A9%E6%B4%A5,TJP&date=2020-03-20&flag=N,N,Y', 'Sec-Fetch-Dest':'script', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 (KHTML, like Gecko)' ' Chrome/80.0.3987.132 Safari/537.36' } url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9142' response = requests.get(url,headers = headers) #通过正则表达式来爬取response中需要信息 pattern = '([\u4e00-\u9fa5]+)\|([A-Z]+)' result = re.findall(pattern,response.text) #建立字典并返回 result = dict(result)    return result

3



最后一步,建立函数来写入起始地、目的地和出发时间,注意参数必须是官方规定的形式输入,比如:兰州西,北京西,否则会因为input_value中的字典没有找到键值而报错。

a = input('起始地:') b = input('目的地:') c = input('乘车日期:') content = input_value() start_place = content[a] end_place = content[b] date = c    get_data(date, start_place, end_place)

运行输入参数可以得到如下结果:









对我们的推文累计打赏超过1000元,我们即可给您开具发票,发票类别为“咨询费”。用心做事,不负您的支持!
往期推文推荐
海外疫情仍严峻,劝君更在家中留
国外疫情怎么看?——实时新闻获真知

基于贝叶斯定理的算法——朴素贝叶斯分类

中国知网爬虫(CNKI) 批量下载PDF格式论文
sencode命令介绍
Ftools命令组之fisid命令和fsort命令介绍
“抽丝剥茧”,层层下分——机器学习基本算法之决策树

爬取东方财富网当日股票交易情况

stata调用python爬取时间数据——借他山之石以攻玉

全国31省GDP排行强势登场!
接力《发哨子的人》Stata版
批量实现WORD转PDF

Stata有问必答环节

我听到了企业的哀鸣
“物以类聚”、“近朱者赤”——机器学习初探之KNN
SFI:Stata与Python的数据交互手册(二)

从流调数据中寻找感染真相

关于我们



微信公众号“Stata and Python数据分析”分享实用的stata、python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。

此外,欢迎大家踊跃投稿,介绍一些关于stata和python的数据处理和分析技巧。
投稿邮箱:statatraining@163.com
投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存