閑來無事,想對近來學習的爬蟲做個簡單的嘗試,做些有趣的東西;同時也記錄下自己在實際應用過程中遇到的各種坑,故此寫下學習筆記。第一次寫這類筆記,很多不足之處,歡迎指正

該項目想實現的功能是:

1、根據某個關鍵字,通過百度地圖、高德地圖等途徑獲取該關鍵字相關的所有地址;如「超市」,即為獲取所有超市地址,僅限上海市。

2、根據獲取的地址,匹配出相應的地址經緯度,將其標註於地圖上;同時計算出對應某個地址一定距離內的超市個數,最終可視化實現上海市的超市分佈情況及核心經濟區域。

針對上述兩個功能,分兩步走實現最終目標。

一、爬取超市地址

1、高德地圖爬取嘗試

首先第一個想到的是在高德地圖上爬取超市信息,那麼我們先來看下其地圖界面(圖1)。很明顯,輸入關鍵字「超市」後,左側出現的豎框中包含了所有的超市信息,一頁20個,但最多隻能顯示45頁。但上海市肯定不止900家超市,故需要根據上海市各區來進行篩選。

圖1

上海有14個區縣,人工去篩選費時費力。觀察到其URL特別長,包含相當多的信息,故我們嘗試從URL入手分析,看能否從中找到規律。下面是兩個區的URL地址,特別長的一串字元,但還是可以從中找出點規律來的。

「query=%E8%B6%85%E5%B8%82」:這個後面一大堆百分比和字母,其實翻譯過來就是「超市」,只是因為編碼的問題顯示差異。

「city=310000」:這個是上海市的編號吧,有點想不通為啥是這個

「geoobj=121.256723%7C31.165719%7C121.294747%7C31.182353」:這個很明顯應該是經緯度數據,應該是每個區的最高經緯度值和最低經緯度值吧,猜的

「zoom=17」:這個應該是地圖的縮放比例

「classify_data=business_area_flag%3D1%3Badcode%3D310101%2Bfilter_keywords%3D%E8%B6%85%E5%B8%82%2Bsort_rule%3D0%3Breserved_keywords%3Dtrue」:這個最長了,只看懂了一部分,其中「3D310101」正是我們要區分的區縣編號,但是我逐個看了下14個區縣的編號,並不是連續的從01-14的,所以爬取的時候還需要知道這些編號。

「pagenum=1」:這個不用解釋都知道,就是圖1左側框下面的頁碼

黃埔區超市:ditu.amap.com/search?

徐匯區超市:

ditu.amap.com/search?

分析完URL後,那麼就可以通過區縣編碼的調整和頁碼的調整,逐個去爬取所有超市信息了。所以,之後的問題就是頁面編碼解析的問題了。

打開火狐瀏覽器的查看器,可以看到左側框的所有信息都包含在

<div class=」serp-body」>(.*?)</div>裡面,也就是說我只需要將每一頁這部分代碼裏的信息提取出來就行了,勝利就在前方。

但是,我們再來看看這個頁面的源代碼,源代碼下面只有簡單的三行,查看器裏顯示的內容是沒有的(應該是被隱藏了或者是調用其他方式顯示),因此此路不通····。在網上查了半天資料,也未能發現有效的解決辦法(怪自己能力有限),故只能換條路再走。

2、百度地圖爬取

上面的路短時間內沒辦法通了,那麼就只能改走其他路 。最好的辦法就是百度,感謝偉大的度娘,終於找到一篇可以借鑒的文章。

在知乎上,有大神寫了一篇《用Python抓取百度地圖裡的店名,地址和聯繫方式》,地址鏈接為zhuanlan.zhihu.com/p/25。啥都不用說了,代碼寫得相當簡潔明瞭,直接改成我所需要的。

當然,原始代碼爬取的是以城市為單位的,而我這同樣做了簡單的處理,對上海市所有區縣分別進行爬取。最終爬取出來9757家超市,包含超市名稱、超市地址等信息。(感覺還是少了,刪重後才8900多條數據)

二、地址可視化

1、經緯度獲取

要將地址呈現在地圖上,同時計算地址間的距離,很明顯需要地址對應的經緯度。之前用python中的geocoder庫對地址進行經緯度提取,但該方法缺陷在於提取速度受網路穩定性影響較大,同時部分地址難於解析。怎麼辦?繼續度娘

終於找到一個批量解析地址的軟體xGeocoding,該軟體可以快速解析出地址,而且簡單易學。不用說了,就用它了。

2、距離計算

花了近2個小時終於將9700多條數據經緯度解析出來,接下來就是需要計算各個經緯度之間的距離。百度了好久,發現有好多種經緯度距離計算方法,最終也沒研究透到底為啥這麼計算,最後選擇了其中一種計算公式(反正測試了下結果都差不多)

distance=6371004*acos(sin(radians(lng))*sin(radians(lng_other))+cos(radians(lng))*cos(radians(lng_other))*cos(radians(lat_other-lat)))

「radians」:用於計算弧度,其實就是角度,即lng/180*pi;

要做的事很簡單,計算每個地址與其他地址之間的距離,然後統計下距離小於max_distance的個數(我這裡設置為距離1000米以內)。但是,問題是python中math庫下面的sin、acos、radians等函數貌似只能用float,而無法用向量進行直接計算。在這樣的情況下,如果用for循環,那數據量是槓槓的(9700*9700,近1億)。不死心嘗試了下,半個小時只運行了10%都不到,快哭了,果斷放棄。

用for循環肯定不行了,那麼只能用向量進行計算了。突然想起來,python中的numpy庫貌似也有sin函數,該函數可以對向量進行計算;radians這個函數可以直接用公式轉換計算,這樣也可以轉換為向量;唯一不能用向量的是acos這個函數。

最後把程序改了下,重新開始跑數據,結果500s不到就跑完,這提升槓槓的。

3、可視化呈現

萬事具備,只欠可視。現在啥都準備好了,只需要將數據點根據經緯度標註於地圖上,然後根據最近距離超市個數大小畫點。該想法可以用python實現,但我更希望能夠看到熱力地圖,目前受個人能力限制,無法在python上實現熱力地圖,故最終選擇採用其他軟體來呈現可視化效果。

選取的是BDP個人版,操作簡單易學,直接上手,最終效果如下:

值得注意的是,紅框內還可以加入條件欄位,篩選自己想要的數據點進行呈現。如:上海市超市名稱中含華聯的數據

至此,本次學習暫告一段落,最大的感受就是:不動手實踐下,你永遠不知道有多少坑等著你去填


推薦閱讀:
查看原文 >>
相關文章