Python爬蟲 —— 攜程機票數(shù)據(jù)

攜程機票搜索頁面

涉及內(nèi)容:
1舵盈、request模擬請求
2、json解析

目標:
爬取某航線上所有航班價格信息

核心思想:
通過頁面上請求數(shù)據(jù)的API接口桩了,模擬前端請求,獲取json數(shù)據(jù)并將其解析夕土。

Step0. 尋找一個合適的方法

進入攜程機票的搜索界面馆衔,隨便搜索一條航線瘟判,跳轉后你會發(fā)現(xiàn)網(wǎng)址一欄變成了:http://flights.ctrip.com/booking/TAO-SJW-day-1.html?DDate1=2017-10-17
很明顯,你搜索的航線是TAO青島到SJW石家莊角溃,起飛時間2017-10-17拷获,整理一下url的規(guī)則就是:http://flights.ctrip.com/booking/<起飛城市三字碼>-<降落城市三字碼>-day-1.html?DDate1=<起飛日期>

拍腦袋想出來的方法一:直接通過頁面url獲取html代碼,然后對html進行解析减细,獲取到所需元素匆瓜。
-> 要用xpath一層層分析網(wǎng)頁元素,一層層解析下去未蝌,好麻煩巴灾ā!
-> 機票價格是Ajax異步請求萧吠!頁面html源碼中沒有這部分數(shù)據(jù)的左冬!就算你有耐心用Xpath定位,也找不到哇纸型!

拍腦袋想出來的方法二:利用selenium框架拇砰,通過webdriver操縱瀏覽器完成爬取
-> 可以解決方法一中動態(tài)頁面獲取不到源碼的問題,用xpath可以定位到元素了狰腌。
-> 可是除破,要是想看每個航班下所有票價信息的話,還需要點N次“訂票”按鈕琼腔,好麻煩呀瑰枫!
-> 我用selenium嘗試了一下,發(fā)現(xiàn)如果這個航線下的航班很多展姐,滾動條不往下拉是不會把后面的航班加載出來的呀躁垛!這可咋整呀我無法預判這條航線下有多少航班呀。每條航線都拖動滾動條3次圾笨?5次教馆?10次?太傻了擂达!

……出于以上種種原因
可以用的方法三:我選擇直接利用ajax請求接口土铺,模擬請求,獲取json數(shù)據(jù)

Step1. 找到API的地址

打開Chrome瀏覽器的開發(fā)者模式板鬓,然后重新搜索一條航線悲敷。
開發(fā)者模式 -> Networks -> XHR里面有一個耗時格外長的請求!


估計就是你了俭令!點開看一下Query String后德,嗯是航線信息,的確就是這個請求抄腔。獲取這個請求的地址瓢湃,也就是Request URL理张。

把Request URL后面這一大串復制出來,整理一下:

request_url = 'http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?' \
                  + 'DCity1=' + dcity \       # 起飛城市三字碼
                  + '&ACity1=' + acity \     # 降落城市三字碼
                  + '&SearchType=S' \
                  + '&DDate1=' + ddate \    # 起飛日期
                  + '&IsNearAirportRecommond=0' \
                  + '&LogToken=8428f186c3504a6ea71158b344a502f5' \
                  + '&rk=0.1311117634227288233503' \
                  + '&CK=05F016D386A1975EFCF0F1240BA33457' \
                  + '&r=0.37113914798207880745716'

request_url后面有奇奇怪怪的四個字段绵患,LogToken雾叭,rkCKr落蝙,但是我在頁面源代碼中只找到了rk的定義织狐,沒有找到另外兩個值的來源。嘗試了一下發(fā)現(xiàn)沒有后面四個字段筏勒,也是可以可以獲取到json數(shù)據(jù)的移迫,因此直接忽略。

源碼中找到的rk定義:&rk=' + Math.random()*10+'223600','0.31100000101726617620017');

Step2. 模擬請求

在Chrome中的Request Headers可以看到這個請求頭有以下信息:

一般情況下模擬請求頭首先要做的就是設置用戶代理:

ctrip_header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36'}

有了用戶代理之后奏寨,我們嘗試模擬請求:

# coding:utf-8
import urllib2


ctrip_header = {'User-Agent':
                    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36'}

def search_flight(dcity, acity, ddate):
    request_url = 'http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?' \
                + 'DCity1=' + dcity \
                + '&ACity1=' + acity \
                + '&SearchType=S' \
                + '&DDate1=' + ddate
    request = urllib2.Request(request_url, headers=ctrip_header)
    response = urllib2.urlopen(request)
    return_json = response.read()
    print return_json


if __name__ == '__main__':
    search_flight('TAO', 'SJW', '2017-10-17')

運行結果:


發(fā)現(xiàn)返回的json當中并沒有想要的數(shù)據(jù)起意,這可能是我們請求的過程中缺少了某些信息導致的。
查看Request Headers中病瞳,除了User-Agent以外還有很多其他的字段揽咕,嘗試將這些字段加入ctrip_header

# coding:utf-8
import urllib2


ctrip_header = {'User-Agent':
                    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36',
                'Host': 'flights.ctrip.com',
                'Referer': 'http://flights.ctrip.com/booking/TAO-SJW-day-1.html?DDate1=2017-10-16'}


def search_flight(dcity, acity, ddate):
    request_url = 'http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?' \
                + 'DCity1=' + dcity \
                + '&ACity1=' + acity \
                + '&SearchType=S' \
                + '&DDate1=' + ddate
    request = urllib2.Request(request_url, headers=ctrip_header)
    response = urllib2.urlopen(request)
    return_json = response.read()
    print return_json

if __name__ == '__main__':
    search_flight('TAO', 'SJW', '2017-10-17')

運行結果:

成功了!我本以為需要有Cookies才能請求成功的套菜!
還好不需要Cookies亲善!我還不太會獲取Cookies,如果一定需要的話逗柴,我只能從Chrome里強行復制一波……(捂臉逃蛹头,順便求Cookies偽造的教學)

Step3. 解析json數(shù)據(jù)

首先我們需要將剛剛請求到json數(shù)據(jù)轉換為可讀的格式,可以用json.loads()這個函數(shù)將json字符串轉換為可讀的字典戏溺。即:

    return_data = json.loads(return_json, encoding='gbk')

注意前面運行結果可以看出渣蜗,字符串存在顯示不出來的情況,這是因為我使用的python2.7存在編碼問題旷祸,需要進行編碼轉換耕拷,即encoding='gbk'

找到所需數(shù)據(jù):

我們需要什么數(shù)據(jù)呢?
所有的航班號托享,及每個航班號下對應的所有價格骚烧。

剛剛我們看的是Headers里的信息,現(xiàn)在切到Preview里闰围。Preview里的信息是格式化的返回json赃绊,在這里我們可以很清晰的找到我們需要的數(shù)據(jù)。

可以看到羡榴,fis是一個航班列表碧查,每個都是一個json,包含航班信息校仑,航班價格信息等等等
那么我們只需要提取fis列表中的一些有用的value值就好了么夫。

    flight_list = return_data['fis']       # 下挖到航班列表的結點
    flight_nums = len(flight_list)      # 航班數(shù)
    for i in range(flight_nums):
        airline = flight_list[i]['alc']         # 航空公司
        flight_no = flight_list[i]['fn']         # 航班號
        price_list = [each['p'] for each in flight_list[i]['scs'] if each['hotel'] is None]     # 非飛宿產(chǎn)品價格

運行結果:

完整代碼:

# coding:utf-8
import urllib2
import json


ctrip_header = {'User-Agent':
                    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36',
                'Host': 'flights.ctrip.com',
                'Referer': 'http://flights.ctrip.com/booking/TAO-SJW-day-1.html?DDate1=2017-10-16'}


def search_flight(dcity, acity, ddate):
    request_url = 'http://flights.ctrip.com/domesticsearch/search/SearchFirstRouteFlights?' \
                + 'DCity1=' + dcity \
                + '&ACity1=' + acity \
                + '&SearchType=S' \
                + '&DDate1=' + ddate
    request = urllib2.Request(request_url, headers=ctrip_header)
    response = urllib2.urlopen(request)
    return_json = response.read()
    # print return_json
    return_data = json.loads(return_json, encoding='gbk')

    flight_list = return_data['fis']
    # print flight_list
    flight_nums = len(flight_list)
    print '共有航班:', flight_nums, '趟'
    for i in range(flight_nums):
        airline = flight_list[i]['alc']         # 航空公司
        flight_no = flight_list[i]['fn']         # 航班號
        print '攜程', airline, flight_no,
        price_list = [each['p'] for each in flight_list[i]['scs'] if each['hotel'] is None]     # 非飛宿產(chǎn)品價格
        print price_list


if __name__ == '__main__':
    search_flight('TAO', 'SJW', '2017-10-17')

注:代碼十分不規(guī)范者冤,完全沒寫異常處理。近期我會努力糾正自己的習慣档痪!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市邢滑,隨后出現(xiàn)的幾起案子腐螟,更是在濱河造成了極大的恐慌,老刑警劉巖困后,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乐纸,死亡現(xiàn)場離奇詭異,居然都是意外死亡摇予,警方通過查閱死者的電腦和手機汽绢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侧戴,“玉大人宁昭,你說我怎么就攤上這事⌒锼危” “怎么了积仗?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蜕猫。 經(jīng)常有香客問我寂曹,道長,這世上最難降的妖魔是什么回右? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任隆圆,我火速辦了婚禮,結果婚禮上翔烁,老公的妹妹穿的比我還像新娘渺氧。我一直安慰自己,他們只是感情好租漂,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布阶女。 她就那樣靜靜地躺著,像睡著了一般哩治。 火紅的嫁衣襯著肌膚如雪秃踩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天业筏,我揣著相機與錄音憔杨,去河邊找鬼。 笑死蒜胖,一個胖子當著我的面吹牛消别,可吹牛的內(nèi)容都是我干的抛蚤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼寻狂,長吁一口氣:“原來是場噩夢啊……” “哼岁经!你這毒婦竟也來了?” 一聲冷哼從身側響起蛇券,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缀壤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后纠亚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體塘慕,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年蒂胞,在試婚紗的時候發(fā)現(xiàn)自己被綠了图呢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡骗随,死狀恐怖蛤织,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蚊锹,我是刑警寧澤瞳筏,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站牡昆,受9級特大地震影響姚炕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丢烘,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一柱宦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧播瞳,春花似錦掸刊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至牌芋,卻和暖如春蚓炬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躺屁。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工肯夏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓驯击,卻偏偏與公主長得像烁兰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子徊都,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理沪斟,服務發(fā)現(xiàn),斷路器暇矫,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向對象的用電信息數(shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,970評論 6 13
  • iOS開發(fā)系列--網(wǎng)絡開發(fā) 概覽 大部分應用程序都或多或少會牽扯到網(wǎng)絡開發(fā)币喧,例如說新浪微博、微信等袱耽,這些應用本身可...
    lichengjin閱讀 3,661評論 2 7
  • 1 前言 作為一名合格的數(shù)據(jù)分析師,其完整的技術知識體系必須貫穿數(shù)據(jù)獲取干发、數(shù)據(jù)存儲朱巨、數(shù)據(jù)提取、數(shù)據(jù)分析枉长、數(shù)據(jù)挖掘冀续、...
    whenif閱讀 18,073評論 45 523
  • 1、感恩父母給予我生命必峰。 2洪唐、感恩祖輩將我養(yǎng)育。 3吼蚁、感恩母親凭需、祖母為家里的巨大付出。 4肝匆、感恩妻子一直的支持粒蜈、包...
    朱曉軍閱讀 180評論 0 2