ArcGisPro脚本工具【3】——高德POI爬取

欢迎关注同名微信公众号,更多文章推送:

本次Arcpy脚本工具用的是ArcGisPro2.8版本,尽量使用同一版本,其它版本可以参照。

混进有

工具介绍

本工具通过高德开放的【搜索POI】的API进行爬取。在此之前,需要先进入官网申请一个key。网址如下:

获取高德地图Keyicon-default.png?t=N7T8https://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-爬取POIicon-default.png?t=N7T8https://pan.baidu.com/s/1am5b8ew4nNIOGhNobRxIkw?pwd=uuu3