
“你喜歡旅游嗎?”
這個(gè)簡單的問題經(jīng)常會(huì)得到一個(gè)積極的回復(fù)甚至還會(huì)額外收到一個(gè)或兩個(gè)冒險(xiǎn)的故事。通常來講,旅行是一種體驗(yàn)新文化和拓寬自己視野的好方法。
但如果把問題換成“你喜歡查機(jī)票的過程嗎?”,我敢肯定大家的反應(yīng)一定會(huì)不那么熱情......
那么,用Python解決你的難點(diǎn)吧!本文作者Fábio Neves,一位資深的商業(yè)數(shù)據(jù)分析師將會(huì)帶你建立一個(gè)網(wǎng)絡(luò)爬蟲項(xiàng)目,幫助我們找到最優(yōu)惠的價(jià)格!
具體做法是對(duì)特定目的地以及靈活的日期范圍(根據(jù)你選擇的日期前后最多3天)進(jìn)行航班價(jià)格搜索。
搜索結(jié)果保存到一個(gè)excel中并為你發(fā)送一封展示快速統(tǒng)計(jì)信息的電子郵件。顯然,最終的目的是幫助我們找到最優(yōu)惠的價(jià)格!
如果你真的想試試,你可以在服務(wù)器上執(zhí)行這個(gè)腳本(一個(gè)簡單的Raspberry Pi就可以(注:Raspberry Pi樹莓派又稱卡片式電腦,外形只有信用卡大小,運(yùn)算性能和智能手機(jī)相仿。So大家在自己筆記本電腦上折騰就足夠了。。)),并且每天運(yùn)行一次或兩次。它會(huì)將檢索結(jié)果以郵件的形式發(fā)給你,我建議將excel文件保存到Dropbox云端,這樣你就可以隨時(shí)隨地訪問它。
注:Dropbox是一個(gè)類似于百度云的云端服務(wù)
我還是沒找到任何錯(cuò)誤低價(jià)票,但我想還是有可能的!
它會(huì)根據(jù)“彈性日期范圍”進(jìn)行檢索,以便查找你首選日期的前后最多3天的所有航班。盡管該腳本一次只適用于一組from/to目的地,但你可以輕松地調(diào)整它在每個(gè)循環(huán)內(nèi)運(yùn)行多組行程目的地。你甚至可能最終找到一些錯(cuò)誤低價(jià)票......簡直棒極了!
爬蟲腳本
當(dāng)我第一次開始做網(wǎng)絡(luò)爬蟲時(shí),我對(duì)這塊并不特別感興趣。我本想用預(yù)測建模,財(cái)務(wù)分析和一些情緒分析來做更多的項(xiàng)目,但事實(shí)證明,弄明白如何構(gòu)建第一個(gè)網(wǎng)絡(luò)爬蟲是很有趣的。隨著我不斷學(xué)習(xí),我意識(shí)到網(wǎng)絡(luò)抓取是互聯(lián)網(wǎng)運(yùn)轉(zhuǎn)的精髓。
是的......就像Larry 和 Sergey一樣,在啟動(dòng)爬蟲程序后去盡情享受按摩浴缸吧!
你可能認(rèn)為這是一個(gè)非常大膽的想法,但如果我告訴你谷歌就誕生于Larry 和 Sergey通過Java和Python寫的爬蟲程序呢?谷歌通過爬取整個(gè)互聯(lián)網(wǎng)來試圖為你的問題提供最佳答案。有非常多關(guān)于網(wǎng)絡(luò)爬蟲的應(yīng)用程序,即便你更喜歡數(shù)據(jù)科學(xué)中的其他主題,你仍然需要一些爬蟲技能來獲取想要的數(shù)據(jù)。
Python可以來拯救你
第一個(gè)挑戰(zhàn)是選擇從哪個(gè)平臺(tái)抓取信息。這其實(shí)并不容易,但我最終選擇了Kayak。決定之前我嘗試了Momondo,Skyscanner,Expedia等等,但這些網(wǎng)站上的驗(yàn)證碼部分真的是讓人抓狂。經(jīng)過幾次嘗試選擇交通信號(hào)燈,人行橫道和自行車的這種“你是真人嗎”的檢查后,我的結(jié)論是Kayak是目前最好的選擇,即使它在短時(shí)間內(nèi)加載太多頁面時(shí)也會(huì)拋出安全性校驗(yàn)。
我設(shè)置機(jī)器人以4到6小時(shí)的間隔來查詢網(wǎng)站,這樣就不會(huì)有問題了。在這里和那里偶爾可能會(huì)出現(xiàn)卡殼中斷現(xiàn)象,但是如果你遇到驗(yàn)證碼校驗(yàn),那么你需要手動(dòng)進(jìn)行驗(yàn)證碼認(rèn)證,確認(rèn)完畢后再啟動(dòng)機(jī)器人程序,然后等待幾個(gè)小時(shí)它就會(huì)重置。你也可以隨意將這些代碼應(yīng)用到其他平臺(tái),歡迎你在評(píng)論部分分享你的應(yīng)用!
如果你是個(gè)爬蟲新手,或者還不了解為什么有一些網(wǎng)站總會(huì)設(shè)置各種障礙來阻止網(wǎng)絡(luò)抓取,那么在寫第一行爬蟲代碼之前,請(qǐng)你先閱讀了解一下谷歌“ 網(wǎng)絡(luò)抓取禮儀 ”。如果你像瘋子一樣準(zhǔn)備好了開始網(wǎng)絡(luò)抓取,你獲得努力成果可能會(huì)比你想象的要快得多。
網(wǎng)絡(luò)抓取禮儀 :
http://lmgtfy.com/?q=web+scraping+etiquette
請(qǐng)系好安全帶……
打開chrome標(biāo)簽頁后,我們將定義一些在循環(huán)內(nèi)使用的函數(shù)。關(guān)于整體結(jié)構(gòu)的大致想法是這樣的:
OK,每個(gè)Selenium項(xiàng)目都將以webdriver作為開頭。我用的是ChromeDriver,當(dāng)然還有其他選擇。比如,PhantomJS或Firefox也很受歡迎。webdriver下載好之后,將其放在一個(gè)文件夾中就可以了。代碼的第一行將會(huì)自動(dòng)打開一個(gè)空白的Chrome標(biāo)簽頁。
請(qǐng)注意,我不是在這里開辟新天地,或是提出一種非常具有開拓性的創(chuàng)新。當(dāng)下確實(shí)已經(jīng)有更先進(jìn)的方法來尋找便宜的票價(jià),但我希望我的這個(gè)帖子可以跟大家分享一些簡單而實(shí)用的東西!
這些是我用于整個(gè)項(xiàng)目所引用的包。我將使用randint來讓機(jī)器人在每次搜索之間隨機(jī)停頓幾秒鐘。這是所有機(jī)器人所必備的功能。如果你運(yùn)行了前面的代碼,則需要先打開一個(gè)Chrome網(wǎng)頁窗口作為機(jī)器人檢索的入口。
所以,先讓我們來快速測試一下,在新網(wǎng)頁打開http://kayak.com。選擇你要飛往的城市和日期。選擇日期時(shí),請(qǐng)務(wù)必選擇“+ -3天”。我已經(jīng)編寫了相關(guān)的代碼,如果你只想搜索特定日期,那么你需要適當(dāng)?shù)剡M(jìn)行一些調(diào)整。我將盡量在整個(gè)文本中指出所有的變動(dòng)值。
點(diǎn)擊搜索按鈕并獲取地址欄中的鏈接。這個(gè)鏈接應(yīng)該就是我在下面需要用的鏈接,在這里我將變量kayak定義為url并調(diào)用webdriver的get方法。你的搜索結(jié)果接下來應(yīng)該就會(huì)出現(xiàn)了。
每當(dāng)短時(shí)間內(nèi)多次使用get命令的時(shí)候,系統(tǒng)就會(huì)跳出驗(yàn)證碼檢查。你可以手動(dòng)解決驗(yàn)證碼問題,并在下一個(gè)問題出現(xiàn)之前繼續(xù)測試腳本。從我的測試來看,第一次搜索運(yùn)行似乎一切正常,所以如果你想要用這段代碼,并且讓它們之間保持較長的執(zhí)行間隔,就可以解決掉這個(gè)難題。你并不需要每10分鐘就更新這些價(jià)格,不是嗎?!
XPath的坑
目前為止,我們打開了一個(gè)瀏覽器窗口并獲得了網(wǎng)址。接下來我會(huì)使用XPath或者CSS選擇器來抓取價(jià)格等其他信息。曾經(jīng)我也只用XPath,當(dāng)時(shí)我覺得沒必要用CSS,但是現(xiàn)在看來最好結(jié)合著用。你可以直接用瀏覽器復(fù)制網(wǎng)頁XPath來用,你也會(huì)發(fā)現(xiàn)由XPath雖可以定位網(wǎng)頁元素但是可讀性很差,所以我漸漸意識(shí)到只用XPath很難獲得你想要的頁面元素。有時(shí)候,指向得越細(xì)就越不好用。
接下來,我們用Python來選擇出最低票價(jià)的頁面元素。上述代碼中紅色部分就是XPath選擇器的代碼,在網(wǎng)頁中,你可以在任意位置點(diǎn)擊右鍵并選擇“檢查”來找到它。試試吧,在你想看代碼的地方點(diǎn)右鍵,“檢查”它。
為了說明我前面所說的XPath的不足,請(qǐng)大家對(duì)比如下差異:
1 # This is what the copy method would return. Right click highlighted rows on the right side and select "copy > Copy XPath"http://*[@id="wtKI-price_aTab"]/div[1]/div/div/div[1]/div/span/span2 # This is what I used to define the "Cheapest" buttoncheap_results = ‘//a[@data-code = “price”]’
上述代碼中,第二種方式的簡潔性清晰可見。它會(huì)去搜素具有data-code屬性值為price的a元素。而第一種方式則是去搜素一個(gè)id為wtKI-price_aTab元素,且該元素嵌在5層div及2層span內(nèi)。對(duì)于這次頁面,它能起作用,但這里的坑在于,下次加載頁面時(shí),這個(gè)id會(huì)變,而且每次加載時(shí)wtKI值也是動(dòng)態(tài)變化的,所以到時(shí)候這段代碼就無效了。所以多花點(diǎn)功夫研究一下XPath表示的內(nèi)容還是對(duì)你有價(jià)值的。
不過這種直接復(fù)制XPath的方法對(duì)于那些不是很復(fù)雜善變的頁面來說還是蠻好用的。
基于上述代碼結(jié)果,如果我想找出所有匹配的結(jié)果并存到list里,該怎么做呢?很簡單,因?yàn)樗薪Y(jié)果都在CSS對(duì)象resultWrapper中,只要按照我下圖代碼中寫個(gè)for循環(huán)就能獲得所有結(jié)果。這個(gè)思路掌握了,那下圖的代碼你也就基本看明白了。也就是說,先選定最外層的頁面元素(如本文網(wǎng)站中的resultWrapper),再找一種方式(如XPath)來獲取信息,最后再將信息存到可讀的對(duì)象中(本例中先存在flight_containers中,再存在flights_list中)。
我把前三個(gè)結(jié)果詳細(xì)內(nèi)容都打印出來了,里面有我們需要的全部有用信息,但我們還是要找個(gè)更好的方法提取它們,這時(shí)我們就要對(duì)這些元素單獨(dú)解析。
開始爬數(shù)據(jù)!
最簡單的代碼就是讀取更多這個(gè)函數(shù),我們先從這里開始。我希望在不觸發(fā)安全校驗(yàn)的情況下獲取盡量多的航班,所以在每次加載完頁面我都會(huì)點(diǎn)擊“l(fā)oad more results”按鈕。值得注意的是我用到了try語句,因?yàn)橛械臅r(shí)候不一定會(huì)存在這個(gè)按鈕。
哦嘞,前期鋪墊的有點(diǎn)長(抱歉,我確實(shí)比較容易跑偏)。我們現(xiàn)在要開始定義用于爬數(shù)據(jù)的函數(shù)了。
我在下文會(huì)提到的page_scrape函數(shù)中解析了大部分元素。有時(shí)候,返回來的航班l(xiāng)ist中會(huì)有兩段行程。我簡單粗暴地把它拆成兩個(gè)變量,如section_a_list 和section_b_list。當(dāng)然,函數(shù)還是會(huì)返回一個(gè)名為flights_df 的DataFrame對(duì)象,有了它我們接下來就可以任意排序并視情況切片或合并。
變量名中帶a的表示第一段行程,帶b的表示第二段行程。接著看下一個(gè)函數(shù)。
別急,還有干貨!
到現(xiàn)在為止,我們有用于加載更多結(jié)果的函數(shù),有用于解析這些結(jié)果的函數(shù)。你可以認(rèn)為這就完事了,可以靠著它們?nèi)ナ謩?dòng)地爬網(wǎng)頁了,但我前面還提到過,我們的目標(biāo)是能給自己發(fā)郵件,當(dāng)然還能包括一些其他信息??纯聪旅孢@個(gè)函數(shù)start_kayak,所有這些都在里面。
這需要我們定義一下要查詢的航班的地點(diǎn)和日期。我們會(huì)打開kayak變量中的網(wǎng)址,并且查詢結(jié)果會(huì)直接按照“best”方式排序。在第一次爬數(shù)之后,我就獲得了頁面上方的價(jià)格矩陣數(shù)據(jù)集,它將用于計(jì)算均價(jià)和最低價(jià),然后和Kayak的預(yù)測價(jià)(頁面的左上角)一起通過電子郵件發(fā)出。在單個(gè)日期搜素時(shí)可能導(dǎo)致錯(cuò)誤,因?yàn)檫@種情況下頁面頂端沒有價(jià)格矩陣。
我用outlook郵箱(http://hotmail.com)做了測試。雖然Gmail我沒試過,甚至還有其他各種郵箱,但我想應(yīng)該都沒問題。而且我前文提到的書中也寫了其他發(fā)郵件的方式,如果你有hotmail郵箱,可以直接在代碼中替換你的郵箱信息,就可以用了。
如果你想知道腳本中某部分代碼的功能,你要把那部分拷出來測試一下,因?yàn)橹挥羞@樣你才能徹底地理解它。
把代碼跑起來
當(dāng)然,我們還能把我們前面編的函數(shù)放進(jìn)循環(huán)里讓它一直執(zhí)行。寫明4個(gè)輸入提示,包括起降的城市和起止時(shí)間(輸入)。但在測試的時(shí)候,我們并不想每次都去輸入這個(gè)四個(gè)變量,就直接修改4個(gè)變量,如注釋的那四行代碼所示。
恭喜各位,至此我們已經(jīng)大功告成了!其實(shí)還有很多可以改進(jìn)的地方,比如我能想到的還可以用Twilio實(shí)現(xiàn)發(fā)送短信進(jìn)而取代郵件。你還能架VPN或者以其他隱蔽的方式,同時(shí)通過多個(gè)服務(wù)器來爬數(shù)據(jù)。還有驗(yàn)證碼問題,它們總會(huì)不時(shí)地跳出來,不過這還是有辦法解決的。如果你有比較好的基礎(chǔ),我覺得你可以試試加上這些功能。甚至你還會(huì)想把Excel文件作為郵件的附件一起發(fā)出。
編譯:高延、熊琰、胡笳、蔣寶尚
數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實(shí)戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動(dòng)態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價(jià)值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實(shí)戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時(shí),“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗(yàn)與 t 檢驗(yàn):差異、適用場景與實(shí)踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計(jì)學(xué)領(lǐng)域,假設(shè)檢驗(yàn)是驗(yàn)證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計(jì)劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計(jì)劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對(duì)象的 text 與 content:區(qū)別、場景與實(shí)踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請(qǐng)求開發(fā)時(shí)(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價(jià)值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請(qǐng)求工具對(duì)比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請(qǐng)求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點(diǎn)數(shù)據(jù)的科學(xué)計(jì)數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長浮點(diǎn)數(shù)據(jù)時(shí)的科學(xué)計(jì)數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價(jià)值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營問題、提升執(zhí)行效率的核心手段,其價(jià)值 ...
2025-09-12用 SQL 驗(yàn)證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實(shí)戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計(jì)” 與 “用戶體驗(yàn) ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動(dòng)下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價(jià)值 在數(shù)據(jù)驅(qū)動(dòng)決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實(shí)踐到業(yè)務(wù)價(jià)值挖掘 在數(shù)據(jù)分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計(jì)模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價(jià)值導(dǎo)向 統(tǒng)計(jì)模型作為數(shù)據(jù)分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10