赞
踩
高德开放平台:https://lbs.amap.com/
下载POI分类编码和城市编码表
搜索POI相关文档:https://lbs.amap.com/api/webservice/guide/api/search
1.首先在高德开放平台上注册账号,然后进行开发者认证,认证成为个人开发者(当然如果商用也可以认证为企业开发者)
2.其次进入控制台,创建应用并申请key,然后就可以调用key啦。
3.利用python调用key结合多边形搜索法获取POI
完整的代码有三个文件:
1. Coordin_transformlat.py -- 坐标转换文件,用于对poi进行坐标系纠偏
2. GetPoi_keywords.py -- 对高德地图发起数据请求并写入csv文件
3. RectanSearch.py -- 四叉树划分法
三个文件缺一不可!!!
代码分别如下:
①Coordin_transformlat.py
文件:
# * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换 # * 即 百度 转 谷歌、高德 # * @param bd_lon # * @param bd_lat # * @returns {*[]} # */ import math def bd09togcj02(bd_lon, bd_lat): x_pi = 3.14159265358979324 * 3000.0 / 180.0 x = bd_lon - 0.0065 y = bd_lat - 0.006 z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi) theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi) gg_lng = z * math.cos(theta) gg_lat = z * math.sin(theta) return [gg_lng, gg_lat] # * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换 # * 即谷歌、高德 转 百度 # */ def gcj02tobd09(lng, lat): x_PI = 3.14159265358979324 * 3000.0 / 180.0 z = math.sqrt(lng * lng + lat * lat) + 0.00002 * math.sin(lat * x_PI) theta = math.atan2(lat, lng) + 0.000003 * math.cos(lng * x_PI) bd_lng = z * math.cos(theta) + 0.0065 bd_lat = z * math.sin(theta) + 0.006 return [bd_lng, bd_lat] # wgs84转高德 def wgs84togcj02(lng, lat): PI = 3.1415926535897932384626 ee = 0.00669342162296594323 a = 6378245.0 dlat = transformlat(lng - 105.0, lat - 35.0) dlng = transformlng(lng - 105.0, lat - 35.0) radlat = lat / 180.0 * PI magic = math.sin(radlat) magic = 1 - ee * magic * magic sqrtmagic = math.sqrt(magic) dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI) dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * PI) mglat = lat + dlat mglng = lng + dlng return [mglng, mglat] # GCJ02/谷歌、高德 转换为 WGS84 gcj02towgs84 def gcj02towgs84(localStr): lng = float(localStr.split(',')[0]) lat = float(localStr.split(',')[1]) PI = 3.1415926535897932384626 ee = 0.00669342162296594323 a = 6378245.0 dlat = transformlat(lng - 105.0, lat - 35.0) dlng = transformlng(lng - 105.0, lat - 35.0) radlat = lat / 180.0 * PI magic = math.sin(radlat) magic = 1 - ee * magic * magic sqrtmagic = math.sqrt(magic) dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI) dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * PI) mglat = lat + dlat mglng = lng + dlng return [lng * 2 - mglng,lat * 2 - mglat] def transformlat(lng, lat): PI = 3.1415926535897932384626 ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * \ lat + 0.1 * lng * lat + 0.2 * math.sqrt(abs(lng)) ret += (20.0 * math.sin(6.0 * lng * PI) + 20.0 * math.sin(2.0 * lng * PI)) * 2.0 / 3.0 ret += (20.0 * math.sin(lat * PI) + 40.0 * math.sin(lat / 3.0 * PI)) * 2.0 / 3.0 ret += (160.0 * math.sin(lat / 12.0 * PI) + 320 * math.sin(lat * PI / 30.0)) * 2.0 / 3.0 return ret def transformlng(lng, lat): PI = 3.1415926535897932384626 ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \ 0.1 * lng * lat + 0.1 * math.sqrt(abs(lng)) ret += (20.0 * math.sin(6.0 * lng * PI) + 20.0 * math.sin(2.0 * lng * PI)) * 2.0 / 3.0 ret += (20.0 * math.sin(lng * PI) + 40.0 * math.sin(lng / 3.0 * PI)) * 2.0 / 3.0 ret += (150.0 * math.sin(lng / 12.0 * PI) + 300.0 * math.sin(lng / 30.0 * PI)) * 2.0 / 3.0 return ret
②GetPoi_keywords.py
文件:
import requests import json import csv import re from Coordin_transformlat import gcj02towgs84 def Get_poi_polygon(key,polygon,keywords,page): ''' 这是一个能够从高德地图获取poi数据的函数 key:为用户申请的高德密钥 polygon:目标城市四个点的坐标 keywords:POI数据的类型 page:当前页数 ''' #设置header header = {'User-Agent': "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"} #将输进来的矩形进行格式化 Polygonstr = str(polygon[0]) + ',' + str(polygon[1]) + '|' + str(polygon[2]) + ',' + str(polygon[3]) #构建url url = 'https://restapi.amap.com/v3/place/polygon?polygon={}&key={}&keywords={}&page={}'.format(Polygonstr, key, keywords, page) print(url) #用get函数请求数据 r = requests.get(url, headers=header) #设置数据的编码为'utf-8' r.encoding = 'utf-8' # 将请求得到的数据按照'utf-8'编码成字符串 data = r.text return data def Get_times_polygon(key,polygon,keywords): ''' 这是一个控制Get_poi_polygon申请次数的函数 ''' page = 1 # 执行以下代码,直到count为0的时候跳出循环 while True: # 调用第一个函数来获取数据 result = Get_poi_polygon(key,polygon, keywords, page) # json.loads可以对获取回来JSON格式的数据进行解码 content = json.loads(result) pois = content['pois'] count = content['count'] print(count) #如果区域内poi的数量大于800,则认为超过上限,返回False请求对区域进行切割 if int(count) > 800: return False else: for i in range(len(pois)): name = pois[i]['name'] location = pois[i]['location'] if 'address' not in pois[i].keys(): address = str(-1) else: address = pois[i]['address'] adname = pois[i]['adname'] result = gcj02towgs84(location) lng = result[0] lat = result[1] row = [name, address, adname, lng, lat] #调用写入函数来保存数据 writecsv(row, keywords) if count == '0': break # 递增page page = page + 1 def writecsv(poilist,keywords): """ 这是写入成csv文件的函数 :param poilist: :param keywords: :return: 输出的结果存放在代码文件夹下 """ with open('{}.csv'.format(keywords),'a',newline='',encoding='utf-8') as csvfile: writer = csv.writer(csvfile) writer.writerow(poilist) def get_city_scope(key, cityname): parameters = 'key={}&keywords={}&subdistrict={}&output=JSON&extensions=all'.format(key, cityname, 0) url = 'https://restapi.amap.com/v3/config/district?' # 设置header header = {'User-Agent': "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"} res = requests.get(url,params=parameters) jsonData = res.json() if jsonData['status'] == '1': district = jsonData['districts'][0]['polyline'] district_list = re.split(';|\|',district) xlist, ylist = [], [] for d in district_list: xlist.append(float(d.split(',')[0])) ylist.append(float(d.split(',')[1])) xmax = max(xlist) xmin = min(xlist) ymax = max(ylist) ymin = min(ylist) return [xmin, ymax, xmax, ymin] else: print ('fail to acquire: {}'.format(jsonData['info']))
③RectanSearch.py
文件:
import GetPoi_keywords as gp def Quadrangle(key,polygon,keywords): """ :param key:高德地图密钥 :param polygon: 矩形左上跟右下坐标的列表 :param keywords: poi关键词 :return: """ #准备一个空列表,存放切割后的子区域 PolygonList = [] for i in range(len(polygon)): currentMinlat = round(polygon[i][0],6)#当前区域的最小经度 currentMaxlat = round(polygon[i][2],6)#当前区域的最大经度 currentMaxlon = round(polygon[i][1],6)#当前区域的最大纬度 currentMinlon = round(polygon[i][3],6)#当前区域的最小纬度 cerrnt_list = [currentMinlat, currentMaxlon, currentMaxlat, currentMinlon] #将多边形输入获取函数中,判断区域内poi的数量 status = gp.Get_times_polygon(key,cerrnt_list,keywords) #如果数量大于800,那么返回False,对区域进行切分,否则返回区域的坐标对 if status != False: print('该区域poi数量小于800,正在写入数据') else: #左上矩形 PolygonList.append([ currentMinlat, #左经 currentMaxlon, #上纬 (currentMaxlat+currentMinlat)/2, #右经 (currentMaxlon+currentMinlon)/2]) #下纬 #右上矩形 PolygonList.append([ (currentMaxlat+currentMinlat)/2,#左经 currentMaxlon, #上纬 currentMaxlat, #右经 (currentMaxlon+currentMinlon)/2#下纬 ]) #左下矩形 PolygonList.append([ currentMinlat,#左经 (currentMaxlon+currentMinlon)/2,#上纬 (currentMaxlat+currentMinlat)/2,#右经 currentMinlon#下纬 ]) #右下矩形 PolygonList.append([ (currentMaxlat+currentMinlat)/2,#左经 (currentMaxlon+currentMinlon)/2,#上纬 currentMaxlat,#右经 currentMinlon#下纬 ]) print(len(PolygonList)) if len(PolygonList) == 0: break else: Quadrangle(key,PolygonList,keywords) #这里修改为自己的高德密钥 key ='************************' #这里修改自己的poi类型 keywords = '公园' #这里输入想要查询的城市(如城市中文、citycode、adcode) city = '北京市' #调用高德查询行政区的API接口来返回矩形坐标对 Retance = gp.get_city_scope(key,city) #存储区域矩形的列表 input_polygon = [] input_polygon.append(Retance) Quadrangle(key,input_polygon,keywords)
如果想要用poi的类型(types)来检索,可以将url里的
keywords={}
替换成types={}
,其他地方均不用再做修改!!!
文章参考:https://blog.csdn.net/abcbbbd/article/details/124162308
3.11更新:
有时候使用一个密钥爬取POI时,依然会出现达到数据限制但没爬取完整数据的情况,因此将多个密钥改为列表形式依次使用,直到所有密钥都被尝试完毕或者查询到结果为止。
代码如下:
只需要修改RectanSearch.py
文件:
import GetPoi_keywords as gp import time def Quadrangle(key, polygon, keywords): """ :param key: 高德地图密钥 :param polygon: 矩形左上跟右下坐标的列表 :param keywords: poi关键词 :return: """ # 准备一个空列表,存放切割后的子区域 PolygonList = [] for i in range(len(polygon)): currentMinlat = round(polygon[i][0], 6) # 当前区域的最小经度 currentMaxlat = round(polygon[i][2], 6) # 当前区域的最大经度 currentMaxlon = round(polygon[i][1], 6) # 当前区域的最大纬度 currentMinlon = round(polygon[i][3], 6) # 当前区域的最小纬度 cerrnt_list = [currentMinlat, currentMaxlon, currentMaxlat, currentMinlon] # 将多边形输入获取函数中,判断区域内poi的数量 status = gp.Get_times_polygon(key, cerrnt_list, keywords) # 如果数量大于800,那么返回False,对区域进行切分,否则返回区域的坐标对 if status != False: print("该区域内POI数量小于800,正在写入数据") else: # 左上矩形 PolygonList.append([ currentMinlat, # 左经 currentMaxlon, # 上纬 (currentMaxlat + currentMinlat) / 2, # 右经 (currentMaxlon + currentMinlon) / 2]) # 下纬 # 右上矩形 PolygonList.append([ (currentMaxlat + currentMinlat) / 2, # 左经 currentMaxlon, # 上纬 currentMaxlat, # 右经 (currentMaxlon + currentMinlon) / 2 # 下纬 ]) # 左下矩形 PolygonList.append([ currentMinlat, # 左经 (currentMaxlon + currentMinlon) / 2, # 上纬 (currentMaxlat + currentMinlat) / 2, # 右经 currentMinlon # 下纬 ]) # 右下矩形 PolygonList.append([ (currentMaxlat + currentMinlat) / 2, # 左经 (currentMaxlon + currentMinlon) / 2, # 上纬 currentMaxlat, # 右经 currentMinlon # 下纬 ]) print(len(PolygonList)) if len(PolygonList) == 0: break else: Quadrangle(key, PolygonList, keywords) time.sleep(1) if __name__ == '__main__': # 定义多个高德地图密钥,存储在列表中 key_list = ['key1', 'key2', 'key3'] # 定义需要查询的poi类型 keywords = '120000' # 定义需要查询的城市 city = '北京市' # 调用高德查询行政区的API接口来返回矩形坐标对 Retance = gp.get_city_scope(key_list[0], city) # 存储区域矩形的列表 input_polygon = [Retance] # 利用多个密钥连续爬取POI for i in range(len(key_list)): print('使用第 %d 个密钥进行爬取' % (i + 1)) try: Quadrangle(key_list[i], input_polygon, keywords) except KeyError: print('密钥 %d 查询失败,尝试使用下一个密钥' % (i + 1)) continue else: break else: print('所有密钥查询失败,结束程序')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。