python查询12306余票_Python爬虫----12306火车票余票查询器

12306火车票余票查询器

文章同步更新:http://www.riba2534.cn/?p=305

今天写了一个12306火车票余票查询器的爬虫,在这里记录一下过程.

首先先看一下最终效果:

比如想查9月2日从西安—北京动车和特快的余票

tickets.py -dg 西安 北京 2017-09-02

效果预览:

首先我们梳理一下用到的工具:

Python3.x(必备)

requests库,用来进行http请求的访问

docopt库,用来实现命令行参数处理(使用方法)

prettytable,使信息以好看的表格形式呈现出来

colorama,用来设置命令行中显示的颜色

一、前期准备

我们的主程序就叫做tickets.py,因为我们是用的带参数的形式实现程序,所以我们要先进行参数的声明:

我们先:from docopt import docopt

"""命令行火车余票查询器

Usage:

tickets [-gdtkz]

Options:

-h,--help 显示帮助菜单

-g 高铁

-d 动车

-t 特快

-k 快速

-z 直达

"""

这些信息会存储在__doc__中,docopt会对这个信息进行解析然后返回我们需要的信息,解析的代码如下:

二、解析URL

既然要写爬虫,那么首先肯定是要对URL进行解析了,我们要爬取的是12306的网站,那么我们首先找到查询余票的网站:

https://kyfw.12306.cn/otn/leftTicket/init

leftTicketDTO.train_date=2017-09-01

leftTicketDTO.from_station=XAY

leftTicketDTO.to_station=BJP

purpose_codes=ADULT

我们通过观察就可以知道,这四个属性分别对应着:查询的时间,出发的站点,结束的站点,票的种类

现在发现了一个问题,出发站点和结束站点的值为什么都是英文,这些字母肯定表示的是城市的名称,那么我们现在就要去寻找这些城市的代码,我们查看网页源代码

发现了一个JS文件,打开以后会发现

这个页面竟然包含着全部的站点名称和对应的代码,所以我们只需要把这些东西解析一下,就可以得到车站和对应的代码了.

所以我们就有了思路了,我们应该先用requests来获取这个页面,然后再用正则表达式来把对应的信息解析一下,然后进行一些处理就好了,关于正则表达式的使用,不会的童鞋还是去百度百度吧~

根据网页上面的信息,我们可以写出如下正则表达式:

([\u4e00-\u9fa5]+)|([A-Z]+)

先匹配汉字,然后后面匹配字母,中间有一个分隔符,完整的代码.

我们建一个文件parser_stations.py解析:

使用方法是运行这个文件,然后把这个文件的结果重定向到一个新文件:

python parser_stations.py > stations.py

然后对新的文件进行处理:

这样我们就可以通过stations.py里面的两个函数进行获取操作了,这样的话我们就可以构造出我们需要的URL

url=('https://kyfw.12306.cn/otn/leftTicket/query?'

'leftTicketDTO.train_date={}&'

'leftTicketDTO.from_station={}&'

'leftTicketDTO.to_station={}&'

'purpose_codes=ADULT').format(date,from_station,to_station)

三、解析火车票的信息

我们现在已经获取到了url,我们现在就可以对其访问,还是用requests来访问我们构造好的URL,比如我们构造的是2017-09-02从西安到北京的火车,那么url是:https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2017-09-02&leftTicketDTO.from_station=XAY&leftTicketDTO.to_station=BJP&purpose_codes=ADULT

我们进入后会看到:

很明显,这是一个json信息,我们用requests自带的json解析器来进行解析,会得到一个列表:

r=requests.get(url,verify=False,headers=headers)

r.encoding=r.apparent_encoding

raw_trains=r.json()['data']['result']

这个列表里面:

6,7元素代表起点和终点的名称

8,9元素代表这趟列车出发和到达的时间

10号元素代表,列车的用时

31代表一等座,30代表二等座

23,28,29代表软卧,硬卧,硬座

26代表无座的信息

我们知道了每个元素代表的信息,只需要把它们呈现出来就可以了,我们先创建一个prettytable对象:

pt=PrettyTable() #初始化一个prettytable对象

pt._set_field_names('车次 车站 时间 历时 一等座 二等座 软卧 硬卧 硬座 无座'.split())

然后弄好表格的标题后,插入列:

for raw_train in raw_trains: #对每一趟列车进行解析

data_list=raw_train.split('|')

train_no=data_list[3]

initial=train_no[0].lower() #获取首字母,表示车次

if not options or initial in options: #如果没有设置options或者首字母在options里面

from_station_code=data_list[6]

to_station_code=data_list[7]

start_time=data_list[8]

arrive_time=data_list[9]

time_duration=data_list[10]

first_class_seat=data_list[31] if data_list[31] else '--'

second_class_seat=data_list[30] if data_list[30] else '--'

soft_sleep=data_list[23] if data_list[23] else '--'

hard_sleep=data_list[28] if data_list[28] else '--'

hard_seat=data_list[29] if data_list[29] else '--'

no_seat=data_list[26] if data_list[26] else '--'

pt.add_row([

Fore.YELLOW + 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,

first_class_seat,

second_class_seat,

soft_sleep,

hard_sleep,

hard_seat,

no_seat])

print(pt)

在这里面用了colorama来对命令行里面的字符进行上色,相关用法去百度找找就行了~

代码长得比较丑陋,还请不要嫌弃,主要作为练手之用,所以懒得重构代码了,相关的源代码已经上传至Github,欢迎提出问题和Bug…

(^▽^)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值