如何爬取摩拜單車位置信息?

如圖所示,如何自己定義一個位置然後爬取返回的單車位置信息?


當然是抓摩拜的微信小程序最方便了,手機掛上代理,打開摩拜微信小程序,過濾條件設置為 http://mobike.com,抓到下圖的包:

通過 AnyProxy 抓包

觀察請求,猜測 /mobaike-api/rent/nearByBikesInfo 是獲取附近單車的包,點開一個詳情:

複製 「response body」中的內容,隨便放到一個可以格式化 json 數據的編輯器,發現如下格式的數據:

{
"code":0,
"message":"",
"biketype":0,
"object":[
{
"distId":"8630405575",
"distX":116.3503811486195,
"distY":40.00803095782774,
"distNum":1,
"distance":"35",
"bikeIds":"8630405575#",
"biketype":1,
"type":0,
"boundary":null
},
Object{...},
Object{...},
Object{...},
Object{...},
Object{...}
]
}

猜測得到驗證,這就是查詢附近單車的介面。這裡可以吐槽一下,摩拜居然用 POST 獲取數據。

然後分析 request headers 和 body 中的數據,比較容易根據命名猜測含義:

  • header:wxcode:微信 OpenID ?(後面發現寫一個假的也可以
  • header:time:請求的時間戳(精確到毫秒
  • header:cityCode:城市編碼(等同於座機區號?
  • body:longitude:經度
  • body:latitude:維度
  • body:altitude:海拔
  • body:citycode:城市編碼(同 header:cityCode

通過程序模擬:

#!/usr/bin/env python
# coding: utf8

import time

import requests

session = requests.Session()
session.headers["host"] = "mwx.mobike.com"
session.headers["content-type"] = "application/x-www-form-urlencoded"
session.headers["opensrc"] = "list"
session.headers["mobileno"] = ""
session.headers["wxcode"] = "fake wxcode"
session.headers["platform"] = "3"
session.headers["accept-language"] = "zh-cn"
session.headers["subsource"] = ""
session.headers["lang"] = "zh"
session.headers["user-agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0_3 like Mac OS X) AppleWebKit/604.1.38 ("
"KHTML, like Gecko) Mobile/15A432 MicroMessenger/6.5.19 NetType/WIFI Language/zh_CN"
session.headers["referer"] = "https://servicewechat.com/fake/137/page-frame.html"

def main():
session.headers["time"] = str(long(time.time() * 1000))
session.headers["citycode"] = "010"

body = {
"verticalAccuracy": 10,
"speed": -1,
"horizontalAccuracy": 65,
"accuracy": 65,
"errMsg": "getLocation:ok",
"citycode": "010",
"wxcode": "fake wxcode",
"longitude": "116.3507080078125",
"latitude": "40.00823211669922",
"altitude": "46.802894592285156",
}

data = session.post(url="https://mwx.mobike.com/mobike-api/rent/nearbyBikesInfo.do", data=body).json()

for bike in data["object"]:
print "{distId} {distX} {distY} {distance} {biketype}".format(**bike)

if __name__ == "__main__":
main()

運行程序,得到結果:

證明抓取微信小程序的包沒有問題。response body 中的 object 中的每個欄位:

{
"distId":"8630405575",
"distX":116.3503811486195,
"distY":40.00803095782774,
"distNum":1,
"distance":"35",
"bikeIds":"8630405575#",
"biketype":1,
"type":0,
"boundary":null
}

根據命名猜測,distId 是車的編號,distX、distY 是車所在坐標,distance 為距離查詢所設置經緯度坐標的距離(單位:米),biketype 是車的類型(比如摩拜、摩拜 Lite 等)。


關於什麼是代理:


接下來可以修改程序,將海拔、坐標、城市區號等數據通過參數設置,就可以得到不同地方的摩拜單車數據了。理想情況下,遍歷一個城市所有坐標(每次在上次基礎上位移一定距離),再根據 distId 去重過濾,就可以得到這個城市的所有摩拜單車數據了。

後面的事情,不折騰了。


抓包後模擬摩拜單車客戶端發請求,爬取北京市內摩拜單車的地理位置信息,製作熱力圖。
可以看我寫的這篇文章,介紹非常詳細
https://zhuanlan.zhihu.com/p/31171275


1.名字打錯了
2.抓取手機上的數據採用fiddler抓取,相關教程可以百度「fiddler 手機抓包」


周圍那一堆都是有人在用的車子嗎?那一直刷app豈不是就能跟蹤某一輛車了。


同學,擺正態度,作業自己寫。


可以用摩拜的微信小程序獲取 api, 我記得之前有人寫過類似的文章,可參考: 抓取手機app的數據(摩拜單車)


找到相應的API,發送位置GPS給摩拜server,然後接收返回的周圍車輛GPS,把全國遍歷一次,競爭對手就能知道有多少摩拜單車了?


又多了一種點開摩拜地圖的表白方法,儘管比較費力,


推薦閱讀:

爬蟲怎麼解決封IP的問題?
爬蟲用哪個好?
python 中文url 編碼如何轉換回中文?
爬蟲工程師的未來方向在哪?
如何抓取etymonline的詞根與解釋?

TAG:Python | 編程 | 爬蟲計算機網路 |