1. 程式人生 > >百度地圖POI數據爬取,突破百度地圖API爬取數目“400條“的限制11。

百度地圖POI數據爬取,突破百度地圖API爬取數目“400條“的限制11。

XML response city 代碼實現 append api json highlight inf

1.POI爬取方法說明

1.1AK申請

  登錄百度賬號,在百度地圖開發者平臺的API控制臺申請一個服務端的ak,主要用到的是Place API.檢校方式可設置成IP白名單,IP直接設置成了0.0.0.0/0比較方便。
  Place API 提供的接口用於返回查詢某個區域的某類POI數據,且提供單個POI的詳情查詢服務,用戶可以使用C#、C++、Java,Python等開發語言發送請求,接收json、xml的數據。關於Place API的具體使用可以參考:Place API Web服務API

1.2爬取方式

  百度地圖將POI數據劃分為多個類別,我想要爬取某個城市的所有類別的POI名稱和經緯度信息。爬取時,先將類別存儲在一個“POI總表.csv”文件中,再逐類別爬取POI數據。POI總表包含POI類別、POI類別對應的編碼、各類POI記錄條數。

  Place API提供了3種爬取區域POI信息的方式:(1)城市內檢索 (2)矩形檢索 (3)圓形區域檢索。這裏,POI信息的爬取主要使用城市內檢索和矩形檢索兩種方式。

技術分享圖片
1.2.1城市內檢索

  城市內檢索主要的請求參數是query查詢的類別、region查詢的城市名稱。將查詢得到json格式的數據,解碼為utf-8編碼方式後存儲在content中。通過正則表達式可以得到POI的名稱和經緯度信息。

reg = r‘"name":"([\d\D]*?)",[\d\D]*?"lat":([\d\D]*?),[\d\D]*?"lng":([\d\D]*?)},‘
pattern = re.compile(reg)

items = re.findall(pattern,content)

技術分享圖片
1.2.2矩形檢索

矩形檢索的主要請求參數是query查詢的類別、bounds查詢區域的左下、右上經緯度。lat,lng(左下角坐標),lat,lng(右上角坐標)。查詢得到的結果與城市範圍內檢索結果相似。
通過兩種方式實現POI的區域檢索都很便捷,但是當城市較大,某一類POI信息數量大時,由於百度API的限制,1.2.1城市內檢索最多只能返回400條POI數據,會造成查不全的現象。這時,可以利用矩形檢索,將區域的外包矩形劃分為多個小網格,並確保每個網格中該類別POI數據的條數不會超過400條,這樣逐個小網格進行矩形檢索,最終得到城市區域某一類別POI的所有數據。

技術分享圖片
2.Python代碼實現

2.1 城市內檢索

  城市區域內檢索通過正則表達式re獲取需要的信息,當該城市某一類POI數量大於400時,可使用劃分為網格的矩形檢索進行POI爬取,以保證爬取到完整的POI數據。

# -*- coding: utf-8 -*- 
import sys
import codecs
import urllib
import urllib2
import re
import pandas as pd

reload(sys)
sys.setdefaultencoding(‘utf-8‘)

user_agent = ‘Mozilla/5.0 (Windows; U; Windows NT 5.2)‘
headers = {‘User-Agent‘:user_agent}

inpath = ‘POI總表.csv‘
path = unicode(inpath, ‘utf-8‘)
poi_list = pd.read_csv(path)
api_key="" #輸入AK

for poi in range(len(poi_list)):
outpath = ‘+str(poi)+‘_‘+poi_list.iloc[poi, 1] + ‘.csv‘
path = unicode(outpath, ‘utf-8‘)
with open(path, ‘w‘) as f:
f.write(codecs.BOM_UTF8)
f.write(‘id,name,lat,lng\n‘)
i=1
j=1
try:
for i in range(int(poi_list.iloc[poi,4])/10+2):
url = "http://api.map.baidu.com/place/v2/search?q="+poi_list.iloc[poi,3]+"&page_size=10&page_num="
url = url+str(i-1) + "&scope=1®ion=%E6%AD%A6%E7%A9%B4&city_limit=true&coord_type=1&output=json&ak="
+api_key # ak需輸入申請的ak 
request = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(request)
content = response.read().decode("utf-8")
# print content
reg = r‘"name":"([\d\D]*?)",[\d\D]*?"lat":([\d\D]*?),[\d\D]*?"lng":([\d\D]*?)},‘
pattern = re.compile(reg)
items = re.findall(pattern,content)
for item in items:
# print "name:",item[0]
# print "lat:",item[1]
# print "lng:",item[2]
savestr = str(j)+‘,‘+str(item[0])+‘,‘+str(item[1])+‘,‘+str(item[2])
j += 1
f.write(savestr)
except urllib2.URLError, e:
if hasattr(e, "code"):
print e.code
if hasattr(e, ‘reason‘):
print e.reason
finally:
f.close()

  


2.2 矩形區域檢索

  BaiduPOI通過url獲取POI數據,LocaDiv劃分網格,逐個網格爬取POI數據。

# -*- coding:utf-8 -*-
import json
import codecs
import os
import urllib2
import sys
import time

reload(sys)
sys.setdefaultencoding(‘utf8‘)


class BaiDuPOI(object):
def __init__(self, itemy, loc):
self.itemy = itemy
self.loc = loc

def urls(self):
api_key = baidu_api
urls = []
for pages in range(0, 20):
url = ‘http://api.map.baidu.com/place/v2/search?query=‘ + self.itemy + ‘&bounds=‘ + self.loc + ‘&page_size=20&page_num=‘ + str(
pages) + ‘&output=json&ak=‘ + api_key
urls.append(url)
return urls

def baidu_search(self):
json_sel = []
for url in self.urls():
json_obj = urllib2.urlopen(url)
data = json.load(json_obj)
for item in data[‘results‘]:
jname = item["name"]
jlat = item["location"]["lat"]
jlng = item["location"]["lng"]
js_sel = jname + ‘,‘ + str(jlat) + ‘,‘ + str(jlng)
json_sel.append(js_sel)
return json_sel


class LocaDiv(object):
def __init__(self, loc_all):
self.loc_all = loc_all

def lat_all(self):
lat_sw = float(self.loc_all.split(‘,‘)[0])
lat_ne = float(self.loc_all.split(‘,‘)[2])
lat_list = []
for i in range(0, int((lat_ne - lat_sw + 0.0001) / 0.1)): # 0.1為網格大小,可更改
lat_list.append(lat_sw + 0.1 * i) # 0.05
lat_list.append(lat_ne)
return lat_list

def lng_all(self):
lng_sw = float(self.loc_all.split(‘,‘)[1])
lng_ne = float(self.loc_all.split(‘,‘)[3])
lng_list = []
for i in range(0, int((lng_ne - lng_sw + 0.0001) / 0.1)): # 0.1為網格大小,可更改
lng_list.append(lng_sw + 0.1 * i) # 0.1為網格大小,可更改
lng_list.append(lng_ne)
return lng_list

def ls_com(self):
l1 = self.lat_all()
l2 = self.lng_all()
ab_list = []
for i in range(0, len(l1)):
a = str(l1[i])
for i2 in range(0, len(l2)):
b = str(l2[i2])
ab = a + ‘,‘ + b
ab_list.append(ab)
return ab_list

def ls_row(self):
l1 = self.lat_all()
l2 = self.lng_all()
ls_com_v = self.ls_com()
ls = []
for n in range(0, len(l1) - 1):
for i in range(0 + len(l1) * n, len(l2) + (len(l2)) * n - 1):
a = ls_com_v[i]
b = ls_com_v[i + len(l2) + 1]
ab = a + ‘,‘ + b
ls.append(ab)
return ls


if __name__ == ‘__main__‘:
# ak
baidu_api ="" # 這裏填入你的百度API的ak
print "開始爬取數據,請稍等..."
start_time = time.time()
loc = LocaDiv(‘29.8255, 115.367400, 30.2194, 115.8287‘)
locs_to_use = loc.ls_row()

for loc_to_use in locs_to_use:
par = BaiDuPOI(u‘購物‘, loc_to_use) # 請修改爬取的類別
a = par.baidu_search()
doc = open(‘zhengfujigou.csv‘, ‘a+‘)
doc.write(codecs.BOM_UTF8)
for ax in a:
doc.write(ax)
doc.write(‘\n‘)
doc.close()
end_time = time.time()
print "購物爬取完畢,用時%.2f秒" % (end_time - start_time)

  


2.3爬取結果示例

技術分享圖片
---------------------
作者:haha_point
來源:CSDN
原文:https://blog.csdn.net/haha_point/article/details/78079614
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

百度地圖POI數據爬取,突破百度地圖API爬取數目“400條“的限制11。