百度地图提供了丰富的api供开发者调用。我们可以免费获取各类地点的具体信息。
本次使用百度地图api获取数据,采用到的技术如下:
1.爬取网页:使用requests请求百度地图api地址
2.解析网页:提取json数据
3.存储数据:存储至MySQL数据库
1项目描述
本项目的目标是,通过百度地图web服务api获取中国所有城市的公园数据,并获取每一个公园具体评分、描述等详细内容,最终将数据存储到MySQL数据库。
百度地图Place API(web服务api--地点检索)地址为 http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi
网络爬虫除了进入网站网页爬取外还可以通过网站提供的api进行爬取,由于api是官方提供的获取数据通道,所以数据的获取没有争议,如果一个网站提供api获取数据,最好使用api进行数据获取,简单又便捷。
除了百度地图外,其他国内提供api免费获取数据的站点还有新浪微博,豆瓣电影,饿了吗,豆瓣音乐等等,国外提供api服务的有Facebook,Twitter等。除此之外,还有很多收费的api数据站点服务,包括百度 api store 和聚合数据等。其他可以搜索一下就有了。
2获取api秘钥
进入这个 http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi 网址后,点击右上角的登录,用自己的百度账号进行登录,登录后可以进入api控制台。(如果没有注册为开发者需要注册认证完即可),然后单击创建应用按钮。
填写好应用名称,选择使用ip白名单校验方式进行校验。在ip白名单的文本框中填写0.0.0.0/0,表示不对ip做任何限制。单机提交,即可在api控制台看到自己创建的AK,就是api请求串的必填参数。
有一点注意的是,未认证(个人或企业)的情况下,每个账号一天最多只有2000次调用额,如果认证了,每个账号每天有10万次调用额。
3 项目实施
本次项目实施主要分为三步:
1.获取所有拥有公园的城市,并将数据存储到txt文本中。
2.获取所有城市的公园数据,并将数据存储到MySQL数据库中。
3.获取所有公园的详细信息,并将数据存储到MySQL数据库中。
在百度地图Place api中,如果需要获取数据,向指定URL地址发送一个get请求即可。例如,要获取数据的城市为北京,检索关键字为“ATM机”,分类偏好为银行,检索后返回10条数据,可以请求下面地址(通过 行政区划区域检索):http://api.map.baidu.com/place/v2/search?query=ATM机&tag=银行®ion=北京&output=json&ak=您的ak //GET请求
请求参数,设置如下(具体查看链接):
还有其他的检索方式,这里不一一介绍了,具体可参考 http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi 中的服务文档。
下面尝试获取北京市的公园数据,并用json数据格式返回,代码如下:
# coding=utf-8
import requests
import json
\'\'\'
获取北京市的公园数据,并用json数据格式返回
\'\'\'
def get_json(region):
headers = {
\'User-Agent\': \'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16\'
}
params = {
\'query\': \'公园\', #检索关键字
\'region\': region, #检索行政区划区域
\'output\': \'json\', #输出格式为json
\'scope\': \'2\', #检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息
\'page_size\': 20, #单次召回POI数量,默认为10条记录,最大返回20条。
\'page_num\': 0, #分页页码,默认为0,0代表第一页,1代表第二页,以此类推。
\'ak\': \'Kcl9bynY5Icf1yGv6mQPzS7Phhkuw0Pb\'
}
res = requests.get("http://api.map.baidu.com/place/v2/search", params=params, headers=headers)
content = res.text
decodejson = json.loads(content) #将已编码的 JSON 字符串解码为 Python 对象,就是python解码json对象
#return decodejson
print(decodejson)
get_json("北京市")
输出结果为:
3.1 获取所有拥有公园的城市
接下来我们获取所有拥有公园的城市,并把数据存储到txt文本中。
在百度地图Place api,如果region的值为“全国”或则某个省份,则会返回指定区域的POI和数量。
我们可以把region设置为各个省份,进而获取各个省份各个市的公园数量。还有就是四大直辖市(北京、上海、天津、重庆)、香港特别行政区和澳门特别行政区,一个城市便是省级行政单位,因此region设置的省份不包含这些特殊省级行政单位。
# coding=utf-8
import requests
import json
\'\'\'
获取所有拥有公园的城市,并把数据存储到txt文本中
\'\'\'
def get_json(region):
headers = {
\'User-Agent\': \'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16\'
}
params = {
\'query\': \'公园\', #检索关键字
\'region\': region, #检索行政区划区域
\'output\': \'json\', #输出格式为json
\'scope\': \'2\', #检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息
\'page_size\': 20, #单次召回POI数量,默认为10条记录,最大返回20条。
\'page_num\': 0, #分页页码,默认为0,0代表第一页,1代表第二页,以此类推。
\'ak\': \'Kcl9bynY5Icf1yGv6mQPzS7Phhkuw0Pb\'
}
res = requests.get("http://api.map.baidu.com/place/v2/search", params=params, headers=headers)
content = res.text
decodejson = json.loads(content) #将已编码的 JSON 字符串解码为 Python 对象,就是python解码json对象
return decodejson
# print(decodejson)
# get_json("北京市")
province_list = [\'江苏省\', \'浙江省\', \'广东省\', \'福建省\', \'山东省\', \'河南省\', \'河北省\', \'四川省\', \'辽宁省\', \'云南省\',
\'湖南省\', \'湖北省\', \'江西省\', \'安徽省\', \'山西省\', \'广西壮族自治区\', \'陕西省\', \'黑龙江省\', \'内蒙古自治区\',
\'贵州省\', \'吉林省\', \'甘肃省\', \'新疆维吾尔自治区\', \'海南省\', \'宁夏回族自治区\', \'青海省\', \'西藏自治区\']
for eachprovince in province_list:
decodejson = get_json(eachprovince)
for eachcity in decodejson[\'results\']:
city = eachcity[\'name\']
num = eachcity[\'num\']
content = \'\t\'.join([city,str(num)])+\'\r\n\'
with open(\'citys_garden_num.txt\',\'a+\',encoding=\'utf-8\') as f:
f.write(content)
f.close()
输出结果为:
接着,我们还要获取四个直辖市以及香港和澳门的数据,并把数据追加写入到citys_garden_num.txt文本中。
# coding=utf-8
import requests
import json
\'\'\'
获取所有拥有公园的城市,并把数据存储到txt文本中
\'\'\'
def get_json(region):
headers = {
\'User-Agent\': \'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16\'
}
params = {
\'query\': \'公园\', #检索关键字
\'region\': region, #检索行政区划区域
\'output\': \'json\', #输出格式为json
\'scope\': \'2\', #检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息
\'page_size\': 20, #单次召回POI数量,默认为10条记录,最大返回20条。
\'page_num\': 0, #分页页码,默认为0,0代表第一页,1代表第二页,以此类推。
\'ak\': \'Kcl9bynY5Icf1yGv6mQPzS7Phhkuw0Pb\'
}
res = requests.get("http://api.map.baidu.com/place/v2/search", params=params, headers=headers)
content = res.text
decodejson = json.loads(content) #将已编码的 JSON 字符串解码为 Python 对象,就是python解码json对象
return decodejson
# print(decodejson)
# get_json("北京市")
decodejson = get_json(\'全国\')
six_cities_list = [\'北京市\',\'上海市\',\'重庆市\',\'天津市\',\'香港特别行政区\',\'澳门特别行政区\',]
for eachprovince in decodejson[\'results\']:
city = eachprovince[\'name\']
num = eachprovince[\'num\']
if city in six_cities_list:
content = \'\t\'.join([city, str(num)]) + \'\r\n\'
with open(\'citys_garden_num.txt\', "a+", encoding=\'utf-8\') as f:
f.write(content)
f.close()
输出结果为:
3.2 获取所有城市的公园数据
这次计划把公园的数据存储在MySQL数据库中,所以我们必须先创建一个badiumap数据库,用来存放所有公园爬去的数据。
创建一个数据库,语句为:create database baidumap;
当然也可以使用可视化工具创建数据库与完成一系列操作,如建表等。
然后就是建表了,在baidumap数据库中创建一个city表,用于存放所有城市的公园数据,公园的变量有:city,park,location_lng等等。这些变量就是第一部分测试的返回results中的数据,根据建立即可。
其中,为了避免数据存储重复,公园的详细信息会存储到另一个表中。
我们使用python的mysqlclient库来操作MySQL数据库,在baidumap数据库中建立city表。
# coding=utf-8
import MySQLdb
conn = MySQLdb.connect(host=\'localhost\',user=\'root\',password=\'123456\',port=3306,db=\'baidumap\')
cur=conn.cursor()
sql = """CREATE TABLE city (
id INT NOT NULL AUTO_INCREMENT,
city VARCHAR(200) NOT NULL,
park VARCHAR(200) NOT NULL,
location_lat FLOAT,
location_lng FLOAT,
address VARCHAR(200),
street_id VARCHAR(200),
uid VARCHAR(200),
created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);"""
cur.execute(sql)
cur.close()
conn.commit()
conn.close()
接下来,爬取每个城市的公园数据,保存到city中。
# coding=utf-8
import requests
import json
import MySQLdb
\'\'\'
获取所有城市的公园数据
\'\'\'
conn = MySQLdb.connect(host=\'localhost\',user=\'root\',password=\'123456\',port=3306,db=\'baidumap\',charset="utf-8")
cur=conn.cursor()
# sql = """CREATE TABLE city (
# id INT NOT NULL AUTO_INCREMENT,
# city VARCHAR(200) NOT NULL,
# park VARCHAR(200) NOT NULL,
# location_lat FLOAT,
# location_lng FLOAT,
# address VARCHAR(200),
# street_id VARCHAR(200),
# uid VARCHAR(200),
# created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
# PRIMARY KEY (id)
# );"""
# cur.execute(sql)
# cur.close()
# conn.commit()
# conn.close()
def get_json(region,page_num):
headers = {
\'User-Agent\': \'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.133 Safari/534.16\'
}
params = {
\'query\': \'公园\', #检索关键字
\'region\': region, #检索行政区划区域
\'output\': \'json\', #输出格式为json
\'scope\': \'2\', #检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息
\'page_size\': 20, #单次召回POI数量,默认为10条记录,最大返回20条。
\'page_num\': 0, #分页页码,默认为0,0代表第一页,1代表第二页,以此类推。
\'ak\': \'Kcl9bynY5Icf1yGv6mQPzS7Phhkuw0Pb\'
}
res = requests.get("http://api.map.baidu.com/place/v2/search", params=params, headers=headers)
content = res.text
decodejson = json.loads(content) #将已编码的 JSON 字符串解码为 Python 对象,就是python解码json对象
return decodejson
city_list=[]
with open(\'citys_garden_num.txt\',\'r\',encoding=\'utf-8\') as f:
# print(f.read())
for eachLine in f:
if eachLine !="" and eachLine !="\n":
fields = eachLine.split("\t")
city=fields[0]
city_list.append(city)
#print(city_list)
for eachcity in city_list:
not_last_page = True
page_num = 0
while not_last_page:
decodejson = get_json(eachcity,page_num)
print(eachcity,page_num)
if decodejson[\'results\']:
for eachone in decodejson[\'results\']:
try



