天天看點

摩拜單車爬蟲源碼及解析

為什麼爬摩拜的資料

摩拜是最早進入成都的共享單車,每天我從地鐵站下來的時候,在APP中能看到很多單車,但走到那裡的時候,才發現車并不在那裡。有些車不知道藏到了哪裡;有些車或許是在高樓的後面,由于有GPS的誤差而找不到了;有些車被放到了小區裡面,一牆之隔讓騎車人無法獲得到車。

那麼有沒有一個辦法通過獲得這些單車的資料,來分析這些車是否變成了僵屍車?是否有人故意放到小區裡面讓人無法擷取呢?

帶着這些問題,我開始了研究如何擷取這些資料。

從哪裡獲得資料

如果你能夠看到資料,那麼我們總有辦法自動化的擷取到這些資料。隻不過擷取資料的方式方法決定了擷取資料的效率,對于摩拜單車的資料分析這個任務而言,這個爬蟲要能夠在短時間内(通常是10分鐘左右)擷取到更多的資料,對于資料分析才有用處。那麼資料來源于哪裡?

最直接的來源是摩拜單車的APP。現代的軟體設計都講究前後端分離,而且服務端會同時服務于APP、網頁等。在這種趨勢下我們隻需要搞清楚軟體的HTTP請求就好了。一般而言有以下一些工具可以幫忙:

直接抓包:

用代理進行HTTP請求抓包及調試:

由于我的手機沒有root,在路由器上抓包又太多的幹擾,對于https也不好弄。是以隻能首先采用Fiddler或者Charles的方式試試。挂上Fiddler的代理,然後在手機端不停的移動位置,看有沒有新的請求。但遺憾的是似乎請求都是去拿高德地圖的,并沒有和摩拜車相關的資料。

那怎麼一回事?試試手機端的。換成Packet Capture後果然就有流量了,在請求中找到了我最關心的那個:

這個API請求一看就很顯然了,在postman中試了一下能夠正确的傳回資訊,看來就是你了!

高興得太早

連續爬了幾天的資料,将資料進行一分析,發現摩拜單車的GPS似乎一直在跳動,有時候跳動會超過幾公裡的距離,顯然不是一個正常的值。

難道是他們的接口做了手腳傳回的是假資料?我觀察到即便在APP中,單車傳回的資料也有跳動。有某一天淩晨到第二天早上,我隔段時間重新整理一下我家附近的車,看看是否真的如此。

圖檔我找不到了,但是觀察後得出的結論是,APP中傳回的位置确實有問題。有一台車放在一個很偏僻的位置,一會兒就不見了,待會兒又回來了,和我抓下來的資料吻合。而且這個跳動和手機、手機号、甚至移動營運商沒有關系,說明這個跳動是摩拜接口的問題,也可以從另一方面解釋為什麼有時候看到車但其實那裡沒有車。

這是之前發的一個朋友圈的視訊截圖,可以看到在營門口附近有一個尖,在那裡其實車是停住的,但是GPS軌迹顯示短時間内在附近攢動,甚至攢動到很遠,又回到那個位置。

這樣的資料對于資料分析來講根本沒法用,我差點就放棄了。

轉機

随着微信小程式的火爆,摩拜單車也在第一時間出了小程式。我一看就笑了,不錯,又給我來了一個資料源,試試。用Packet Capture抓了一次資料後很容易确定API,具體過程就不在闡述。抓取後爬取了兩三天的資料,發現出現了轉機,資料符合正常的單車的軌迹。

剩下事情,就是提高爬蟲的效率了。

其他嘗試

有時候直接分析APP的源代碼會很友善的找到API入口,将摩拜的Android端的APP進行反編譯,但發現裡面除了一些資源檔案有用外,其他的檔案都是用奇虎360的混淆器加殼的。網上有文章分析如何進行脫殼,但我沒有太多時間去鑽研,也就算了。

也談API的設計

摩拜單車的API之是以很容易抓取和分析,很大程度上來講是由于API設計的太簡陋:

如果大家有興趣,可以試着看一下小藍單車APP的request,他們使用https請求,對資料的request進行了加密,要抓取到他們的資料難度會增加非常多。

當然了,如果摩拜單車官方并不care資料的事情的話,這樣的API設計也是ok的。

摩拜單車爬蟲開源項目

目錄結構

摩拜單車爬蟲源碼及解析

思路

核心代碼放在crawler.py中,資料首先存儲在sqlite3資料庫中,然後去重複後導出到csv檔案中以節約空間。

摩拜單車的API傳回的是一個正方形區域中的單車,我隻要按照一塊一塊的區域移動就能抓取到整個大區域的資料。

left,top,right,bottom定義了抓取的範圍,目前是成都市繞城高速之内以及南至南湖的正方形區域。offset定義了抓取的間隔,現在以0.002為基準,在DigitalOcean 5$的伺服器上能夠15分鐘内抓取一次。

摩拜單車爬蟲源碼及解析

然後就啟動了250個線程,至于你要問我為什麼沒有用協程,哼哼~~我當時沒學~~~其實是可以的,說不定效率更高。

由于抓取後需要對資料進行去重,以便消除小正方形區域之間重複的部分,最後的group_data正是做這個事情。

摩拜單車爬蟲源碼及解析

最核心的API代碼在這裡。小程式的API接口,搞幾個變量就可以了,十分簡單。

摩拜單車爬蟲源碼及解析

最後你可能要問頻繁的抓取IP沒有被封麼?其實摩拜單車是有IP的通路速度限制的,隻不過破解之道非常簡單,就是用大量的代理。

我是有一個代理池,每天基本上有8000以上的代理。在ProxyProvider中直接擷取到這個代理池然後提供一個pick函數用于随機選取得分前50的代理。請注意,我的代理池是每小時更新的,但是代碼中提供的jsonblob的代理清單僅僅是一個樣例,過段時間後應該大部分都廢棄了。

在這裡用到一個代理得分的機制。我并不是直接随機選擇代理,而是将代理按照得分高低進行排序。每一次成功的請求将加分,而出錯的請求将減分。這樣一會兒就能選出速度、品質最佳的代理。如果有需要還可以存下來下次繼續用。

摩拜單車爬蟲源碼及解析

在實際使用中,通過proxyProvider.pick()選擇代理,然後使用。如果代理出現任何問題,則直接用proxy.fatal_error()降低評分,這樣後續就不會選擇到這個代理了。

摩拜單車爬蟲源碼及解析

原文釋出時間為:2017-05-12

本文作者:我是思聰

本文來自雲栖社群合作夥伴“Python中文社群”,了解相關資訊可以關注“x”微信公衆号

繼續閱讀