Python实践笔记 - 1、高德地图的坐标转换与周边搜索
张板书的Python的实践笔记,包括笔记与DeBug的经历。
为了完成一个比较麻烦的实习任务,尝试着做了这样一个爬虫项目。
实践内容为对一个储存了地点的 csv 表格进行处理,并在地图上标好,同时检查这些地点周围是否存在某类型的企业,如果有需要进行标注。
思考得到,需要将这些地点标注在地图上,就需要得到其经纬度,并要基于高德、百度、腾讯等进行此地点的周边搜索,并将符合要求的信息放在csv中。
目录
一、高德地图的开发平台
https://lbs.amap.com/ # 高德开放平台
申请key
高德Web服务API向开发者提供HTTP接口,开发者可通过这些接口使用各类型的地理数据服务,返回结果支持JSON和XML格式。
Web服务API对所有用户开放。使用服务之前,需要在高德开放平台上创建应用,并根据需求申请对应的服务key。不同类型用户可获取不同的数据访问能力。
例如对本次的需求,我们需要进行坐标转换与周边搜索,所以需要 Web服务。
阅读开发文档
然后需要阅读开发文档
https://lbs.amap.com/api/webservice/summary/
坐标转换
文档中说:
坐标转换是一类简单的HTTP接口,能够将用户输入的非高德坐标(GPS坐标、mapbar坐标、baidu坐标)转换成高德坐标。
而在这里我们要将一个产业园名称转换为经纬度信息。
第一步,申请”Web服务API”密钥(Key);
第二步,拼接HTTP请求URL,第一步申请的Key需作为必填参数一同发送;
第三步,接收HTTP请求返回的数据(JSON或XML格式),解析数据。
如无特殊声明,接口的输入参数和输出数据编码全部统一为UTF-8。
文档中给出接口url、请求方式和请求参数:
1、请求url:
即需要程序向 https://restapi.amap.com/v3/geocode/geo 发送 get 请求,且同时发送参数parameters;
"https://restapi.amap.com/v3/geocode/geo"
2、parameters
在这里是一个字典,字典的具体内容在下面的表格3中;
3、请求参数
params = { 'key': '这里填写之前申请的 web服务 的key',
'address': city }
对于向 url 发送请求后,服务器会把标准化的返回信息以某种格式发送给你,具体标准在开发文档中也有说明:
周边搜索
和坐标转换一样,不同的只是 url 和请求参数。
params = {'key': '你申请的 web服务 的key',
'location': location, # 用于表示待标注点的坐标,格式为(经纬,纬度)
'keywords': keywords, # 表示搜索的关键词,多个关键词用 | 分割
'offset': '20', # 每页记录的数据,不要超过25
'page':page, # 当前页数,最大翻页100
'types':'170000',
# 'output': "JSON", # 返回数据格式类型
'radius': distance, # 表示搜索的范围半径,单位:米。取值范围(1,50000),默认为3000。
# "sortrule":"distance" # 返回结果的排序方式;按距离排序:distance;综合排序:weight
}
二、用 Python 来进行抓取
坐标转换
import requests
import json
def get_JWD(city):
url = 'https://restapi.amap.com/v3/geocode/geo'
# 将两个参数放入字典中作为请求参数
parameters = { 'key': '这里填写之前申请的 web服务 的key',
'address': city }
res = requests.get(url, params)
response = json.loads(res.text) # 使用json来解析返回信息
try:
return response['geocodes'][0]['location'] # 解析方式在下面
except:
print ("Erro 地址: {} 查询错误,错误代码: {}".format(city,jd['info']))
return "Error"
返回信息可以使用开发文档中的插件先进行尝试:
尝试一下之后可以看返回信息大概是个什么样子,然后再使用相关工具来进行解析
我们需要得到经纬度,故需要解析的内容是
response['geocodes'][0]['location']
运行结果如下:
get_JWD("北京大学")
>>>116.308264,39.995304
get_JWD("这啥都不是")
>>>Erro 地址: 这啥都不是 查询错误,错误代码: OK
附近搜索
同理,做附近搜索的项目
import requests
import json
def zhoubian_search(location,keywords,distance,page): # 输入地址查询周边,参数:中心经纬度,关键词,搜索半径,第几页
requests.adapters.DEFAULT_RETRIES = 5
s = requests.session()
s.keep_alive = False
url = "https://restapi.amap.com/v3/place/around"
params = {'key': 'f18d291d2fd31af29c6d2c3378c6d310',
'location': location, # 用于表示待标注点的坐标,格式为(经纬,纬度)
'keywords': keywords, # 表示搜索的关键词,多个关键词用 | 分割
'offset': '10', # 每页记录的数据,不要超过25
'page':page, # 当前页数,最大翻页100
# 'types':'170000',# 如果是 170000,则只搜索所有类型为“企业”的地点
# 'output': "JSON", # 返回数据格式类型
'radius': distance, # 表示搜索的范围半径,单位:米。取值范围(1,50000),默认为3000。
# "sortrule":"distance" # 返回结果的排序方式;按距离排序:distance;综合排序:weight
}
res = requests.get(url, params)
jd = json.loads(res.text)
ifo = ""
try:
for poi in jd['pois']:
print("企业: {}\t 距离:{}".format(poi["name"],poi["distance"]))
if check(poi["name"]): # 简单的数据清洗
ifo += "企业:{} 距离:{} m \t".format(poi["name"],poi["distance"])
return ifo
except:
return "Error"
zhoubian_search("116.308264,39.995304","理发店",5000,1)
>>>企业: 越秀专业美发 距离:686
>>>企业: 北京大学燕园美发 距离:762
>>>企业: 锡华酒店美容美发 距离:815
>>>企业: 啊木造型 距离:828
>>>企业: 好心情美发 距离:885
>>>企业: 越秀造型 距离:958
>>>企业: 胡同理发店 距离:1015
>>>企业: 雨琪造型 距离:1049
>>>企业: 思丝清心美容美发 距离:1050
>>>企业: 思阳光理发店 距离:1062
简单的数据清洗
下面对返回的数据进行一些简单的数据清洗,比如我们不想要名称中含有 “理发店” 与 “美容美发” 的,就需要写一个简易的清洗函数,清洗掉所有含:
def check(name):
white_list = ["理发店","美发","美容"]
CK = 0
for word in white_list:
try:
name2 = name.replace(word,"") # 原名称去掉白名单中的关键词
if name != name2: # 去掉之后不一样,则说明有白名单中的词
CK += 1
# return False # 返回不能用
except:
CK = CK
if CK > 0: # 有白名单中的词
return False
else:
return True
zhoubian_search("116.308264,39.995304","理发店",5000,1)
>>>企业: 啊木造型 距离:828
>>>企业: 越秀造型 距离:958
>>>企业: 雨琪造型 距离:1049
>>>企业: 木北护肤造型(水磨社区店) 距离:1080
>>>企业: 标心立艺 距离:1085
>>>企业: 鑫沐造型(苏州街店) 距离:1311
>>>企业: 时光发廊 距离:1353
>>>企业: 元琦造型 距离:1398
三、加上 csv 的处理
def get_JWD_file(keywords): # 根据查询关键字列表生成表格
error_count = 0
distance = 3000
page = 1
adress = "单位"
file1 = r"开发区2-0.csv" # 存了各单位名称的文件地址
file2 = r"ing.csv" # 需要有一个新的文件,这个文件最好用excel另存为“CSV UTF-8(逗号分隔)”格式,否则保存出来可能解码不出中文来
# open(file2, "w",encoding = "utf-8")
with open(file1, "r", encoding = "utf-8") as f, open(file2, "r", encoding = "utf-8") as f2 :
reader = csv.DictReader(f)
writer = csv.DictReader(f2)
reader_l = [row for row in reader]
writer_l = [row for row in writer]
for i in range(len(reader_l)):
line = {}
line[adress] = reader_l[i][adress]
for keyword in keywords: # 不止一个关键词
ifo = zhoubian_search(get_JWD(reader_l[i][adress]),keyword,distance,page)
if ifo == "Error": # 如果找不到
error_count += 1
print("# # # # # # # --- NO:{} 地址:{} 实在是找不到 --- # # # # # # #".format(error_count,reader_l[i][adress]))
line["检索关键词:{}".format(keyword)] = ifo
if i % 10 == 0:
print("————— 关键词:{} 查询已完成 {} / {} ; 查询错误 {}—————".format(keyword,i,len(reader_l),error_count))
writer_l.append(line)
print("————— 查询已完成 {} / {} ; 查询错误共 {} 个 —————".format(i,len(reader_l),error_count))
file2 = "ing.csv"
header = writer_l[0].keys()
datas = writer_l
with open(file2, 'a', newline='',encoding='utf-8') as f:
writer = csv.DictWriter(f,fieldnames=header) # 提前预览列名,当下面代码写入数据时,会将其一一对应。
writer.writeheader() # 写入列名
writer.writerows(datas) # 写入数据