欢迎关注同名微信公众号,更多文章推送:
本次Arcpy脚本工具用的是ArcGisPro2.8版本,尽量使用同一版本,其它版本可以参照。
本工具通过高德开放的【搜索POI】的API进行爬取。在此之前,需要先进入官网申请一个key。网址如下:
获取高德地图Keyhttps://lbs.amap.com/api/webservice/guide/create-project/get-key
申请方法可以看下这个指南,或者网上搜一下别的大神的教程。
参数只有2个。
1、【输入城市名或城市代码】——这里随工具附带了一个高德地图的城市代码表,分别是城市名和对应的城市代码,一般情况下填城市名就可以了,不过有的城市特别是区会存在重名的情况,而城市代码都是唯一值,填代码更稳妥一点:
2、【输出POI点】——输出一个点要素。
代码比较长,就不细说了,就是调用官方提供的POI,获取POI信息,转点,再通过坐标转换,把高德用的【gcj02坐标】,也称为火星坐标,转换成【WGS84坐标】,和【CGCS2000国家大地坐标】基本可以认为一致。
其中坐标转换的代码单独写成了一个脚本,不要删掉它!
主代码如下:
# -*- coding:utf-8 -*-
from urllib.parse import quote
from urllib import request
import json
import xlwt
import requests
import arcpy
import os
arcpy.env.overwriteOutput = True
# 工具箱输入参数
cityname = arcpy.GetParameterAsText(0) # 输入城市名称或代码
point = arcpy.GetParameterAsText(1) # 输出结果POI
# 获取文档位置
default_path = os.path.dirname(__file__)
arcpy.ImportToolbox(default_path + r"\cc工具箱.tbx") # 加载cc工具箱
excelPath = default_path + r'\output.xls' # 临时excel文件
tablePath = r'memory\tablePOI' # 临时的坐标点表格
#TODO 替换为申请的密钥
amap_web_key = '6d71f68deb0d1b2087b482242d93f030'
poi_search_url = "http://restapi.amap.com/v3/place/text"
# POI分类
classes = ['餐饮服务', '道路附属设施', '地名地址信息', '风景名胜', '公共设施', '公司企业', '购物服务', '交通设施服务', '金融保险服务'
, '科教文化服务', '摩托车服务', '汽车服务', '汽车维修', '汽车销售', '商务住宅', '生活服务', '事件活动', '室内设施'
, '体育休闲服务', '通行设施', '医疗保健服务', '政府机构及社会团体', '住宿服务']
class Geocoding:
def __init__(self, api_key):
self.api_key = api_key
def geocode(self, address):
"""
利用高德geocoding服务解析地址获取位置坐标
:param address:需要解析的地址
:return:
"""
geocoding = {'s': 'rsv3',
'key': self.api_key,
'city': '全国',
'address': address}
# geocoding = urllib.urlencode(geocoding)
# ret = urllib.urlopen("http://restapi.amap.com/v3/geocode/geo{}".format(geocoding))
url = "http://restapi.amap.com/v3/geocode/geo?"
ret = requests.get(url, params=geocoding)
if ret.status_code == 200:
# res = ret.json()
# json_obj = json.loads(res)
json_obj = ret.json()
if json_obj['status'] == '1' and int(json_obj['count']) >= 1:
geocodes = json_obj['geocodes'][0]
lng = float(geocodes.get('location').split(',')[0])
lat = float(geocodes.get('location').split(',')[1])
return [lng, lat]
else:
return None
else:
return None
# 根据城市名称和分类关键字获取poi数据
def getpois(cityname, keywords):
i = 1
poilist = []
while True: # 使用while循环不断分页获取数据
result = getpoi_page(cityname, keywords, i)
print(result)
result = json.loads(result) # 将字符串转换为json
if result['count'] == '0':
break
hand(poilist, result)
i = i + 1
return poilist
# 数据写入excel
def write_to_excel(poilist, classfield):
# 一个Workbook对象,这就相当于创建了一个Excel文件
book = xlwt.Workbook(encoding='utf-8', style_compression=0)
sheet = book.add_sheet(classfield, cell_overwrite_ok=True)
# 第一行(列标题)
sheet.write(0, 0, 'x')
sheet.write(0, 1, 'y')
sheet.write(0, 2, '省级行政区')
sheet.write(0, 3, '地级市')
sheet.write(0, 4, '区县')
sheet.write(0, 5, '名称')
sheet.write(0, 6, '大类')
sheet.write(0, 7, '中类')
sheet.write(0, 8, '小类')
for i in range(len(poilist)):
location = poilist[i]['location']
name = poilist[i]['name']
c_type = poilist[i]['type']
adname = poilist[i]['adname']
pname = poilist[i]['pname']
cityname = poilist[i]['cityname']
lng = str(location).split(",")[0]
lat = str(location).split(",")[1]
type01 = str(c_type).split(";")[0]
type02 = str(c_type).split(";")[1]
type03 = str(c_type).split(";")[2]
#坐标转换
result = arcpy.cc.TransForm(float(lng), float(lat), 'gcj02_to_wgs84')
lng = float(str(result).split(';')[0])
lat = float(str(result).split(';')[1])
# 每一行写入
sheet.write(i + 1, 0, lng)
sheet.write(i + 1, 1, lat)
sheet.write(i + 1, 2, pname)
sheet.write(i + 1, 3, cityname)
sheet.write(i + 1, 4, adname)
sheet.write(i + 1, 5, name)
sheet.write(i + 1, 6, type01)
sheet.write(i + 1, 7, type02)
sheet.write(i + 1, 8, type03)
# 最后,将以上操作保存到指定的Excel文件中
book.save(excelPath)
# 转点
def XYtoPoint():
arcpy.env.overwriteOutput = True
arcpy.ExcelToTable_conversion(excelPath,tablePath)
os.remove(excelPath)
arcpy.XYTableToPoint_management(tablePath, point, 'x', 'y')
arcpy.DeleteIdentical_management(point, 'shape')
arcpy.DeleteField_management(point, 'x')
arcpy.DeleteField_management(point, 'y')
# 将返回的poi数据装入集合返回
def hand(poilist, result):
# result = json.loads(result) # 将字符串转换为json
pois = result['pois']
for i in range(len(pois)):
poilist.append(pois[i])
# 单页获取pois
def getpoi_page(cityname, keywords, page):
req_url = poi_search_url + "?key=" + amap_web_key + '&extensions=all&keywords=' + quote(
keywords) + '&city=' + quote(cityname) + '&citylimit=true' + '&offset=25' + '&page=' + str(
page) + '&output=json'
data = ''
with request.urlopen(req_url) as f:
data = f.read()
data = data.decode('utf-8')
return data
if __name__ == '__main__':
# 直接获取整个城市的POI数据
classes_all_pois = []
for clas in classes:
pois_area = getpois(cityname, clas)
classes_all_pois.extend(pois_area)
arcpy.AddMessage("数据总数为:" + str(len(classes_all_pois)))
arcpy.AddMessage('================写入Excel================')
write_to_excel(classes_all_pois, clas)
arcpy.AddMessage('================转换成点================')
XYtoPoint()
坐标转换的代码就不贴了,自己直接看python文件。
在主代码中,【key】最好使用自己申请的,一个key每天的使用量是有限制的,多人用的话很容易超出限制。
amap_web_key = '6d71f68deb0d1b2087b482242d93f030'
结果POI如下,每个点都带着【名称、类型】等属性,方便搜索。
最后,贴上工具下载地址:
工具下载:BUG-爬取POIhttps://pan.baidu.com/s/1am5b8ew4nNIOGhNobRxIkw?pwd=uuu3