爬取百度地图 POI 数据

爬取百度地图 POI 数据

初衷

老婆大人想知道金华地区的早教、培训机构相关的情况,老办法,爬起来。

百度地图api的限制

webapi/guide/webservice-placeapi – Wiki

查找了下大家获取百度POI数据的方法,知道了百度地图的地点检索api做了几个限制:

  • 非认证个人开发者2k每日请求量,认证后个人开发者3w日请求量
  • 检索接口最大返回670条结果 地点检索api分两类接口,一类是区域检索,第二类是详情检索,也就是说,如果我需要对每个地点去做详情检索,那就算3w的日请求量也远远不够了。好在我看区域检索接口内也可以返回较为详细的内容,基本够用。还有一个坑是区域检索接口是分页返回的,每页最多20条,所以这会消耗请求量。这里不考虑这些限制,大不了多跑几天。

实施方法

由于检索接口一次最多能返回670条数据,所以有个策略就是使用矩形检索接口,将矩形区域缩小到一定程度后,该区域的返回条目数不超过670条就可以,当然也不要太小,太小浪费请求量。

我先用一个大矩形划定我关心的区域,然后找到左上角和右下角的坐标:(这个可以手动从百度地图web站上获取到) 左下角,石门村:13312800.93,3357744.44 右上角,横山村:13334828.53,3373640.97

我们先设计10*10个小矩形来扫描。为了第二天继续爬取,每次移动记录当前矩形的位置。为了观察是否可能由于矩形过小导致数据丢失,记录每个矩形的获取数目,当等于670条时,可以重新细分扫描该类矩形区域。

注意 :上面拿到的坐标是百度地图米制坐标,需要转换成百度经纬度坐标才能用于检索api,转换api地址:webapi/guide/changeposition – Wiki

编码

由于是纯api爬取,就不上框架了。

#coding: utf-8
import requests
import json
import time


""" 查询关键字: """
FileKey = 'preclass'
KeyWord = u"早教$培训"

""" 关注区域的左下角和右上角百度地图坐标(经纬度) """
BigRect = {
    'left': {
        'x': 119.58962425017401,
        'y': 29.02371358317696
    },
    'right': {
        'x': 119.787499394624553,
        'y': 29.149153586357146
    }
}

""" 定义细分窗口的数量,横向X * 纵向Y """
WindowSize = {
    'xNum': 10.0,
    'yNum': 10.0
}


def getBaiduApiAk():
    """ 获取配置文件中百度apikey: { "baiduak":"xx"} :return: str """
    with open("./config.json", "r") as f:
        config = json.load(f)
        return config["baiduak"]

def getSmallRect(bigRect, windowSize, windowIndex):
    """ 获取小矩形的左上角和右下角坐标字符串(百度坐标系) :param bigRect: 关注区域坐标信息 :param windowSize: 细分窗口数量信息 :param windowIndex: Z型扫描的小矩形索引号 :return: lat,lng,lat,lng """
    offset_x = (bigRect['right']['x'] - bigRect['left']['x'])/windowSize['xNum']
    offset_y = (bigRect['right']['y'] - bigRect['left']['y'])/windowSize['yNum']
    left_x = bigRect['left']['x'] + offset_x * (windowIndex % windowSize['xNum'])
    left_y = bigRect['left']['y'] + offset_y * (windowIndex // windowSize['yNum'])
    right_x = (left_x + offset_x)
    right_y = (left_y + offset_y)
    return str(left_y) + ',' + str(left_x) + ',' + str(right_y) + ',' + str(right_x)


def requestBaiduApi(keyWords, smallRect, baiduAk, index, fileKey):
    today = time.strftime("%Y-%m-%d")
    pageNum = 0
    logfile = open("./log/" + fileKey + "-" + today + ".log", 'a+', encoding='utf-8')
    file = open("./result/" + fileKey + "-" + today + ".txt", 'a+', encoding='utf-8')
    # print('-------------')
    # print(index)
    while True:
        try:
            URL = "http://api.map.baidu.com/place/v2/search?query=" + keyWords + \
                "&bounds=" + smallRect + \
                "&output=json" +  \
                "&ak=" + baiduAk + \
                "&scope=2" + \
                "&page_size=20" + \
                "&page_num=" + str(pageNum)
            # print(pageNum)
            # print(URL)
            resp = requests.get(URL)
            res = json.loads(resp.text)
            # print(resp.text.strip())
            if len(res['results']) == 0:
                logfile.writelines(time.strftime("%Y%m%d%H%M%S") + " stop " + str(index) + " " + smallRect + " " + str(pageNum) + '\n')
                break
            else:
                for r in res['results']:
                    # print(r)
                    file.writelines(str(r).strip() + '\n')
            pageNum += 1
            time.sleep(1)
        except:
            print("except")
            logfile.writelines(time.strftime("%Y%m%d%H%M%S") + " except "  + str(index) + " " + smallRect + " " + str(pageNum) + '\n')
            break


def main():
    baiduAk = getBaiduApiAk()
    for index in range(int(WindowSize['xNum'] * WindowSize['yNum'])):
        smallRect = getSmallRect(BigRect, WindowSize, index)
        requestBaiduApi(keyWords=KeyWord, smallRect=smallRect, baiduAk=baiduAk, index=index, fileKey=FileKey)
        time.sleep(1)


if __name__ == '__main__':
    main()

复制代码

结果

发现我的需求,只要10*10就已经够用了。其实可以通过配置变量,查询想要查询的任何内容了。哔哔哔。。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/101456.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java将字符串转换为json对象的方法_java jsonobject转string

    java将字符串转换为json对象的方法_java jsonobject转string在与服务器交互的时候,我们往往会使用json字符串,今天的例子是java对象转化为字符串,代码如下protectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Persionp1=newPersion(…

    2022年9月21日
    2
  • java byte数组拷贝_异或校验原理

    java byte数组拷贝_异或校验原理其实在以前没接触这些内容的时候,脸上是懵逼的表情,完全不明白异或是为了干什么。其实用简单的语言来说,接收数据的异或校验相当于解密,发送时候的校验位相当于加密;官方解释是:其他数据信息传递中为保证数据传递正确可靠,在数据帧中常加载异或校验位(个人理解怕传输过程中出现数据丢失损坏的情况,所以加校验保证了数据的准确性)言归正传java中怎么异或校验1、发送数据byte[]rece=newbyte[6];rece[0]=0x55;

    2022年9月28日
    2
  • matlab画折线图,标记指定点「建议收藏」

    matlab画折线图,标记指定点「建议收藏」首先,找到你需要标注的点。比如说你有x、y两个列向量构成一条曲线。现在要找最大值点那么用p=find(y=max(y)),那么坐标(x(p),y(p))就是你要找的点咯。2第二步如何标记。我介绍两总方法来标记这个点,但是总体上可以归结为一种方法。(1)利用text(x(p),y(p),’o’,’color’,’g’));这里o表示标注的形状,也可以用*、^等比较好看的符号哟。’g’表示的是颜色。(…

    2022年5月20日
    54
  • finalize方法_final与finalize区别

    finalize方法_final与finalize区别当对象没有引用指向时,虚拟机会按照一定的垃圾回收机制算法来调用finalize方法将该对象回收,并不是只要没有引用对象就会被回收。因此,可以调用System.gc()方法来主动调用垃圾回收机制,但也并不能保证一定能成功。在调用时,程序并不会阻塞在此处,而是会继续向下执行。默认的object类中的finalize方法是不作其余处理的。可以重写finalize方法来实现自己想要的资源释放操作,比如数据库连接等。…

    2022年9月19日
    3
  • Hadoop-2.2.0中国文献——MapReduce 下一代 —配置单节点集群

    Hadoop-2.2.0中国文献——MapReduce 下一代 —配置单节点集群

    2022年1月17日
    41
  • 手机游戏开发平台有哪些

    手机游戏开发平台有哪些随着近年来智能手机市场的快速发展,它所提供的丰富多彩的应用不仅开启了一个新的通讯时代,更给人们带来了一种集沟通、办公、娱乐为一体的新的生活方式。在满足人们娱乐方面,手机游戏发挥了举足轻重的作用。手机游戏开发一直以来是手机应用市场盈利份额最重的一部分,随着4G网络的逐步普及,手机应用也慢慢融入到我们生活中成为必需品。Android、iPhone、WindowsPhone和黑莓平台都非常适合独立和小…

    2022年4月28日
    83

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号