专栏名称: 城长数据
ArcGIS for Urabn planning.主要面向城市规划专业,通过全方位的ArcGIS技术与方法讲解,达到高效运用ArcGIS ,以辅助城市规划设计及研究的目的。
目录
相关文章推荐
51好读  ›  专栏  ›  城长数据

如何使用百度Geocoding API进行地址解析,并进行坐标转换?

城长数据  · 公众号  ·  · 2017-03-21 07:28

正文

请到「今天看啥」查看全文


前段时间,由于项目需要,希望获得给定地址的经纬度坐标,以便后续进行空间分析。比如图1,希望获得各企业的经纬度坐标,如果是单个企业或者很少的企业,我们可以使用百度的坐标拾取系统人工查询(图2)。但是,如果有成千上万个企业,人工查询的方式显然是无法接受的。这时候,我们就需要借助百度Geocoding API来进行地址解析(图3)。最后,获得的百度经纬度坐标,我们还需要转换为国测局经纬度坐标以及WGS84经纬度坐标。下面,大家就随我一起学习如何使用百度Geocoding API进行地址解析,并进行坐标转换吧!

图1  企业列表

图2  百度坐标拾取系统

图3  百度Geocoding API



一、如何使用百度Geocoding API进行地址解析?


我们仍然采用Python来进行代码编写,先上代码(图4)。

图4  Geocoding API进行地址解析

1、导入需要的几个库,包括pandas、requests、re、time。

2、定义需要读取的Excel文件和需要导出的Excel文件。

3、使用pandas里面的read_excel函数读取文件并将读取的数据命名为data变量,并新建两列,包括经度与纬度。

4、通过for循环去生成请求的url地址,并获取请求返回的数据。由于返回的数据不是JSON数据,所以我们使用正则去获取经纬度坐标。其正则写法见第24行。

返回的数据示例:

showLocation&&showLocation({"status":0,"result":{"location":{"lng":116.30815063007148,"lat":40.056890127931279},"precise":1,"confidence":80,"level":"道路"}})

5、存储获取的经纬度数字。

需要说明的是,为了避免百度数据库中无该企业记录而无法获取经纬度数据,以及避免网页解析出现问题,我们需要加入try—except进行错误异常处理。

6、将生成的数据导出为excel文件(图5)。

图5  成功获取的坐标(约2W条记录,数据量还是比较大的)



二、如何将百度经纬度坐标转换为国测局、WGS84坐标?


1、编写坐标转换的代码(trans.py)。该代码为某网友编写,经测试可用。由于时间比较久了,我无法找到原出处,如果作者看到我的这篇文章,需要我进行署名,可联系我。

# -*- coding: utf-8 -*-

import json

import requests

import math


key = 'your key here'  # 这里填写api的key

x_pi = 3.14159265358979324 * 3000.0 / 180.0

pi = 3.1415926535897932384626  # π

a = 6378245.0  # 长半轴

ee = 0.00669342162296594323  # 扁率


def geocode(address):

"""

利用百度geocoding服务解析地址获取位置坐标

:param address:需要解析的地址

:return:

"""

geocoding = {'s': 'rsv3',

'key': key,

'city': '全国',

'address': address}

res = requests.get(

"http://restapi.amap.com/v3/geocode/geo", params=geocoding)

if res.status_code == 200:

json = res.json()

status = json.get('status')

count = json.get('count')

if status == '1' and int(count) >= 1:

geocodes = json.get('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


def gcj02tobd09(lng, lat):

"""

火星坐标系(GCJ-02)转百度坐标系(BD-09)

谷歌、高德——>百度

:param lng:火星坐标经度

:param lat:火星坐标纬度

:return:

"""

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]


def bd09togcj02(bd_lon, bd_lat):

"""

百度坐标系(BD-09)转火星坐标系(GCJ-02)

百度——>谷歌、高德

:param bd_lat:百度坐标纬度

:param bd_lon:百度坐标经度

:return:转换后的坐标列表形式

"""

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]


def wgs84togcj02(lng, lat):

"""

WGS84转GCJ02(火星坐标系)

:param lng:WGS84坐标系的经度

:param lat:WGS84坐标系的纬度

:return:

"""

if out_of_china(lng, lat):  # 判断是否在国内

return lng, lat

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]


def gcj02towgs84(lng, lat):

"""

GCJ02(火星坐标系)转GPS84

:param lng:火星坐标系的经度

:param lat:火星坐标系纬度

:return:

"""

if out_of_china(lng, lat):

return lng, lat

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):

ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + \

0.1 * lng * lat + 0.2 * math.sqrt(math.fabs(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):

ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + \

0.1 * lng * lat + 0.1 * math.sqrt(math.fabs(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


def out_of_china(lng, lat):

"""

判断是否在国内,不在国内不做偏移

:param lng:

:param lat:

:return:

"""

return not (lng > 73.66 and lng < 135.05 and lat > 3.86 and lat < 53.55)


if __name__ == '__main__':

lng = 128.543

lat = 37.065

result1 = gcj02tobd09(lng, lat)

result2 = bd09togcj02(lng, lat)

result3 = wgs84togcj02(lng, lat)

result4 = gcj02towgs84(lng, lat)

result5 = geocode('北京市朝阳区朝阳公园')

print result1, result2, result3, result4, result5


2、在同一文件夹内编写调用坐标转换的程序trans_coor.py(图6),该代码与 Geocoding API地址解析代码类似。这里需要特别说明的是,必须在程序里 调用刚才的trans.py模块,即增加L9。这里我们将坐标转换为国测局坐标系统以及WGS84坐标系统。

图6 坐标转换的代码

图7 经转换的坐标


结  语



最后,Python的效率比C、C++、java等要低不少,但对追求结果的城市规划师而言,影响不大。当然,我们仍然可以对算法进行优化。我们可以通过使用pandas的apply()函数来代替for循环,其效率要高很多。这个示例的优化我将在后期推出的视频课程中给大家详细介绍。

大家去试试吧!喜欢就赞一个吧!







请到「今天看啥」查看全文