随着2018年春节的脚步日益临近,归心似箭的人们都希望能尽快赶回家中。中国人回家过年,是每个人一年中最重要的事,无论你离家远近。在所有的交通工具中,承担着最大客流量的交通工具,毫无疑问是火车。中国庞大的人口与密布的中中国铁路网紧密相连,每一个归家游子的回家欲求逐渐汇聚成春运大潮,成为每年春节都避免不了的现象。另据TechWeb报道 1月8日消息称,2018年春运从2月1日开始至3月12日结束,共计40天。国家发展改革委网站今日发布“关于全力做好2018年春运工作的意见”(简称“意见”),要求铁路进一步扩充互联网售票系统处理能力,丰富支付手段,提升购票体验。相信每一位游子都有在12306上购买车票的经历,也相信不少购票者都因在12306上抢票而对该网站的“任性”印象深刻。
今天,小编就向大家简单介绍一下,如何通过AI时代的编程利器Python在12306上优雅地抢票。
首先在买票前我们需要先确认是否有票,那么进行正常的查票,打开12306查票网站https://kyfw.12306.cn/otn/leftTicket/init 输入出发地和目的地进行搜索。
图1
因为该请求是采用的js中ajax异步请求的方式动态加载的,并不包含在源代码里面,所以我们只能够通过抓包的方式来查看浏览器与服务器的数据交互情况,通过使用谷歌浏览器的开发者工具,其打开方式可以是快捷键F12或shift+ctrl+i。通过元素选项卡,查看相应的网页元素。
图2
选中network选项,此时只要是浏览器和服务器发生数据交互都会在下面列表框显示出来,我们再次点击查询按钮。
图3
从返回结果看,我们可以看到列表中出现了两个请求,下面我们就根据这两个返回值来分析判断哪个请求才是真正获取到车次相关数据的请求,以便我们用Python来模拟浏览器操作。
第一次请求:
图4
很明显第一次请求返回的值没有我们需要的车次信息。
第二次请求:
图5
第二次请求里面数据比较多,虽然我们暂时还没看到车次信息,但是我们发现这个列表的值里面有13个元素,而我们搜索出来的从合肥到杭州的车辆也是13条数据,所以这两者肯定有一定关系,那么我们先用Python来获取到这些数据再进行下一步分析:
# -*- coding: utf-8 -*-
import urllib2
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
def getList():
req = urllib2.Request( 'https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2018-01-09&leftTicketDTO.from_station=HFH&leftTicketDTO.to_station=HZH&purpose_codes=ADULT')
req.add_header( 'User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36')
html = urllib2.urlopen(req).read()
return html
print getList()
图6
首先定义一个函数来获取车次列表信息:
从抓包数据中获取到该请求的url:https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2018-01-09&leftTicketDTO.from_station=HFH&leftTicketDTO.to_station=HZH&purpose_codes=ADULT
为了防止被12306检测到屏蔽我们的请求那么我们可以简单的增加个头信息来模拟浏览器的请求。
req. add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36')
其中的:
ssl. _create _default_https _context = ssl. _create _unverified _context
是因为12306采用的是https协议,而ssl证书是它自己做的并没有得到浏览器的认可,所以Python默认是不会请求不受信任的证书的网站的,我们可以通过这行代码来关闭掉证书的验证
那么我们先来看看能不能正常获取到我们想要的信息 :
图7
事实证明我们的操作没有问题,接下来先拿到包含有13条数据的这个列表再说。
返回的数据是json格式,但是Python标准数据类型中没有json这个类型,所以对于Python而言它就是个字符串,如果要非常方便的操作这个json我们就可以借助Python中的json这个包来把json这个字符串变成dict类型,然后通过dict的键值对操作方法把列表取出来并进行返回。
最终返回的是一个list数据,我们先把这个数据for出来再看看每一条数据都有些什么东西:
for出来之后我们先来看看第一条数据是什么样的:
|预订|4e0000G59604|G596|WHN|HGH|ENH|HGH|16:42|19:22|02:40|Y|X9nNIopI6veiH0N47EFP9D9VoNOalcBzrKiqWVGBi77NXE4%2F|20180109|3|N2|04|11|1|0|||||||||||2|无|2||O0M090|OM9|0
其实我们稍微留一下就会发现里面有包含G596,16:42,02:40,无这样的车次信息的,只不过看起来比较乱,但是他们都有一个特点,每个数据都是由|这个符号分开的,所以我们可以通过用|分割看看能发现什么呢?
for i in getList():
for n in i. split('|'):
print n
break
图8
可以看到所有的值都打印出来了,我们再在前面加上一个序号就能清楚到看到每个序号所对应的值到底是什么了,比如有辆火车商务座特等座还剩3张票,软卧没有剩票,显示无,那我们就查看哪个序号对应的值是“3”哪个序号对应的值是“无”就搞清楚了哪个序号是代表什么座次或者其他参数了。
图9
到了这里用的这个函数只能够获取到从合肥到杭州的数据,而别人不一定是买这个方向的火车,所以我们还得搞清楚请求的url当中的出发站和到达站的值是怎么来的。
url:https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date=2018-01-09&leftTicketDTO.from_station=HFH&leftTicketDTO.to_station=HZH&purpose_codes=ADULT
先找到出发站和到达站的参数分别是:leftTicketDTO.from_station=HFH&leftTicketDTO.to_station=HZH
然而通过查找和分析我并没有发现这两个参数有规律,那么也就是说这两个值是在之前的请求里面就已经获取到了的,通过检查网页源代码没有找到,那么又只能通过抓包的方式来找。
在抓包过程中找到了一个包的返回值是附带有各城市的代号的,url如下:
https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9043
图10
然后我们通过把参数做成通过输入出发城市和到达城市就可以直接在这个数据里面匹配到相应的城市代号,代码如下:
图11
这样就已经能够通过输入时间,城市获取相应的车次信息了 。
图12
到这里,仅仅完成整个抢票环节的一环而已,同时再结合登录,购票等流程,才算基本完成整个流程,由于整个过程较为复杂而篇幅有限,所以小编这里就先简单介绍到这里,希望给还在为春运购票而烦恼的你提供些许思路。