python04:爬取12306火车票

一、实验目的

平时生活中要查找火车票,一般步骤:先打开12306网站或者APP,但是这样比较麻烦。能不能直接输入一行代码,就可以直接找到我们需要的火车票信息呢?本实验就是用python爬虫,写一个命令行版的火车票查看器,只需要敲一行命令,就能够或许我们想要的信息。

二、实验的总体设计

step1:pip安装实验需要的第三方库
step2:用docopt库,获取命令行参数信息
step3:获取火车票对应的代码信息
step4:通过构造请求链接,获取车票信息
step5:解析返回的链接信息
step6:将返回的车站代码替换成中文
step7:显示设置

三、代码实现

step1:pip安装实验需要的第三方库

  • docopt
  • requests
  • prettytable:
  • pprint:
  • colorama:

1、以管理员身份运行cmd(在安装的时候能省去一些麻烦,比如python安装的不是在C盘,安装第三方库更加的迅速)
2、 pip install docopt 安装这些代码
3、 输入pip list查看这些文件是否安装完毕,如下图所示:
这里写图片描述

step2:用docopt库,获取命令行参数信息

docopt官网
docopt是一个命令行接口描述语言,用于定义命令行程序的各项参数,并且生成一个处理分析参数的分析器。
本质上是在 Python 中引入了一种针对命令行参数的形式语言,在代码的最开头使用 “”“文档注释的形式写出符合要求的文档,就会自动生成对应的parse,体验非常赞。


"""命令行火车票查看器
Usage:
    tickets [-gdtkz] <from> <to> <date>

"""
from docopt import docopt

arguments = docopt(__doc__)
print(arguments['<from>'])
print(arguments['<to>'])
print(arguments['<date>'])

本实验中,只需要输入

E:\Github\test>python test_docopt.py -dg 云南 丽江 2018

即可得到相应的三个返回值arguments[‘’],arguments[‘’],arguments[‘’],用于后面的链接构造

step3: 获取火车票对应的代码信息

在火车票查询的html网页中寻找station_version,如下图所示:
这里写图片描述
再网页中输入如下代码,即可查找到到车站代码:
https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9051
但返给我们的是个json格式的文件,如下图所示:
这里写图片描述
我们用requests.get(url),获取json文件
使用正则表达式提取出相应的车站和代码,以字典的形式放在一个station的变量中,并且将其放入stations.py文件中,以供调用。这里需要使用pprint这的第三方库,更好的打印字典。
cmd中运行:

python parse_station.py > station1.py

将这个字典存入到stations.py文件当中
这里到stations.py添加字典名
这里写图片描述


step4:通过构造请求链接,获取车票信息

当我们登陆12306,点击搜索的时候,浏览器传递给服务器的是一个链接,通过这个链接获取我们想要的信息,我们需要的就是构造这个链接,并且解析传递回来的信息
获取火车票查询url
每次点击12306的查询,浏览器就会向网站发送一个请求信息:https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2018-05-02&leftTicketDTO.from_station=WHN&leftTicketDTO.to_station=SZN&purpose_codes=ADULT
其格式如下:
https://kyfw.12306.cn/otn/leftTicket/query?
leftTicketDTO.train_date=2018-05-02
&leftTicketDTO.from_station=WHN
&leftTicketDTO.to_station=SZN
&purpose_codes=ADULT
由以上四个部分组成,在这里,我们需要提供出发站代码,目的站代码以及出发时间信息
我们输入的是中文,但出发站和目的站代码是相应的缩写,需要进行替换

step5:解析返回的链接信息

我们获得的是json格式的数据
这里最困难的就是找到对应的数据信息
网页html源码中,寻找class对应的id,再到对应js中寻找每个元素对应的信息
这里可以根据对应的缩写大致确定一些值,其他的只能通过一个个试了(其中动卧是,上海-重庆-成都,这条线上面的)
这里写图片描述
这里写图片描述
这里面cq(0)~cq(36)显示了相关的信息

step6:将返回的车站代码替换成中文

new_dict = {v : k for k, v in dict.items()}

step7:显示设置

用PrettyTable来显示对应值
https://blog.csdn.net/codeway3d/article/details/52798804


代码1:获取车票信息

parse_stations.py

import re  # 用正则表达式提取信息
import requests  # 获取网页信息
from pprint import pprint  # 整齐显示

url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9051'
response = requests.get(url)
stations = re.findall(u'([\u4e00-\u9fa5]+)\|([A-Z]+)', response.text)
pprint(dict(stations), indent=4)
> python parse_stations.py > stations.py

代码2:车票显示

tickets.py

# coding: utf-8
"""命令行火车票查看器

Usage:
    tickets [-gdtkz] <from> <to> <date>

"""
import requests  # 抓取车票信息
from docopt import docopt  # 命令行接口描述语言
from stations import stations  # 从stations.py中输入stations这个字典,用于车站和代码的转换
from prettytable import PrettyTable  # 格式化打印车票信息


def cli():
    arguments = docopt(__doc__)  # 将命令行输入值放入arguments字典中
    from_station = stations.get(arguments['<from>'])  # 获得出发站
    to_station = stations.get(arguments['<to>'])  # 获得到达站
    date = arguments['<date>']  # 获得日期
    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
    )  # 生成12306访问链接
    r = requests.get(url)  # 获取放回的车站信息,是json类型
    available_trains = r.json()['data']['result']  # 提取json中的有用车站信息,准备显示
    table = PrettyTable('车次 出发站 到达站 出发时间 到达时间 历时  '
                        '商务座 一等  二等  高级软卧  软卧 动卧 硬卧 软座 硬座 无座 其他'.split())  #显示列表
    new_stations = {v: k for k, v in stations.items()}  # 将stations中的keys和value交换位置,中文显示出发站和到达站
    for raw_train in available_trains:  # 开始逐行显示信息
        data_list = raw_train.split('|')  # 提取每趟列车的信息
        table.add_row(    # 提取列表中的信息
            [data_list[3],
             new_stations[data_list[6]],
             new_stations[data_list[7]],
             data_list[8],
             data_list[9],
             data_list[10],
             data_list[32],
             data_list[31],
             data_list[30],
             data_list[21],
             data_list[23],
             data_list[33],
             data_list[28],
             data_list[24],
             data_list[29],
             data_list[26],
             data_list[22]])
    print(table)  # 打印信息


if __name__ == '__main__':
    cli()

这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_39393712/article/details/80100167
今日推荐