其他
查询12306车次信息
本文作者:张延丰(兰州财经大学)
文字编辑:孙晓玲
导读
今天,我们为大家介绍查询12306车次信息的方法,步骤如下:分析url构成,从而构建爬取任意时间和站点的车次信息的框架,封装成get_data函数。出发地和目的地两个参数需要使用官方英文缩写,所以爬取汉字地点与英文缩写的对应字典,封装成input_value函数。主函数加入input函数,从而通过键入参数查询任意需要的时间和始末站点的车次信息。
1
根据我们所构建的爬取步骤,首先我们要做的就是先构建一个爬取当前页面,也就是固定的日期和始末站点的车次信息的框架。第一步,我们先要找到数据所存放的位置,我们打开12306车次查询页面,右击查看网页的源代码,发现页面内容并没有在网页源码中,12306查询车次信息网页,如下图:
技术可以通过查看该请求的请求头,如果请求头中含有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)
运行输入参数可以得到如下结果:
关于我们
微信公众号“Stata and Python数据分析”分享实用的stata、python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。