配额限制下利用百度地图按名称获取POI的技巧
介绍
百度地图获取POI日配额目前限制在100,这个数量对于爬取大量POI的需求是远远不够的。但是实际操作中发现,达到配额后并不是完全不能爬取了,还是有一定概率能获取到结果的,只是按照顺序获取时就会有很多空白,像这样:
{
"status": 302,
"message": "天配额超限,限制访问"
}
如果事先有一个爬取的列表,通过反复爬取来补齐数据可以多获取几倍的数据量。
以下是根据这个现象的解决思路:
- 首先,最好多准备一些密钥key,在爬取的时候随机选用
- 第一遍爬取的时候,保存json结果。
- 读取json中status = 302 的对象,再次爬取,补充数据
- 可以多次运行第三步,知道完成所有列表内容的爬取。
第一步 准备多个密钥
headers = {'User-Agent':'你的header'}
key = ['增加多个key']
# 使用的时候随机取key
keyN = random.randint(0, len(key))
data = getJson(poi, i, key[keyN]) # 这里是获取json的方法,参考爬取POI:合并url用request
第二步 第一遍爬取
已有一份要爬取的名单 poi.csv, 第一遍爬取存储获得的每个json结果
逐个存储并合并为一个json文件的方法:
def firstRequest(start, end, jsonPath, key):
# jsonPath 是存储的路径
for i in range(start, end):
data = getJson(poi, i, key) # 这里是获取json的方法,参考爬取POI:合并url用request
if data != '':
try:
with open(jsonPath, 'r', encoding='utf-8') as json_file:
old_data = json.load(json_file) # 先加载原有的数据
with open(jsonPath, 'w+', encoding='utf-8') as json_file:
old_data.append(data) # 将新数据合并进去
json_file.write(json.dumps(old_data, indent=True, ensure_ascii=False))
except FileNotFoundError: # 如果是第一次创建
with open(jsonPath, 'a', encoding='utf-8') as json_file:
old_data = json.dumps(data, indent=True, ensure_ascii=False)
json_file.write('[')
json_file.write(old_data)
json_file.write(']')
print(i, poi.loc[i, '名称']) # 成功的
time.sleep(random.uniform(0.5, 2)) # 随机休眠
else:
print(i, poi.loc[i, '名称'], " not found") #如果没有数据,占位
with open(jsonPath, 'w+', encoding='utf-8') as json_file:
json_file.seek(-1, os.SEEK_END)
json_file.truncate()
json_file.write(',{}]')
continue
如果达到配额会出现多个这样的json, status显示为302:
{
"status": 302,
"message": "天配额超限,限制访问"
}
而能够获取的json是这样的, status 为0 :
{
"status": 0,
"message": "ok",
"total": 80,
"result_type": "poi_type",
"results": [
{
"name": "北京大学",
"location": {
"lat": 39.998877,
"lng": 116.316833
},
"address": "北京市海淀区颐和园路5号",
"province": "北京市",
"city": "北京市",
"area": "海淀区",
"street_id": "ddfd7c2d8db36cf39ee3219e",
"telephone": "(010)62752114",
"detail": 1,
"uid": "ddfd7c2d8db36cf39ee3219e"
},
……
]
}
第三步 替换缺失部分
def replace302(poi, json_path):
file = open(json_path, 'r', encoding='utf-8')
data = json.load(file)
for i in range(0,len(data)):
d = data[i]
if d["status"] != 302:
continue
# 找到配额超出的部分
keyN = random.randint(0, 3)
new_data = getJson(poi, i, key[keyN])
if(new_data == '') | (new_data['status'] == 302):
continue
#替换新的数据进去
data[i] = new_data
print(i,poi.loc[i,'名称'])
with open(json_path, 'w+', encoding='utf-8') as json_file:
json_file.write(json.dumps(data, indent=True, ensure_ascii=False)) # indent 缩进
time.sleep(random.uniform(0.5, 2)) # 随机休眠
第四步 循环第三步的方法
反复进行直到补齐所有数据,当然超出太多到后面基本上很少能爬到了,经过测试大概还是能多几倍数据。之后再解析json,因为获取数据有缺失所以建议先存json补齐了再解析。