本篇文章转自CSDN大神Giser@lin的两篇大作:https://blog.csdn.net/abcbbbd?type=blog
方法一,关键词搜索法获取POI(不推荐)
主程,根据指定关键词抓取高德店铺的店名、地址及联系方式信息。
import requests
import json
from urllib.parse import quote
import xlwt
from Coordin_transformlat import gcj02towgs84
def Get_poi(key, city, types, page):
'''
这是一个能够从高德地图获取poi数据的函数
key:为用户申请的高德密钥
city:目标城市
types: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"}
# 构建url
# {}在链接里表示占位符,也就是占住位置先不填写,.format()里就是往刚刚占位符的地方填写变量,按照顺序一一对应,第一个{}里是key,第二个{}里是types
url = 'https://restapi.amap.com/v3/place/text?key={}&types={}&city={}&page={}&output=josn'.format(
key, types, quote(city), page)
# 用get函数请求数据
r = requests.get(url, headers=header)
# 设置数据的编码为'utf-8'
r.encoding = 'utf-8'
# 将请求得到的数据按照'utf-8'编码成字符串
data = r.text
print(url)
return data
def Get_times(key, city, types):
'''
这是一个控制申请次数的函数
'''
page = 1
# 创建一个poilist的空列表
poilist = []
# 执行以下代码,直到count为0的时候跳出循环
while True:
# 调用第一个函数来获取数据
result = Get_poi(key, city, types, page)
# json.loads可以对获取回来JSON格式的数据进行解码
content = json.loads(result)
# print(content)
# content的样子其实跟返回结果参数是一样的,可以想象成有很多个字段的excel表格,下面这个语句就是提取出pois那个字段
pois = content['pois']
# pois的信息写入空列表里
for i in range(len(pois)):
poilist.append(pois[i])
# 递增page
page = page + 1
# 判断当前页下的count是否等于0
if content['count'] == '0':
break
# 将写好poi信息的列表返回
return poilist
def write_to_excel(poilist, city, types):
# 这是一个可以将列表写入excel的函数
# poilist -- 上面得到的poilist
# city -- 城市名,这个参数是保存excel文件的名字用的
# types -- poi类别,这个也是为了保存excel文件,可直接看代码最后一行
# 我们可以把这两行代码理解成新建一个excel表,第一句是新建excel文件
book = xlwt.Workbook(encoding='utf-8', style_compression=0)
# 往这个excel文件新建一个sheet表格
sheet = book.add_sheet(types, cell_overwrite_ok=True)
# 第一行(列标题)
sheet.write(0, 0, 'x')
sheet.write(0, 1, 'y')
sheet.write(0, 2, 'count')
sheet.write(0, 3, 'name')
sheet.write(0, 4, 'tel')
sheet.write(0, 5, 'address')
sheet.write(0, 6, 'adname')
for i in range(len(poilist)):
name = poilist[i]['name']
tel = poilist[i]['tel']
location = poilist[i]['location']
address = poilist[i]['address']
adname = poilist[i]['adname']
lng = str(location).split(",")[0]
lat = str(location).split(",")[1]
result = gcj02towgs84(location)
lng = result[0]
lat = result[1]
sheet.write(i + 1, 0, lng)
sheet.write(i + 1, 1, lat)
sheet.write(i + 1, 2, 1)
sheet.write(i + 1, 3, name)
sheet.write(i + 1, 4, tel)
sheet.write(i + 1, 5, address)
sheet.write(i + 1, 6, adname)
# 最后,将以上操作保存到指定的Excel文件中
book.save(city + "_" + types + '.xls')
# 这里修改为自己的高德密钥
key = 'b00578b8d5db123455555'
# 这里修改自己的poi类型
types = ['关键词']
# 建议将大区域切分成几个小区域来获取,保证获取的数据齐全
city_list = ['白云区', '天河区', '越秀区', '黄埔区']
# 先遍历city_list里面的每个区域
for city in city_list:
# 再遍历types里的每个类别
for type in types:
poi = Get_times(key, city, type)
print('当前城市:' + str(city) + ', 分类:' +
str(type) + ", 总的有" + str(len(poi)) + "条数据")
write_to_excel(poi, city, type)
print('*'*50+'分类:' + str(type) + "写入成功"+'*'*50)
print('====爬取完成====')
百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换,这个文件引入主程,文件名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
方法二,矩形搜索法获取POI(推荐)
文件名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']
tel = pois[i]['tel']
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, tel, 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']))
主程,根据指定关键词抓取高德店铺的店名、地址及联系方式信息。
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 ='12344333304ed3230235cf'
#这里修改自己的poi类型
keywords = '关键词'
#这里输入想要查询的城市
city = '广州'
#调用高德查询行政区的API接口来返回矩形坐标对
Retance = gp.get_city_scope(key,city)
#存储区域矩形的列表
input_polygon = []
input_polygon.append(Retance)
Quadrangle(key,input_polygon,keywords)
本方法也需引入方法一中的Coordin_transformlat.py文件,推荐使用Python3.11,可以最少安装需要的模块,实测运行没有任何问题。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。