使用scrapy進行12306車票查詢
概述
通過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車票查詢