前言
-
本博客总的来说原创的东西不多,主要的内容是集成了多个博主和参考网站的代码,实现了基于百度地图开放平台Web服务api爬取经纬度并转换为WGS84坐标一整套体系流程,文章后面会附上相应作者文章的链接,若有侵权,请联系我修改。
百度地图开放平台创建web服务应用
-
百度开放平台的网站百度地图开放平台
-
创建新的应用之前你需要申请一个账号,并且通过认证。
-
点击控制台–>应用管理–>我的应用–>创建应用,其中应用类型选择服务端,启用的服务默认全部选中即可,请求校验方式选用IP白名校验,0.0.0.0表示不对IP做任何限制,在测试阶段可以设置为该IP,应用正式上线后建议修改。
基于web服务api爬取对应地点的经纬度
-
我的本意是做一个丝绸之路的路线图,因此爬取经纬的地点都是丝绸之路上的地点,原始数据存储以如下格式存储在excel中。
-
经纬度的爬取在网上有很多现场的代码,我直接附上就好了,代码也没啥好讲的,代码运行环境是annaconda的jupyter笔记本。
import urllib
import math
import pandas as pd
import requests
import json
def BaiduQuery(address, currentkey):
url = 'http://api.map.baidu.com/geocoder/v2/'
params = { 'address' : address,
'ak' : currentkey, # 百度密钥
'output': 'json' } # 输出结果设置为json格式
res = requests.get(url,params)
jd = json.loads(res.text)
# 将json格式转化为Python字典
#搜索不到的地点经纬度坐标设置为0,0
if jd['status'] == 1:
coords = {'lng': 0, 'lat': 0}
else:
#百度坐标转火星坐标
coords = jd['result']['location']
coords_1 = baidu_togcj02(coords['lng'], coords['lat'])
coords['lng'] = coords_1[0]['x']
coords['lat'] = coords_1[0]['y']
#火星坐标转WGS84
reverses_coord = gcj02_to_wgs84(coords['lng'], coords['lat'])
coords['lng'] = reverses_coord[0]
coords['lat'] = reverses_coord[1]
return coords
-
可能细心的读者以及发现了我这篇博客的坐标转了两次,一次是转成火星坐标(GCJ02),一次是从火星坐标转成WGS84,原因在下面我会解答。
百度坐标转换参数介绍
-
web服务端的坐标转换限制很大,是通过(http://api.map.baidu.com/geoconv/v1/?)网站获取对应的转换结果,网站的完整请求方式如下
-
‘http://api.map.baidu.com/geoconv/v1/?coords=’+data+’&from=5&to=3&output=json’+’&ak=yourak’
-
上述中data是一个坐标对,形式如"66.968649,39.656794",ad就是创建应用生成的AK,主要参数是from和to,表示初始坐标系和目标坐标系。
-
from:number //源坐标类型,分别有:
1:GPS设备获取的角度坐标,WGS84坐标;
2:GPS获取的米制坐标、sogou地图所用坐标;
3:google地图、soso地图、aliyun地图、mapabc地图和amap地图所用坐标,国测局(GCJ02)坐标;
4:3中列表地图坐标对应的米制坐标;
5:百度地图采用的经纬度坐标;
6:百度地图采用的米制坐标;
7:mapbar地图坐标;
8:51地图坐标 -
to:number //目标坐标类型,分别有:
3:国测局(GCJ02)坐标;
4:3中对应的米制坐标;
5:bd09ll(百度经纬度坐标);
6:bd09mc(百度米制经纬度坐标) -
可以看出百度坐标转换web服务api不支持百度坐标直接到WGS84的转换,但是可以转换成火星坐标,而正好网上有很多火星坐标到WGS84的转换方法,并且是公开的公式,公开方不明,精度保障有限,科研慎用。
-
接下来又是代码了,代码是从百度坐标转成火星坐标的方法。
def baidu_togcj02(lng, lat):
data = str(lng)+','+str(lat)
url = 'http://api.map.baidu.com/geoconv/v1/?coords='+data+'&from=5&to=3&output=json'+'&ak=sHlqv5QdGaZzeIcpAT2gbVe8aFevOpXm'
response = requests.get(url) #发出请求
answer = response.json() #json化
coords = answer['result']
return coords
-
注意:该方法返回的是一个列表,列表的第一项是一个包含坐标对的字典,以x、y为key,所以引用的方式为coords_1[0][‘x’]和 coords_1[0][‘y’]
火星坐标转WGS84
-
直接上代码吧,也没啥好说的,火星坐标对国外的坐标没有偏移,因此国外的坐标不需要进行变化。
pi = math.pi # π
x_pi = pi * 3000.0 / 180.0
a = 6378245.0 # 长半轴
ee = 0.00669342162296594323 # 偏心率平方
def gcj02_to_wgs84(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)
-
上面是方法,测试代码如下
coords = BaiduQuery('碎叶', currentkey="AK")
print(coords)
df = pd.read_excel('丝绸之路城市表.xlsx')
height,width = df.shape
print(df.head(3))
for i in range(0, height):
coords = BaiduQuery(df['city'][i], currentkey="AK")
df['lng'][i] = coords['lng']
df['lat'][i] = coords['lat']
#导出结果到Excel
df.to_excel('city_coords.xls')
print("数据爬取成功,已存储!")
-
爬取结果如下所示:
-
参考博客:
1 :Python源码|GCJ02转WGS84坐标
2:百度地图js 坐标转换
3:Python调用百度地图API爬取经纬度