Python 调用 API 爬取百度 POI 数据

发布时间:2020-03-06 阅读 3925

Stata 连享会   主页 || 视频 || 推文

温馨提示: 定期 清理浏览器缓存,可以获得最佳浏览体验。

课程详情 https://gitee.com/arlionn/Course   |   lianxh.cn

课程主页 https://gitee.com/arlionn/Course

作者:孙斯嘉 (810963623@qq.com)


POI 是“ Point of Interest ”的缩写,中文可以翻译为“兴趣点”。在地理信息系统中,一个 POI 可以是一栋房子、一个商铺、一个邮筒、一个公交站等。
POI (兴趣点) 数据分类众多,包括美食、购物、旅游景点、政府机构、交通设施等地理信息数据。传统的地理信息采集方法需要地图测绘人员采用精密的测绘仪器去获取一个兴趣点的经纬度,然后再标记下来,是一个非常费时费事的工作,而利用 Python 可以方便的批量调用 API 即 Application Programming Interface 应用程序接口,抓取数据、返回兴趣点的名称、经纬度坐标等数据。

Python 调用 API 爬取百度 POI 数据可以应用到产业集聚、空间溢出效应、城市与交通规划、城市经济学等方面。我们举几个简单的例子。例如,在经济学研究中,我们想要探究城市规模、人口结构对于不可贸易品多样性水平的影响状况,以菜品多样性作为评价不可贸易品多样性的指标,这个时候我们就需要利用调用百度 API 爬取美食餐饮类的 poi 信息作为研究的基础性数据。推文介绍详情见 香樟经济学术圈。 再比如说,我们想要研究长三角某类企业的集聚效益以及这些企业配套的上下游企业、相关服务业等,我们首先要知道这个地区这类产业链到底有多少家企业,企业的名称,地理位置及分布。只有获得了这些基础数据,才能进行下一步的分析。再比如说,邮政银行想在西安雁塔区开设新的服务网点,需要从现有网点分布以及雁塔区客户分布情况进行考虑,这个时候我们就可以利用 Python 调用 API 爬取百度 POI 来对网点坐标信息进行搜索。

本文利用百度地图 API ,实现批量抓取餐饮类 POI 数据。其他类型 POI 数据以此类推。

爬取 POI 数据程序代码

首先我们要导入程序所需要的库,构建所要抓取的根 url ,根据百度开放平台中的服务文档的说明确定 url 的内容,可点击 百度服务平台地点检索服务介绍 查询。接下来我们要确定存放解析地址出来的坐标文件的工作目录。 在本例中,我们使用圆形区域进行检索,这样我们就需要先确定检索区域范围中一些圆心点的坐标。选取圆心点和半径大小时可根据获取数据的需求,覆盖到感兴趣的所有区域。


from urllib.request import urlopen #调用urllib.request库里面的urlopen命令,向网页发送请求并打开网页
import json #调用库,json是一种便于解析的格式
import time #调用库,time是时间,防止访问次数过于频繁被系统后台禁止
from urllib.parse import quote #调用urllib.parse库里面的查询命令


# 构建抓取的根URL
baseURL = 'http://api.map.baidu.com/place/v2/search?output=json&' #抓取网页的地址
ak = '********************' #在百度地图中申请的ak
query = quote('美食') #爬取的POI类型是美食,quote是把中文转化成url的格式
scope = '2' #返回内容的详细程度,2是比较详尽的意思

# 确定工作目录
path = 'E://pachong//Poi//' #爬取坐标文件所在的路径,Windows系统的分隔符为\\,mac系统的分隔符是/
poiList = [] #创建一个poi列表存储爬出来的数据

之后我们定义一个fetch小程序用于抓取 url 链接,接下来读取检索点(圆心点)的坐标文件,生成抓取列表。循环所生成的 coordinates 列表,对列表中的每一个 coordinate 进行 fetch ,并存储所得数据 。
:坐标默认为百度地图的坐标类型 BD09II ,否则使用其他坐标系统时(例如 WGS84 ),检索点会有偏移。

下一步进行实际的抓取动作,根据 BaseURL ,构建抓取所用 URL,生成抓取结果并将结果赋给 response , 同时确认此次调用返回数据的页数。

我们在编写程序之前,需要手动单次进行 POI 信息抓取,访问相应 url 后,我们发现 results 的格式是列表,因此我们在编写程序时,要先对列表里的字典进行提取,再提取字典中的信息。对应每个坐标点,循环提取每页抓取到的 poi 信息,将提取到的结果赋给 contents 。 嵌套在上一个循环内,开始循环 contents 列表中的所需信息,对 contents 列表中的信息进行进一步提取,即 poi 的名字、经纬度和 uid。


# 定义抓取动作
# 分四步:访问-读取-解析-休眠
def fetch(url): #定义抓取的参数是url
    feedback = urlopen(url) #使用urlopen命令进行访问url
    data = feedback.read() #读取url
    response = json.loads(data) #对返回结果进行解析
    time.sleep(2) #暂停2秒,防止访问次数过于频繁被系统后台禁止
    return response #返回抓取结果

# 读取坐标文件,生成抓取队列
coordinateFile = open(path + 'XianChAnBaiduCoord0-1066.txt', 'r') #打开坐标文件即经纬度坐标文件,r是读取的意思
outputFile = path + '11.txt' #定义输出的POI文件,BaiduPOI_0128自行命名

coordinates = coordinateFile.readlines() #读取坐标文件中的每一行

# 循环coordinates,对每一个coordinates进行fetch,并存储所得数据

# for coord in coordinates:
#      fetch
#      get data
#      write

# for coord in coordinates:
for c in range(0,20): #循环coordinates中的每一个坐标
   
    coord = coordinates[c].split(',') #提取坐标
    lat = coord[2].strip() #纬度,0对应坐标文件中的第1列,1对应坐标文件中的第2列,2对应坐标文件中的第3列
    lng = coord[1].strip() #经度
    locator = coord[0] #定位我们抓取到了第几个坐标
    print ('This is ' + str(locator) + ' of ' + str(len(coordinates))) #在屏幕上打印抓取到了第几个坐标
    
    # 抓取动作
    # 根据BaseURL,生成抓取所用URL
    initialURL = baseURL + 'ak=' + ak + '&query=' + query + '&scope=' + scope + \
                '&location=' + str(lat) + ',' + str(lng) + '&radius=800' + '&page_size=20&page_num=0'
    #ak,query,scope已经介绍过,不再赘述,location是坐标即经纬度,radius=800即抓取半径是800米,&page_size=20&page_num=0即每页返回20条数据,超过20条数据进行翻页
    
    # 确认此次调用返回数据的页数
    response = fetch(initialURL) #返回抓取结果
    totalNum = response['total'] #返回抓取结果数据的数量
    numPages = int(totalNum/20)+1 #计算页数取整后+1
    
    print (str(numPages) + ' in Total') #在屏幕上打印页数
    
    # 开始翻页
    for i in range(0, numPages+1): #循环每页
        print ('Start to fetch page ' + str(i)) #在屏幕上打印抓取到第几页
        URL = baseURL + 'ak=' + ak + '&query=' + query + '&scope=' + scope + '&location=' + \
              str(lat) + ',' + str(lng) + '&radius=800' + '&page_size=20&page_num=' + str(i)
        
        response = fetch(URL) #返回抓取url的结果
        contents = response['results'] #将返回的结果放在列表contents中
        print(contents) #contents是列表的格式
        
        # 开始循环抓取列表中的所需信息
        for content in contents: #content是列表中的内容,是字典格式
            print(content)
            name = content['name'] #由于抓取到的数据很多,我们进行进一步的提取;提取名字
            lat = content['location']['lat'] #提取纬度
            lng = content['location']['lng'] #提取经度
            uid = content['uid'] #提取uid
                        
            poiInfo = name+','+str(lat)+','+str(lng)+','+str(uid) #定义输出的结果为名字+纬度+经度+uid
            print (name) #输出美食点的名字
            poiList.append(poiInfo) #提取到一个poiInfo便加到poiList列表中

最后生成一个 txt 文件,输出所有抓取结果。


with open(outputFile, 'a') as f:
    for poiInfo in poiList:
        f.write(poiInfo.encode('utf-8') + '\n')
        f.close()
        f = open(outputFile, 'a')

小结

本程序主要通过构建一个fetch小程序抓取网页中的 url 链接,并对输入的坐标文件中的每一个坐标进行循环、提取目标参数,最终生成 poi 数据文件,完成整个调用 API 爬取百度 POI 数据的过程。

在百度地图开放平台中,我们可以获得美食、购物、旅游景点、交通设施等各类 POI 数据。每个类型的 POI 数据对应着一个关键词。例如,我们想爬取公司企业类的 poi 数据,则只需要在上述程序中,将 query = quote ('餐饮') 中 餐饮 改成 公司 即可。其他类型的 POI 数据以此类推。每个类型的关键词在百度开放平台网页中有具体说明,可点击 百度地图开放平台 poi 分类 进行查看。

相关课程

连享会-直播课 上线了!
http://lianxh.duanshu.com

免费公开课:


课程一览

支持回看,所有课程可以随时购买观看。

专题 嘉宾 直播/回看视频
最新专题 DSGE, 因果推断, 空间计量等
Stata数据清洗 游万海 直播, 2 小时,已上线
研究设计 连玉君 我的特斯拉-实证研究设计-幻灯片-
面板模型 连玉君 动态面板模型-幻灯片-
面板模型 连玉君 直击面板数据模型 [免费公开课,2小时]

Note: 部分课程的资料,PPT 等可以前往 连享会-直播课 主页查看,下载。


关于我们

  • Stata连享会 由中山大学连玉君老师团队创办,定期分享实证分析经验。直播间 有很多视频课程,可以随时观看。
  • 连享会-主页知乎专栏,300+ 推文,实证分析不再抓狂。
  • 公众号推文分类: 计量专题 | 分类推文 | 资源工具。推文分成 内生性 | 空间计量 | 时序面板 | 结果输出 | 交乘调节 五类,主流方法介绍一目了然:DID, RDD, IV, GMM, FE, Probit 等。
  • 公众号关键词搜索/回复 功能已经上线。大家可以在公众号左下角点击键盘图标,输入简要关键词,以便快速呈现历史推文,获取工具软件和数据下载。常见关键词:课程, 直播, 视频, 客服, 模型设定, 研究设计, stata, plus, 绘图, 编程, 面板, 论文重现, 可视化, RDD, DID, PSM, 合成控制法

连享会主页  lianxh.cn
连享会主页 lianxh.cn

连享会小程序:扫一扫,看推文,看视频……

扫码加入连享会微信群,提问交流更方便

✏ 连享会学习群-常见问题解答汇总:
https://gitee.com/arlionn/WD