zoukankan      html  css  js  c++  java
  • 使用scrapy进行12306车票查询

    概述

    通过12306的查询API进行查询某日火车票, 结果保存在csv文件中.

    详细

    一、环境搭建

    1. 安装配置python3.6

    示例网站使用的是python 3.6.1

    下载地址:https://www.python.org/downloads/release/python-361/

    根据自己的系统选择相应的版本

    2. 安装Twisted

    Windows:

    进入http://www.lfd.uci.edu/~gohlk...下载对应twisted

    QQ图片20180312102009.png

    转到下载目录, 命令行执行:pip install Twisted-17.9.0-cp36-cp36m-win_amd64.whl

    3. 安装Scrapy

    mac或linux:

    pip install Scrapy

    windows:

    pip install pywin32

    pip install Scrapy


    二、项目结构以及程序实现

    QQ图片20180312103634.png

    上图是使用scrapy startproject spider12306 命令生成的基本模板, 之后使用scrapy genspider search 12307.cn 生成了一个基本爬虫,在此基础上进行自己需要的爬虫改写.

    思路:

    找到网页接口——进行查询后通过chrome找到查询地址是这样的:

    image.png

    通过这个地址可以看出,查询是通过向https://kyfw.12306.cn/otn/leftTicket发送GET请求来执行查询的。参数一共有4个:

    leftTicketDTO.train_date: 日期

    leftTicketDTO.from_station: 出发站

    leftTicketDTO.to_station: 到达站

    purpos_codes:车票类型 ADULT 成人票

    现在有一个问题,出发站和到达站用的是缩写,查询返回的结果用的也是缩写,所以我们需要知道英文缩写对应的车站,之后我就找到了这个东西:

    image.png

    有一个名为:station_name 的js文件,其中就记录所有的中文站名以及其缩写。

    通过正则等方法将其保存为两个json文件(本人用的是笨办法),键值对分别是:

    站点名: 缩写 以及 缩写: 站点名 方便我们将来查询

    之后就可以编写爬虫了

    1. 根据顺序来我们先设置起始站点为查询站点缩写的js文件

    class SearchSpider(scrapy.Spider):
    
        name = 'search'
        allowed_domains = ['12306.cn']
        # 出发时间 日期如果小于今天  会报错的
        train_data = '2018-03-22'
        # 出发站
        from_station = '郑州'
        # 到
        to_station = '杭州'
    
        start_urls = ['https://kyfw.12306.cn/otn/resources/js'
                      '/framework/station_name.js?station_version=1.9048']

    2. 解析并保存结果为json文件

    if not os.path.exists('stations.json'):
        text = response.body.decode('utf-8')
        content = re.match('.+?(@.+)', text)
        if content:
            # 获取所有车站信息
            text = content.group(1)
            # 进行清洗后写入json文件
            l = text.split('|')
            a, b = 1, 2
            stations = {}
            search = {}
            while b < len(l):
                stations[l[a]] = l[b]
                search[l[b]] = l[a]
                a += 5
                b += 5
            stations = json.dumps(stations, ensure_ascii=False)
            with open('stations.json', 'w', encoding='utf-8') as f:
                f.write(stations)
            search = json.dumps(search, ensure_ascii=False)
            with open('search.json', 'w', encoding='utf-8') as f:
                f.write(search)
        else:
            (response.body.decode())

    3. 根据需要查询的内容向查询地址发出get请求并接受查询结果

    with open('stations.json', 'rb') as f:
        station = json.load(f)
    query_url = 'https://kyfw.12306.cn/otn/leftTicket/queryZ?' 
                'leftTicketDTO.train_date={}&' 
                'leftTicketDTO.from_station={}&' 
                'leftTicketDTO.to_station={}&' 
                'purpose_codes=ADULT'.format(
                    self.train_data, station[self.from_station],
                    station[self.to_station])
    yield scrapy.Request(query_url, callback=self.query_parse)

    4. 解析查询结果并保存为csv文件(可使用excel打开)

    通过观察发现,返回的结果都是用'|'隔开的,貌似只能用下标来定位, 所以采用了下面的方法,如果有更好的方法请联系我,谢谢!

    def query_parse(self, response):
        """解析查询结果"""
        text = response.body.decode('utf-8')
        message_fields = ['车次', '始发站', '终点站', '出发站', '到达站', '出发时间', '到达时间',
                          '历时', '特等座', '一等座', '二等座', '软卧', '硬卧', '硬座', '无座']
        writer = csv.writer(open('ans.csv', 'w'))
        writer.writerow(message_fields)
        infos = json.loads(text)['data']['result']
        with open('search.json', 'rb') as f:
            search = json.load(f)
        for info in infos:
            info = info.split('|')[3:]
            if info[8] == 'N':
                continue
            row = [info[0], search[info[1]], search[info[2]], search[info[3]],
                   search[info[4]], info[5], info[6], info[7], info[29],
                   info[28], info[27], info[20], info[25], info[26], info[23]]
            writer.writerow(row)
        pass

    image.png

    详细代码在例子包中, 仅供参考.....

    运行

    进入spider12306文件夹,在装有scrapy的虚拟环境或真实环境中运行

    scrapy crawl search

    即可, 然后可在运行目录找到 ans.csv 文件 打开后类似上图

    注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

  • 相关阅读:
    开启power management功能有坑,ESP32串口频繁出现UART_BREAK中断
    ESP32音频开发板ESP32-Korvo V1.1踩坑
    驱动开发常用位运算
    ESP8266 RTOS 开发笔记(4)串口透传
    mosquitto服务状态监控(转载)
    ESP8266 RTOS 开发笔记(3)用户参数
    ESP8266 RTOS 开发笔记(2)TCP Client+Server
    ESP8266 RTOS 开发笔记(1)STA+AP模式(共存)
    C uint32 转 uint8
    python 简易计算器(只能计算加减乘除和括号)
  • 原文地址:https://www.cnblogs.com/demodashi/p/9452868.html
Copyright © 2011-2022 走看看