高德地图获取城市所有小区的POI
我們使用高德開放平臺https://lbs.amap.com上的webapi服務(wù),獲取POI數(shù)據(jù),嚴格說來不算爬蟲,就是調(diào)數(shù)據(jù)接口獲取數(shù)據(jù)而已。
步驟也很簡單。
1.獲取北京的范圍。
2.將北京范圍拆分成設(shè)定步長的網(wǎng)格,用每個網(wǎng)格矩形搜索小區(qū)數(shù)據(jù),如果搜索到的數(shù)據(jù)量大于閾值,則將網(wǎng)格拆分成四個,如此遞歸,直到矩形搜索到的數(shù)據(jù)量小于閾值。
3.用2中獲取的網(wǎng)格調(diào)用接口,獲取小區(qū)數(shù)據(jù),把所有網(wǎng)格的數(shù)據(jù)匯總到一起就可以了。
稍稍有點難度的,可能就是網(wǎng)格拆分的遞歸,但只要想明白了,就也很簡單。
接下來,看實踐。
一.獲取北京范圍
看說明:高德地圖開放平臺——開發(fā)指南——行政區(qū)劃查詢。
https://lbs.amap.com/api/webservice/guide/api/district
根據(jù)請求參數(shù)說明,拼接出如下一個url,就可以獲取北京范圍的數(shù)據(jù)了,當(dāng)然,用戶key自己申請一個。
https://restapi.amap.com/v3/config/district?keywords=北京&subdistrict=0&extensions=all&key=<用戶的key>
polyline就是北京邊界坐標(biāo)點串,拷貝下來,留著備用。
把polyline:后面跟著那一串,復(fù)制保存在polyline.txt文件中,雙引號不用留。
二.遞歸拆分網(wǎng)格
為了便于理解,我們把拆分網(wǎng)格和獲取數(shù)據(jù)分開寫。
先看說明:
高德地圖開放平臺——開發(fā)指南——搜索POI——多邊形搜索:
https://lbs.amap.com/api/webservice/guide/api/search
多邊形搜索的示例:
https://restapi.amap.com/v3/place/polygon?polygon=116.460988,40.006919|116.48231,40.007381|116.47516,39.99713|116.472596,39.985227|116.45669,39.984989|116.460988,40.006919&keywords=kfc&output=xml&key=<用戶的key>
根據(jù)多邊形搜索條目下的請求參數(shù)說明,可以知道,在url中,我們需要拼接幾個參數(shù),才能獲取數(shù)據(jù)。
1.key,需要在高德地圖開放平臺上申請,既key=用戶的key
2.polygon,圖簡單,我們使用矩形,傳左下右上兩個頂點坐標(biāo)對,既polygon=minlng,minlat|maxlng,maxlat
3.types,查詢的POI類型,這個查《POI分類編碼》,能看到(大類)商務(wù)住宅——(中類)住宅區(qū)——(小類)住宅小區(qū)的NEW-TYPE是120302,中類住宅區(qū)的NEW-TYPE是120300,既types=12302。
(其實也可以用120300這個中類的碼入?yún)?#xff0c;但反正也不考慮別墅,就算了吧。)
4.offset,每頁記錄數(shù)據(jù),offset=20。
5.page,當(dāng)前頁數(shù),這個需要根據(jù)返回的POI總量算,從1開始。
6.extensions,返回結(jié)果控制,多多益善,extensions=all。
7.output,返回數(shù)據(jù)格式類型,output=json。
根據(jù)offset和page的說明,offset是強烈建議不超過25,若超過25可能造成訪問報錯,page是最大翻頁數(shù)100,這表明,每次矩形搜索最多返回2500條記錄。
**
**
我們繼續(xù)看返回參數(shù)說明,count,搜索方案數(shù)目(最大值為1000)。
這說明啥?
按照官方文檔,矩形搜索,最多返回1000條數(shù)據(jù),為了獲取足夠的數(shù)據(jù),我們只能把搜索的矩形不斷細分變小。理論上,在同一個地方,范圍越小,內(nèi)含的數(shù)據(jù)就越少。
假設(shè)說,一個矩形覆蓋整個北京,通過這個矩形調(diào)接口,返回count=1000,那我們就要把這個矩形拆分一下,橫一刀,豎一刀,變成0、1、2、3四個小矩形,再通過這四個小矩形調(diào)接口,如果0返回的count小于1000,那它不用再拆分了,如果1返回的count=1000,那它需要繼續(xù)拆分,如此遞歸下去,直到所有的矩形調(diào)接口,返回的count都小于1000。
雖然按官方說明,閾值選1000是正確的,但按照實踐來看,這個閾值選800正好,因為我發(fā)現(xiàn),挺大個矩形,返回的count是800多,拆成4個,每個小矩形也返回count是800多,這就有點不太合理了,實踐出真知,那就用800做閾值吧。
總結(jié)一下:
1.先根據(jù)北京范圍拆分基礎(chǔ)的矩形網(wǎng)格。
2.根據(jù)這個基礎(chǔ)的矩形網(wǎng)格,去調(diào)用高德多邊形搜索服務(wù),如果搜索出的小區(qū)小于800個,則保留矩形,否則拆分矩形,直到矩形搜索出的小區(qū)小于800個。
3.將處理好的矩形寫入文件備用。
結(jié)果如下圖:
代碼如下,Python3代碼,需要的包是requests和shapely,其實基礎(chǔ)的矩形網(wǎng)格拆分得足夠小,就都不用遞歸了,如果想看看遞歸效果,可以把步長d設(shè)置得大一些。也可以把代碼改一改,獲取其他類型的POI等。
import requests from shapely.geometry import Polygon from shapely import wkt from requests.adapters import HTTPAdapter s = requests.Session() s.mount('http://', HTTPAdapter(max_retries=3))#設(shè)置重試次數(shù)為3次 s.mount('https://', HTTPAdapter(max_retries=3)) # 獲取矩形搜索到poi的count數(shù)量 # key,是高德地圖的key # r是矩形,[minlng,minlat,maxlng,maxlat] def countSearchPoi(key,r):minlng = r[0]minlat = r[1]maxlng = r[2]maxlat = r[3]url = 'https://restapi.amap.com/v3/place/polygon?types=120302&offset=20&page=1&extensions=all&output=json&polygon='\+ str(minlng) +',' + str(minlat) + '|' + str(maxlng) + ',' + str(maxlat) + '&key=' + keycount = -1print(url)try:r = s.get(url, timeout=5)data = r.json()if 'status' in data:if data['status'] == '1':count = int(data['count'])except BaseException as e:print(e)return count # 切分矩形,把大矩形分成四個小矩形 def clipRectangle(r):minlng = r[0]minlat = r[1]maxlng = r[2]maxlat = r[3]dx = 0.5*(maxlng-minlng)dy = 0.5*(maxlat-minlat)return [[minlng,minlat,minlng+dx,minlat+dy],[minlng+dx,minlat,maxlng,minlat+dy],[minlng+dx,minlat+dy,maxlng,maxlat],[minlng,minlat+dy,minlng+dx,maxlat]]# 按照步長,將面切分成矩形網(wǎng)格,把所有跟入?yún)⒌拿嫦嘟坏木匦味挤祷?/span> # polygon是多邊形geometry,d是步長 def clipPolygon(polygon,d):bbox = polygon.boundsrectangles = []lngnum = int((bbox[2]-bbox[0])/d)+1latnum = int((bbox[3]-bbox[1])/d)+1minlng = int(bbox[0]/d)*dminlat = int(bbox[1]/d)*dfor i in range(0,lngnum+1):for j in range(0,latnum+1):rectangle = Polygon([(minlng+d*i,minlat+d*j),(minlng+d*i+d,minlat+d*j),(minlng+d*i+d,minlat+d*j+d),(minlng+d*i,minlat+d*j+d),(minlng+d*i,minlat+d*j)])if polygon.intersects(rectangle):rectangles.append([minlng+d*i,minlat+d*j,minlng+d*i+d,minlat+d*j+d])return rectanglesif __name__ =='__main__':d = 0.05maxcount = 800key = ''# 將北京的范圍坐標(biāo)點串從txt文件中讀出,構(gòu)建成polygonfpolyline = open(r'polyline.txt','r',encoding='utf-8')polyline = fpolyline.readlines()[0].strip('\n')fpolyline.close()polygonstr = 'POLYGON(('+polyline.replace(',',' ').replace(';',',')+'))'polygon = wkt.loads(polygonstr)# 根據(jù)polygon和步長,構(gòu)建矩形網(wǎng)格rectangles = clipPolygon(polygon,d)fnew = open(r'rectangles.txt','a',encoding='utf-8')# 嵌入遞歸for r in rectangles:# 如果矩形構(gòu)建的polygon與北京范圍polygon不相交,進入下一個rp = Polygon([(r[0],r[1]),(r[2],r[1]),(r[2],r[3]),(r[0],r[3]),(r[0],r[1])])if not polygon.intersects(rp):continuecount = countSearchPoi(key,r)print(count)# 如果count小于閾值,將矩形和count寫入文件,否則將矩形拆分,進行遞歸if count < maxcount:fnew.write(str(r[0])+','+str(r[1])+'|'+str(r[2])+','+str(r[3])+'\t'+str(count)+'\n')else:rectangles.extend(clipRectangle(r))fnew.close()三.獲取小區(qū)數(shù)據(jù)
一個很簡單的腳本,獲取所有小區(qū)的name、id、address、location,保存在xiaoqu.txt中。
import requests from requests.adapters import HTTPAdapter import math s = requests.Session() s.mount('http://', HTTPAdapter(max_retries=3))#設(shè)置重試次數(shù)為3次 s.mount('https://', HTTPAdapter(max_retries=3)) # 獲取小區(qū)POI # key,是高德地圖的key # r是矩形,minlng,minlat|maxlng,maxlat # page是頁碼 def getPoi(key,r,page):url = 'https://restapi.amap.com/v3/place/polygon?types=120302&offset=20&page='+str(page)+'&extensions=all&output=json&polygon='\+ r + '&key=' + keyprint(url)result = []try:r = s.get(url, timeout=5)data = r.json()if 'status' in data:if data['status'] == '1':pois = data['pois']for p in pois:result.append([str(p['id']),str(p['name']),str(p['location']),str(p['address'])])except BaseException as e:print(e)return result if __name__ =='__main__':key = ''f = open(r'rectangles.txt','r',encoding='utf-8')fnew = open(r'xiaoqu.txt','a',encoding='utf-8')flines = f.readlines()f.close()for l in flines:llist = l.strip('\n').split('\t')r = llist[0]count = int(llist[1])if count < 1:continue# 整除,向上取整pagenum = math.ceil(count/20)for i in range(1,pagenum+1):result = getPoi(key,r,i)if len(result) > 0:for re in result:print(re)fnew.write('\t'.join(re)+'\n')fnew.close()總結(jié)
以上是生活随笔為你收集整理的高德地图获取城市所有小区的POI的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 经典的面板数据集(R语言包plm)
- 下一篇: 8款实用的Jquery瀑布流插件