从零开始写Python爬虫 --- 爬虫应用: 12306火车票信息查询

从零开始写Python爬虫 --- 爬虫应用: 12306火车票信息查询

好久没更新了,我才不会 告诉你们我沉迷django开发了 话说昨在知乎上看到了这个: 两把王者荣耀的时间,学会Python爬虫 想想自己也有好长时间没有写爬虫了,就去听了一波, 顺便吧这个功能增加到自己的公众号里。 实验楼的代码君小哥哥貌似是第一次直播,还有点小紧张呢!

先看一下效果图:




说一下实现的原理:

其实非常简单,主要是调用了 12306的查询接口,得到返回数据后,再格式化输出

步骤如下:

  • 寻找查询接口
  • 理解接口的调用
  • 找到调用时的城市名代码
  • 编写脚本调用接口(返回的是json格式的数据)
  • 格式画数据后接入公众号

代码的实现:

调用接口时需要的城市代码字典

'''
获取12306城市名和城市代码的数据
文件名: parse_station.py
'''
import requests
import re

#关闭https证书验证警告
requests.packages.urllib3.disable_warnings()
# 12306的城市名和城市代码js文件url
url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9018'
r = requests.get(url,verify=False)
pattern = u'([\u4e00-\u9fa5]+)\|([A-Z]+)'
result = re.findall(pattern,r.text)
station = dict(result)
print(station)

接着将字典保存在文件中:

在终端输入: python3 parse_stations.py >> stations.py

这样,就通过linux的导入功能,将字典文件保存在本地,方便我们一会调用


调用接口,爬取信息

'''
查询两站之间的火车票信息

输入参数: <date> <from> <to>

12306 api:
'https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2017-07-18&leftTicketDTO.from_station=NJH&leftTicketDTO.to_station=SZH&purpose_codes=ADULT'

'''
import requests
import json

# 关闭https证书验证警告
requests.packages.urllib3.disable_warnings()

# 城市名代码查询字典
# key:城市名 value:城市代码
from .stations import stations_dict
# 反转k,v形成新的字典
code_dict = {v: k for k, v in stations_dict.items()}

def get_query_url(text):
    '''
    返回调用api的url链接
    '''
    # 解析参数 aggs[0]里是固定字符串:车票查询 用于匹配公众号接口
    args = str(text).split(' ')
    try:
        date = args[1] 
        from_station_name = args[2] 
        to_station_name = args[3]
        from_station=stations_dict[from_station_name]
        to_station = stations_dict[to_station_name]
    except:
        date,from_station,to_station='--','--','--' 
    #将城市名转换为城市代码
    
    # api 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)
    print(url)
    
    return url

def query_train_info(url):
    '''
    查询火车票信息:
    返回 信息查询列表
    '''

    info_list = []
    try:
        r = requests.get(url, verify=False)
        # 获取返回的json数据里的data字段的result结果
        raw_trains = r.json()['data']['result']

        for raw_train in raw_trains:
            # 循环遍历每辆列车的信息
            data_list = raw_train.split('|')

            # 车次号码
            train_no = data_list[3]
            # 出发站
            from_station_code = data_list[6]
            from_station_name = code_dict[from_station_code]
            # 终点站
            to_station_code = data_list[7]
            to_station_name = code_dict[to_station_code]
            # 出发时间
            start_time = data_list[8]
            # 到达时间
            arrive_time = data_list[9]
            # 总耗时
            time_fucked_up = data_list[10]
            # 一等座
            first_class_seat = data_list[31] or '--'
            # 二等座
            second_class_seat = data_list[30]or '--'
            # 软卧
            soft_sleep = data_list[23]or '--'
            # 硬卧
            hard_sleep = data_list[28]or '--'
            # 硬座
            hard_seat = data_list[29]or '--'
            # 无座
            no_seat = data_list[26]or '--'

            # 打印查询结果
            info = ('车次:{}\n出发站:{}\n目的地:{}\n出发时间:{}\n到达时间:{}\n消耗时间:{}\n座位情况:\n 一等座:「{}\n二等座:「{}\n软卧:「{}\n硬卧:「{}\n硬座:「{}\n无座:「{}\n\n'.format(
                train_no, from_station_name, to_station_name, start_time, arrive_time, time_fucked_up, first_class_seat,
                second_class_seat, soft_sleep, hard_sleep, hard_seat, no_seat))

            info_list.append(info)

        return info_list
    except:
        return ' 输出信息有误,请重新输入'

这个脚本的功能是这样的: 首先 调用 get_query_url()函数,来生成符合api要求的url链接 接着 调用 query_train_info()函数 来获取火车票查询信息

把结果输出



将功能接入公众号服务器:

这个地方我就不上完整的代码了 给出这个功能的分支代:

# 针对火车票查询特殊处理
        elif msg_content[:4] == '车票查询':
            info_list = query_train_info(get_query_url(msg_content))
            text = '由于微信文本长度限制,只能回复时间最新的5条列车信息\n\n'+''.join(info_list[0:5])
            return parser_text(xml, text)


单独看这一段代码,可能觉得没头没脑的,

关于公众号的接入,可以看这里: 从零开始写Python爬虫 --- 爬虫应用: requests+django实现微信公众号后台

看完之后,你就肯定能明白这端代码是啥意思啦!

最后:

这篇文章只是大概记录了如何实现这个功能, 具体的如何寻找:

  • 12306api接口
  • 城市代码字典
  • 命令行工具
  • 彩色列表输出

大家可以去找一下 实验楼小哥哥 的视频录像, 整个过程还是非常愉快的! 感谢!!


哦哦对了,不建议大家刚开始学写代码就用vim

新人上手还是有一些难度的。

在服务区写一些脚本的时候我推荐一个更加轻量级的工具:「nano」

有这方面需要的可以尝试一下。

暑假一直忙着学车,都已经黑的认不出自己来了。(逃)


每天的学习记录都会 同步更新到

微信公众号: findyourownway

知乎专栏:zhuanlan.zhihu.com/Ehco

blog : www.ehcoblog.ml

Github: github.com/Ehco1996/Pyt

编辑于 2017-07-20

文章被以下专栏收录