Python3.x 抓取12306車次信息,表格詳情顯示却嗡,讓你學(xué)會思路,分析網(wǎng)站特點嘹承,爬取數(shù)據(jù)窗价。12306車票查看器!

我的例子都比較適合新手叹卷,那種老司機(jī)請繞道舌镶,謝謝!

ps

查詢車票接口被更換了豪娜,就是多了一個O而已餐胀,不知道啥時候又要換成什么樣?我tm能說是開發(fā)后臺的那個逼輸錯單詞了不https://kyfw.12306.cn/otn/leftTicket/queryO?leftTicketDTO.train_date=2017-10-31&leftTicketDTO.from_station=GIW&leftTicketDTO.to_station=ZIW&purpose_codes=ADULT

前言

最近學(xué)習(xí)Python瘤载,所以呢否灾?跟大家一樣,都是看看官網(wǎng)鸣奔,看看教程墨技,然后就準(zhǔn)備搞一個小東西來試試,那么我使用的例子是實驗樓中的12306火車票查詢例子挎狸。但是那個是2.7版本的扣汪,并且那個實驗樓的ubuntu系統(tǒng)老是一些包裝不上,沒辦法就在我電腦上搞好了锨匆。

結(jié)果展示:

我在window上運行的結(jié)果

下面這一段說明我是抄的崭别,哈哈,因為我自己再怎么寫還不是同樣的內(nèi)容。

讓我們先給這個小應(yīng)用起個名字吧恐锣,既然及查詢票務(wù)信息茅主,那就tickets,其實 大家隨意了,需要發(fā)布就需要起一個更好的名字土榴,不然只要自己玩兒的懂诀姚,但是要有程序的特點,所以還是tickets相關(guān)的吧玷禽。方便閱讀和自己記憶赫段。

我們希望用戶只要輸入出發(fā)站呀打,到達(dá)站以及日期就讓就能獲得想要的信息,比如要查看10月31號貴陽-遵義西的火車余票糯笙, 我們只需輸入:

python3.5 lnlr.py 貴陽 遵義西 2017-10-31

注意:上面的日期(包括后面的)是筆者寫文章時確定的日期聚磺,當(dāng)你在做這個項目的時候可能要根據(jù)當(dāng)前時間做適當(dāng)調(diào)整。

轉(zhuǎn)化為程序語言就是:

python3.5 lnlr.py from to date

另外炬丸,火車有各種類型,高鐵蜒蕾、動車稠炬、特快、快速和直達(dá)咪啡,我們希望可以提供選項只查詢特定的一種或幾種的火車首启,所以,我們應(yīng)該有下面這些選項:

-g 高鐵
-d 動車
-t 特快
-k 快速
-z 直達(dá)
這幾個選項應(yīng)該能被組合使用撤摸,所以毅桃,最終我們的接口應(yīng)該是這個樣子的:

python3.5 lnlr.py [options] from to date

接口已經(jīng)確定好了,剩下的就是實現(xiàn)它了准夷。

環(huán)境

Centos 7 linux 系統(tǒng)
Python3.5.2

使用到的庫

docopt------>命令行解釋器(把我玩兒死)
colorama--->一個文本著色器
requests --->爬蟲必備钥飞,http請求庫
prettytable->表格顯示

安裝庫

  1. 未安裝之前


    Linux上面目前的庫

安裝庫:

pip3.5 install requests colorama docopt prettytble

  1. 安裝之后


    安裝完成之后的庫列表

ok,我們環(huán)境有了衫嵌,庫有了读宙,那么應(yīng)該干啥呢?

爬蟲個人分析:

  1. 制定爬取內(nèi)容
  2. 選取目標(biāo)
  3. 準(zhǔn)備環(huán)境楔绞,上面就提前說了结闸,因為這個本來就是在搞爬蟲,所以...
  4. 分析該網(wǎng)站的html結(jié)構(gòu)酒朵,得到url
  5. 爬取數(shù)據(jù)
  6. 分析數(shù)據(jù)
  7. 封裝數(shù)據(jù)(組裝數(shù)據(jù))桦锄,弄成自己想要的樣子
  8. coding......

那么我們開始吧

第一步

當(dāng)然是打開12306的官網(wǎng)了,然后進(jìn)行一個余票查詢蔫耽,當(dāng)然首先你得按一下f12结耀,打開控制臺面板哦。
我是查詢的是:貴陽--遵義西 10-31號的車票

f12之后匙铡,查票頁面

我先埋下一個伏筆:

我看到的貴陽-遵義 10-31的車次一共是11個班次饼记。

第二步

首先在控制臺找到Network按鈕,點擊慰枕。然后選擇XHR ---》找到請求到后臺的接口具则,

請求接口

那么我們先看一個三個接口的請求和返回的數(shù)據(jù):
1.https://ad.12306.cn/sdk/webservice/rest/appService/getAdAppInfo.json?placementNo=0004&clientType=2&billMaterialsId=28e783cd2ec048ee8575cc3e502292c2
查看返回的結(jié)果:
貌似沒有什么有用的信息。

  1. https://kyfw.12306.cn/otn/leftTicket/log?leftTicketDTO.train_date=2017-10-31&leftTicketDTO.from_station=GIW&leftTicketDTO.to_station=ZIW&purpose_codes=ADULT
    好像也看不到關(guān)于貴陽-遵義的任何信息

3.https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2017-10-31&leftTicketDTO.from_station=GIW&leftTicketDTO.to_station=ZIW&purpose_codes=ADULT

第三個接口返回的數(shù)據(jù)

哈哈具帮,在里面我看到了貴陽博肋,遵義低斋,那么大膽的猜測這個接口有可能就是我們需要的。
我們繼續(xù)點開看看有什么東西匪凡,這些數(shù)據(jù)都是以json的格式傳遞過來的膊畴。


展開結(jié)果

到這里我相信,聰明的人已經(jīng)知道了這個就是我們所需要的接口了病游,而這些數(shù)據(jù)就絕對是車次信息的數(shù)據(jù)唇跨。
由上面的我f12查看到的數(shù)據(jù)是11條,那么你們就沒有點小激動么衬衬?
說明這個接口就是我們所需要的接口無誤买猖。那么現(xiàn)在我們就要得到它的url咯。
靠滋尉,雙十一快到了玉控,被女朋友抓去看了一會兒衣服,可能今天就不寫了狮惜,明天接著寫高诺。

那么這樣:我就明天開始分析url,然后就coding
請求的接口URL:

https://kyfw.12306.cn/otn/leftTicket/query?leftTicketDTO.train_date=2017-10-31&leftTicketDTO.from_station=GIW&leftTicketDTO.to_station=ZIW&purpose_codes=ADULT
分析:
1. 查看請求方式 POST/GET(常用的),這里使用的是GET請求
2. 肯定帶有參數(shù)了碾篡,并且GET請求是拼接到url之后的虱而,我們查詢的時候是輸入了起始地點,目的地點开泽,出發(fā)時間薛窥。那么url上也應(yīng)該帶有這三個。
3. 得到參數(shù)名稱:leftTicketDTO.train_date=2017-10-31,leftTicketDTO.from_station=GIW,leftTicketDTO.to_station=ZIW
還有一個參數(shù):purpose_codes=ADULT 根據(jù)ADULT的意思(成人眼姐,成年)大膽猜測這就是學(xué)生票和成人票诅迷。
4.得到了四個參數(shù),但是我們還不知道其中有兩個GIW,ZIW是什么意思众旗。
因為我輸入的是中文罢杉,但是出現(xiàn)的是字母代號。做過前后臺交互的同學(xué)應(yīng)該覺得這種是很常見的贡歧。目的是避免了中文傳輸導(dǎo)致的問題滩租。

分析參數(shù)的獲取

leftTicketDTO.train_date=2017-10-31 時間
leftTicketDTO.from_station=GIW 出發(fā)地
leftTicketDTO.to_station=ZIW 目的地
同學(xué)們請注意:我們輸入的是中文,出來的是地點代碼利朵,說明中間有一層轉(zhuǎn)換律想,那么在常規(guī)的網(wǎng)站中,只有兩種三種方式能這樣處理绍弟?

  1. 將這個地點-地點代碼字典寫入js中技即,這個地方有可能,因為國內(nèi)的地點太多樟遣,需要手動維護(hù)而叼。
  2. 將地點-地點代碼字典寫入本地文件文件身笤,做好緩存,每次讀取文件葵陵,然后使用液荸。
  3. 從遠(yuǎn)端服務(wù)器進(jìn)行獲取,在這里也沒必要脱篙,因為每次都要去請求后臺娇钱,增加服務(wù)器的壓力,這個是沒必要的绊困,因為這個字典的話是基本不會變化的文搂。

ok經(jīng)過上面的分析,我們就能很清楚的知道這個字典絕對是從js獲取的考抄,那么我們就也一樣的使用發(fā)f12來檢查到資源,找到該頁面所引用的所有js,然后進(jìn)行分析蔗彤。

該頁面所加載的js文件

上圖中的矩形中的就是當(dāng)前頁面中的所有js,當(dāng)然每個js的作用我就不一一的說了川梅,各位需要幫助的可以email(leihfein@gmail.com)我,或者在下面留言然遏。
那么我直接查看各個的內(nèi)容贫途,發(fā)現(xiàn)有一個是:

包含了地點,地點代碼js

這樣我們就得到了一個js的請求地址哦待侵。https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9028

瀏覽器中輸入該URL看到的結(jié)果

我們還可以來一個測試:
我在查詢的時候是輸入了丢早,貴陽-遵義,搜索一下看看吧秧倾。

搜索

同學(xué)們怨酝,看到這個你們覺得爽不爽,說明這個文件就是我們所需要的那先。

ok农猬,到這里,編碼前期準(zhǔn)備工作售淡,所有的都昨晚了斤葱,我從一步一步的分析,然后截圖揖闸。給大家思路揍堕,方法,步驟汤纸。希望大家能夠更明白衩茸,更多的是學(xué)習(xí)到其中的分析思路哈。

codingwars

  1. 首先爬取地點-代碼code字典贮泞。
#!/usr/bin/env python3
# coding: utf-8

import requests
import re
from pprint import pprint
"""
  獲取到地點-地點code字典
"""
def get_station():
        url = 'https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9028'
        response = requests.get(url,verify=False)
        station = re.findall(u'([\u4e00-\u95fa5]+)\|([A-Z]+)',response.text)
        pprint(dict(station),indent=4)

if __name__=="__main__":
        get_station()

在最后递瑰,我是使用pprint輸出到屏幕的祟牲,大家可以進(jìn)行拷貝,或者是使用Linux的重定向進(jìn)行輸出到別的文件 抖部。
python3.5 get_station_code.py > stations.py
并且需要在stations.py文件中增加一個名字哦说贝,因為輸出來時也沒有名字的。見下圖

在windows中就只能拷貝了慎颗,
新增一個stations字典名稱

好的乡恕,到這里我們的地點-地點代碼就得到了,那么我們就應(yīng)該寫那個爬取車次信息的py了俯萎。

處理輸出的代碼:

from prettytable import PrettyTable

from stations import stations
from colorama import init, Fore

"""
    處理爬取出來的車次信息傲宜,并進(jìn)行表格輸出
"""

init()


class TrickCollection(object):
    def __init__(self, available_trains, options):
        self.header = ('車次 車站 時間 歷時 特等座 一等 二等 高級軟臥 軟臥 動臥 硬臥 '
                       + '軟座 硬座 無座 備注').split()
        self.available_trains = available_trains
        self.options = options

    # 將歷時轉(zhuǎn)化為小時和分鐘的形式
    def get_duration(self, raw_train):
        duration = raw_train[10].replace(':', '小時') + '分'
        if duration.startswith('00'):
            return duration[4:]
        if duration.startswith('0'):
            return duration[1:]
        return duration



    # 返回每個車次的基本信息
    def trains(self):
        for raw_train in self.available_trains:
            # 列車號
            train_no = raw_train[3]
            # 得到什么列車并小寫
            initial = train_no[0].lower()
            # 反轉(zhuǎn)station所對應(yīng)的字典
            stations_re = dict(zip(stations.values(), stations.keys()))
            if not self.options or initial in self.options:
                # 將車次的信息保存到列表中
                # train 出發(fā)地
                begin_station = stations_re.get(raw_train[4])
                # train 目的地
                end_station = stations_re.get(raw_train[5])
                # your 出發(fā)地
                from_station = stations_re.get(raw_train[6])
                # your 目的地
                to_station = stations_re.get(raw_train[7])
                # 判斷是起始還是經(jīng)過
                begin_flag = self.__check_equals(begin_station, from_station)
                end_flag = self.__check_equals(end_station, to_station)
                train = [
                    train_no,
                    '\n'.join([begin_flag + ' ' + self.__get_color(Fore.GREEN, from_station),
                               end_flag + ' ' + self.__get_color(Fore.RED, to_station)]),
                    '\n'.join([self.__get_color(Fore.GREEN, raw_train[8]),
                               self.__get_color(Fore.RED, raw_train[9])]),
                    # 時間
                    self.get_duration(raw_train),
                    # 歷時
                    raw_train[32],
                    # 特等座
                    self.__show_color(raw_train[31]),
                    # 一等
                    self.__show_color(raw_train[30]),
                    # 二等
                    self.__show_color(raw_train[22]),
                    # 高級軟臥
                    self.__show_color(raw_train[23]),
                    # 軟臥
                    self.__show_color(raw_train[33]),
                    # 硬臥
                    self.__show_color(raw_train[28]),
                    # 軟座
                    self.__show_color(raw_train[24]),
                    # 硬座
                    self.__show_color(raw_train[29]),
                    # 無座
                    self.__show_color(raw_train[26]),
                    # 備注
                    self.__show_color(raw_train[1])
                ]
                # 更改不運行車次的時間和歷時
                if raw_train[14] == 'null':
                    train[2] = '--\n--'
                train[3] = '--'
                # 將空字符串轉(zhuǎn)化為‘--’
                for i, item in enumerate(train):
                    if not item:
                        train[i] = '--'
                yield train

    def __check_equals(self, from_station, to_station):
        """
        檢查是否是始、過
            檢查你的起始站是否為該車次的起始站
            檢查你的終止站是否為該車次的終止站
        :param from_station:  出發(fā)位置
        :param to_station:     結(jié)束位置
        :return: 決定了是使用‘始' 還是 ’過‘
        """
        if from_station == to_station:
            return '始'
        else:
            return '過'
    def __get_color(self, color, content):
        """
        返回顏色內(nèi)容組合夫啊,并且清除該內(nèi)容之后的顏色
        :param color: 傳遞的顏色
        :param content: 內(nèi)容
        :return: 返回值為拼接上顏色
        """
        return color + content + Fore.RESET

    def __show_color(self, content):
        """
        對內(nèi)容進(jìn)行顏色顯示函卒,并且只顯示有入蛆,其余不上色
        :param content: 需要顏色顯示的內(nèi)容
        :return: 返回設(shè)置結(jié)果
        """
        if content == '有':
            return Fore.GREEN + content + Fore.RESET
        else:
            return content

    def pretty_print(self):
        """
            顯示內(nèi)容
        :return:
        """
        pt = PrettyTable()
        pt._set_field_names(self.header)
        for train in self.trains():
            pt.add_row(train)
        print(pt)

成果展示:
但是我在遠(yuǎn)端上使用xshell沒有顏色土全,這個是什么鬼。最后發(fā)現(xiàn)是自己設(shè)置xshell而已贡未。
好的熊榛,下面就是我們的程序執(zhí)行的結(jié)果锚国。
如果程序輸入的地點在字典中查詢不到,那么就不能查票玄坦。所以我們需要隨時更新stations.py文件(地點-code字典表)


成果展示

ok血筑,到這里的話,我們的所有的爬蟲就抓取成功煎楣,并且輸出成我們想要的結(jié)果了豺总。我準(zhǔn)備下一步就是搞那個搶票。試試吧择懂。
代碼在后面我會給出github地址的园欣。

總結(jié)

在本次實驗中,我所遇到的問題簡單說一下:

  1. optdoc的使用休蟹,這個是我遇到的最大的坑沸枯,(usage 下面命令之后必須空一行)
  2. 在Linux上的縮進(jìn)問題
    3.就是對python還不是特別的熟。

github地址

12306火車票查看器git地址

閱讀到本教程的童鞋赂弓,喜歡請點個喜歡绑榴,不求贊賞,只求喜歡盈魁,頂上去∠柙酰現(xiàn)在網(wǎng)上很多都是以前的接口的例子,已經(jīng)跑不起來了,所以我希望讓更多的人看到赤套,能幫助更多還在py的起步階段飘痛,又沒有人練手項目的人。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末容握,一起剝皮案震驚了整個濱河市宣脉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剔氏,老刑警劉巖塑猖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谈跛,居然都是意外死亡羊苟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門感憾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜡励,“玉大人,你說我怎么就攤上這事阻桅×挂校” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵鳍刷,是天一觀的道長占遥。 經(jīng)常有香客問我俯抖,道長输瓜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任芬萍,我火速辦了婚禮尤揣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柬祠。我一直安慰自己北戏,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布漫蛔。 她就那樣靜靜地躺著嗜愈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪莽龟。 梳的紋絲不亂的頭發(fā)上蠕嫁,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音毯盈,去河邊找鬼剃毒。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赘阀。 我是一名探鬼主播益缠,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼基公!你這毒婦竟也來了幅慌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤酌媒,失蹤者是張志新(化名)和其女友劉穎欠痴,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秒咨,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡喇辽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了雨席。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菩咨。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖陡厘,靈堂內(nèi)的尸體忽然破棺而出抽米,到底是詐尸還是另有隱情,我是刑警寧澤糙置,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布云茸,位于F島的核電站,受9級特大地震影響谤饭,放射性物質(zhì)發(fā)生泄漏标捺。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一揉抵、第九天 我趴在偏房一處隱蔽的房頂上張望亡容。 院中可真熱鬧,春花似錦冤今、人聲如沸闺兢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屋谭。三九已至,卻和暖如春龟糕,著一層夾襖步出監(jiān)牢的瞬間桐磁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工翩蘸, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留所意,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像扶踊,于是被迫代替她去往敵國和親泄鹏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 看到網(wǎng)上有很多火車票查詢的小腳本秧耗,參考一下备籽,發(fā)現(xiàn)很多都已經(jīng)不能再運行了,據(jù)說12306接口返回的數(shù)據(jù)格式更新比較快...
    lexyhp閱讀 3,787評論 1 3
  • 前幾天看了一個爬取12306來獲得火車票信息的教程分井,發(fā)現(xiàn)12306官網(wǎng)的存儲車票信息的 Json 數(shù)據(jù)格式已經(jīng)變了...
    LiuHDme閱讀 2,066評論 0 12
  • 項目簡介:使用Python3抓取12306網(wǎng)站信息提供一個命令行的火車票查詢工具车猬。通過該項目的實現(xiàn),可以熟悉Pyt...
    海人為記閱讀 1,704評論 0 1
  • 蓋被子 2017.8.31 一直覺得自己對寶爸不夠上心尺锚,在他面前既不賢惠也不體貼珠闰,寶爸會有一些抱怨,我自己也有些自...
    Cici清清閱讀 233評論 0 0
  • 復(fù)習(xí)指南 金融衍生工具(李國華) 期貨市場的產(chǎn)生瘫辩,發(fā)展伏嗜,特點,功能交易流程伐厌,結(jié)算流程承绸,期貨套期保值,期貨投機(jī)挣轨,利率...
    千張卷卷閱讀 321評論 0 0