1. 程式人生 > >使用scrapy進行12306車票查詢

使用scrapy進行12306車票查詢

split codes field als project amd64 otn mark 基礎上

概述

通過12306的查詢API進行查詢某日火車票, 結果保存在csv文件中.

詳細

代碼下載:http://www.demodashi.com/demo/12623.html

一、環境搭建

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

技術分享圖片

轉到下載目錄, 命令行執行: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


二、項目結構以及程序實現

技術分享圖片

上圖是使用scrapy startproject spider12306 命令生成的基本模板, 之後使用scrapy genspider search 12307.cn 生成了一個基本爬蟲,在此基礎上進行自己需要的爬蟲改寫.

思路:

找到網頁接口——進行查詢後通過chrome找到查詢地址是這樣的:

技術分享圖片

通過這個地址可以看出,查詢是通過向https://kyfw.12306.cn/otn/leftTicket發送GET請求來執行查詢的。參數一共有4個:

leftTicketDTO.train_date: 日期

leftTicketDTO.from_station: 出發站

leftTicketDTO.to_station: 到達站

purpos_codes:車票類型 ADULT 成人票

現在有一個問題,出發站和到達站用的是縮寫,查詢返回的結果用的也是縮寫,所以我們需要知道英文縮寫對應的車站,之後我就找到了這個東西:

技術分享圖片

有一個名為: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

技術分享圖片

詳細代碼在例子包中, 僅供參考.....

運行

進入spider12306文件夾,在裝有scrapy的虛擬環境或真實環境中運行

scrapy crawl search

即可, 然後可在運行目錄找到 ans.csv 文件 打開後類似上圖

代碼下載:http://www.demodashi.com/demo/12623.html

註:本文著作權歸作者,由demo大師發表,拒絕轉載,轉載需要作者授權

使用scrapy進行12306車票查詢