Python爬蟲(chóng)_城市公交、地鐵站點(diǎn)和線(xiàn)路數(shù)據(jù)采集實(shí)例
城市公交、地鐵數(shù)據(jù)反映了城市的公共交通,研究該數(shù)據(jù)可以挖掘城市的交通結(jié)構(gòu)、路網(wǎng)規(guī)劃、公交選址等。但是,這類(lèi)數(shù)據(jù)往往掌握在特定部門(mén)中,很難獲取?;ヂ?lián)網(wǎng)地圖上有大量的信息,包含公交、地鐵等數(shù)據(jù),解析其數(shù)據(jù)反饋方式,可以通過(guò)Python爬蟲(chóng)采集。閑言少敘,接下來(lái)將詳細(xì)介紹如何使用Python爬蟲(chóng)爬取城市公交、地鐵站點(diǎn)和數(shù)據(jù)。
首先,爬取研究城市的所有公交和地鐵線(xiàn)路名稱(chēng),即XX路,地鐵X號(hào)線(xiàn)??梢酝ㄟ^(guò)圖吧公交、公交網(wǎng)、8684、本地寶等網(wǎng)站獲取,該類(lèi)網(wǎng)站提供了按數(shù)字和字母劃分類(lèi)別的公交線(xiàn)路名稱(chēng)。Python寫(xiě)個(gè)簡(jiǎn)單的爬蟲(chóng)就能采集,可參看WenWu_Both的文章,博主詳細(xì)介紹了如何利用python爬取8684上某城市所有的公交站點(diǎn)數(shù)據(jù)。該博主采集了站點(diǎn)詳細(xì)的信息,包括,但是缺少了公交站點(diǎn)的坐標(biāo)、公交線(xiàn)路坐標(biāo)數(shù)據(jù)。這就讓人抓狂了,沒(méi)有空間坐標(biāo)怎么落圖,怎么分析,所以,本文重點(diǎn)介紹的是站點(diǎn)坐標(biāo)、線(xiàn)路的獲取。

以圖吧公交為例,點(diǎn)擊某一公交后,出現(xiàn)該路公交的詳細(xì)站點(diǎn)信息和地圖信息。博主頓感興奮,覺(jué)得馬上就要成功了,各種抓包,發(fā)現(xiàn)并不能解析??赡懿┲骷夹g(shù)所限,如有大神能從中抓到站點(diǎn)和線(xiàn)路的坐標(biāo)信息,請(qǐng)不寧賜教。這TM就讓人絕望了啊,到嘴的肥肉吃不了。

天無(wú)絕人之路,嘗試找找某地圖的API,發(fā)現(xiàn)可以調(diào)用,通過(guò)解析,能夠找到該數(shù)據(jù)的后臺(tái)地址。熟悉前端的可以試試,博主前端也就只會(huì)個(gè)hello world,不獻(xiàn)丑了。這是一種思路,實(shí)踐證明是可以的。

地圖API可以,那么通過(guò)地圖抓包呢?打開(kāi)某圖主頁(yè),直接輸入某市公交名稱(chēng),通過(guò)抓包,成功找到站點(diǎn)和線(xiàn)路信息。具體抓包信息如下圖所示,busline_list中詳細(xì)列出了站點(diǎn)和線(xiàn)路的信息,其中有兩條,是同一趟公交不同方向的數(shù)據(jù),略有差別,需注意。找到入口過(guò)后,接下來(lái)爬蟲(chóng)就要大顯身手了。

主要爬取代碼如下,其實(shí)也很簡(jiǎn)單,主函數(shù)如下。首先需要構(gòu)建傳入的參數(shù),主要的包括路線(xiàn)名稱(chēng),城市編碼,地理范圍,縮放尺度。地理范圍可以通過(guò)坐標(biāo)拾取器獲取,參數(shù)經(jīng)url編碼后,發(fā)送請(qǐng)求,判斷返回?cái)?shù)據(jù)是否符合要求(注:可能該線(xiàn)路地圖上停運(yùn)或不存在,也可能是訪問(wèn)速度過(guò)快,反爬蟲(chóng)機(jī)制需要人工驗(yàn)證,博主爬取的時(shí)候碰到過(guò),所以后面設(shè)置了隨機(jī)休眠)。接下來(lái),就是解析json數(shù)據(jù)了。代碼中的extratStations和extractLine,就是提取需要的字段,怎么樣,是不是很簡(jiǎn)單。最后,就是保存了,站點(diǎn)和路線(xiàn)分別存儲(chǔ)。
def main():
df = pd.read_excel("線(xiàn)路名稱(chēng).xlsx",)
BaseUrl = "https://ditu.amap.com/service/poiInfo?query_type=TQUERY&pagesize=20&pagenum=1&qii=true&cluster_state=5&need_utd=true&utd_sceneid=1000&div=PC1000&addr_poi_merge=true&is_classify=true&"
for bus in df[u"線(xiàn)路"]:
params = {
'keywords':'11路',
'zoom': '11',
'city':'610100',
'geoobj':'107.623|33.696|109.817|34.745'
}
print(bus)
paramMerge = urllib.parse.urlencode(params)
#print(paramMerge)
targetUrl = BaseUrl + paramMerge
stationFile = "./busStation/" + bus + ".csv"
lineFile = "./busLine/" + bus + ".csv"
req = urllib.request.Request(targetUrl)
res = urllib.request.urlopen(req)
content = res.read()
jsonData = json.loads(content)
if (jsonData["data"]["message"]) and jsonData["data"]["busline_list"]:
busList = jsonData["data"]["busline_list"] ##busline 列表
busListSlt = busList[0] ## busList共包含兩條線(xiàn),方向不同的同一趟公交,任選一趟爬取
busStations = extratStations(busListSlt)
busLine = extractLine(busListSlt)
writeStation(busStations, stationFile)
writeLine(busLine, lineFile)
sleep(random.random() * random.randint(0,7) + random.randint(0,5)) #設(shè)置隨機(jī)休眠
else:
continue
附上博主的解析函數(shù):
def extratStations(busListSlt):
busName = busListSlt["name"]
stationSet = []
stations = busListSlt["stations"]
for bs in stations:
tmp = []
tmp.append(bs["station_id"])
tmp.append(busName)
tmp.append(bs["name"])
cor = bs["xy_coords"].split(";")
tmp.append(cor[0])
tmp.append(cor[1])
wgs84cor1 = gcj02towgs84(float(cor[0]),float(cor[1]))
tmp.append(wgs84cor1[0])
tmp.append(wgs84cor1[1])
stationSet.append(tmp)
return stationSet
def extractLine(busListSlt):
## busList共包含兩條線(xiàn),備注名稱(chēng)
keyName = busListSlt["key_name"]
busName = busListSlt["name"]
fromName = busListSlt["front_name"]
toName = busListSlt["terminal_name"]
lineSet = []
Xstr = busListSlt["xs"]
Ystr = busListSlt["ys"]
Xset = Xstr.split(",")
Yset = Ystr.split(",")
length = len(Xset)
for i in range(length):
tmp = []
tmp.append(keyName)
tmp.append(busName)
tmp.append(fromName)
tmp.append(toName)
tmp.append(Xset[i])
tmp.append(Yset[i])
wgs84cor2 = gcj02towgs84(float(Xset[i]),float(Yset[i]))
tmp.append(wgs84cor2[0])
tmp.append(wgs84cor2[1])
lineSet.append(tmp)
return lineSet
爬蟲(chóng)采集原始數(shù)據(jù)如下:

以下是某一條公交站點(diǎn)和線(xiàn)路的處理后的數(shù)據(jù)展示。由于不同的地圖商采用不同的坐標(biāo)系,會(huì)有不同程度的偏差,需要坐標(biāo)糾偏。下一步,博主將詳細(xì)介紹如何批量將這些站點(diǎn)和坐標(biāo)進(jìn)行坐標(biāo)糾正和矢量化。

相關(guān)文章
Python的Scrapy爬蟲(chóng)框架簡(jiǎn)單學(xué)習(xí)筆記
這篇文章主要介紹了Python的Scrapy爬蟲(chóng)框架簡(jiǎn)單學(xué)習(xí)筆記,從基本的創(chuàng)建項(xiàng)目到CrawlSpider的使用等都有涉及,需要的朋友可以參考下2016-01-01
python 實(shí)現(xiàn)多維數(shù)組(array)排序
今天小編就為大家分享一篇python 實(shí)現(xiàn)多維數(shù)組(array)排序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02
Pandas根據(jù)條件實(shí)現(xiàn)替換列中的值
在使用Pandas的Python中,DataFrame列中的值可以通過(guò)使用各種內(nèi)置函數(shù)根據(jù)條件進(jìn)行替換,本文主要來(lái)和大家討論在Pandas中用條件替換數(shù)據(jù)集列中的值的各種方法,希望對(duì)大家有所幫助2024-01-01
python中Apriori算法實(shí)現(xiàn)講解
給大家詳細(xì)講解一下Apriori 算法在python中的實(shí)現(xiàn)過(guò)程,有需要的朋友收藏一下本片文章吧。2017-12-12
怎么處理Python分割字符串時(shí)有多個(gè)分隔符
在使用Python處理字符串的時(shí)候,有時(shí)候會(huì)需要分割字符。本文就介紹了Python分割字符串時(shí)有多個(gè)分隔符,感興趣的可以了解一下2021-07-07
python中用logging實(shí)現(xiàn)日志滾動(dòng)和過(guò)期日志刪除功能
這篇文章主要介紹了python中用logging實(shí)現(xiàn)日志滾動(dòng)和過(guò)期日志刪除功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08

