事先声明,本人小白一枚,第一次写博客,对地理信息系统这方面基本不了解,因最近在一个规划公司实习,想整理一下做过的一些项目,参考了很多人的代码,也看到一些人需要这方面的代码,网上的一些代码都是Python2的,和Python3有一点区别,比如Python3中urllib2已经合并为了urllib,但函数基本都还是有的,需要大家去找一找。不喜勿喷!!!!
-
首先说明一下,什么是POI:
POI是“Point of Interest”的缩写,中文翻译叫兴趣点,在地理信息系统中,一个POI可以是一栋房子、一个商铺、一个邮筒、一个公交站等。
而我要做的呢就是利用百度地图提供的API接口获取某一类型的POI,比如餐饮、公交站等(虽然我不知道这些数据能用了来干嘛,像我们专业做分析都是抓评论的。。) -
百度地图API:
要想用百度地图的API,是需要申请产品密钥的,这个比较容易。登录百度账号,在百度地图开发者平台的API控制台申请一个服务端的AK。应用名称任意,IP白名单就0.0.0.0/0就可以。
但是你这个申请的秘钥还不能获取很多数据,要想获取,需要进一步申请认证
http://lbsyun.baidu.com/apiconsole/record
(证件一定要清晰)。
拿到AK以后就可以进行后续操作了。
-
怎么爬取
要知道,每个区域爬取POI数目上限是400,也就是说,如果你要爬取的区域内的POI数目大于400,就只能获取400,所以我们要对区域进行划分,让每个区域内POI数目在400以内,这样就不会了。这里我们用矩形检索,主要请求参数是query查询的类别、bounds查询区域的左下、右上经纬度。lat,lng(左下角坐标),lat,lng(右上角坐标)。将查询得到json格式的数据,解码为utf-8编码方式后存储在content中
大致就是这样:
http://api.map.baidu.com/place/v2/search?query=%E8%A5%BF%E9%A4%90&bounds=23.1121,113.4408,23.212100000000003,113.5408&page_size=20&page_num=0&output=json&ak=
(你的API秘钥)
然后我们将这个大矩形划分为若干小矩形就OK了。好了,废话不多少上代码:
代码块
import json
from urllib.request import urlopen
import time
from urllib import request
def urls(itemy, loc):
#baidu_api = "你的秘钥"
urls=[]
for page in range(0,20):
url = "http://api.map.baidu.com/place/v2/search?query=" + request.quote(itemy) + "&bounds=" + loc
url = url + "&page_size=20&page_num=" + str(page) + "&output=json&ak=你的秘钥"
urls.append(url)
return urls
def baidu_search(urls):
try:
json_sel = []
for url in urls:
req = request.Request(url)
json_obj = urlopen(req)
data = json.load(json_obj)
for item in data['results']:
jname = item["name"]
jlat = item["location"]["lat"]
jlng = item["location"]["lng"]
if "telephone" in item:
jtel = item["telephone"].replace(',',' ')
else:
jtel = ''
js_sel = jname + ',' + str(jlat) + ',' + str(jlng) + ',' + str(jtel)
json_sel.append(js_sel)
except:
pass
return json_sel
def lat_all(loc_all):
lat_sw = float(loc_all.split(',')[0])
lat_ne = float(loc_all.split(',')[2])
lat_list = []
for i in range(0, int((lat_ne - lat_sw ) / 0.01)): # 网格大小,可根据区域内POI数目修改
lat_list.append(lat_sw + 0.01 * i)
lat_list.append(lat_ne)
return lat_list
def lng_all(loc_all):
lng_sw = float(loc_all.split(',')[1])
lng_ne = float(loc_all.split(',')[3])
lng_list = []
for i in range(0, int((lng_ne - lng_sw ) / 0.01)):
lng_list.append(lng_sw + 0.01 * i)
lng_list.append(lng_ne)
return lng_list
def ls_com(loc_all):
l1 = lat_all(loc_all)
l2 = lng_all(loc_all)
ab_list = []
for i1 in range(0, len(l1)):
a = str(l1[i1])
for i2 in range(0, len(l2)):
b = str(l2[i2])
ab = a + ',' + b
ab_list.append(ab)
return ab_list
def ls_row(loc_all):
l1 = lat_all(loc_all)
l2 = lng_all(loc_all)
ls_com_v = ls_com(loc_all)
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
ab_list = ab.split(',')
if (ab_list[0] < ab_list[2] and ab_list[1] < ab_list[3]):
ls.append(ab)
return ls
if __name__ == '__main__':
print("开始爬取数据,请稍等...")
start_time = time.time()
loc = '23.1121, 113.3408, 23.1475, 113.3902'
locs_to_use = ls_row(loc)
i = 0
num = []
filepath = '你的路径\政府.txt'
f = open(filepath, 'w',encoding='utf-8')
for loc_to_use in locs_to_use:
print(loc_to_use)
i += 1
print("正在采集第%d个区域"%i)
par = urls(u'政府', loc_to_use)
print(par)
a = baidu_search(par)
b = len(a)
num.append(b)
print("第%d个区域采集数量为%d"%(i,b))
for ax in a:
print('政府,' + ax)
item = '政府,' + ax
f.write(item)
f.write("\n")
end_time = time.time()
print("爬取完毕,用时%.2f秒" % (end_time - start_time))
好了,以上代码是在参考前人的基础上修改的,本人在Python以及爬虫上还是小白,如有问题,欢迎指正。
另外,代码中有一些输出是给我自己看的,比如区域内的POI数目,这个我是为了调控网格大小的,还有就是说一下
request.quote()是将ASCII码转换为URL编码的,这里烦了我好久,踩得比较深的坑。