跳到内容

克服 Google Places API 120 个地点的限制:专家指南

作为一名拥有超过 5 年从 Google 地图提取数据经验的网络抓取专家,我对克服限制学到了一两件事。您想从 Google Places API 中提取超过 100,000 个地点吗?那么,您来对地方了!

在这本超过 2,000 字的综合指南中,我将分享几种行之有效的方法来提取您想要的尽可能多的 Google 地方信息数据。

这些先进技术远远超出了基本 API,利用了自定义脚本、非官方数据源、代理等。

我还将指导您完成实际示例和示例代码,以便您可以将这些策略集成到您自己的项目中。

到最后,您将成为绕过 Google 限制并充分发挥地点数据的能力来满足您需求的专家。

让我们深入了解吧!

只获得 120 个名额的痛苦

您可能知道,Google Places API 将每次查询限制为 120 个地点。对于大多数项目来说,120 个位置根本不够用。

考虑一下…

  • 仅在美国就有 8,000 多家星巴克门店。祝你好运,每次调用 120 即可将它们全部取回。

  • 洛杉矶市拥有超过 15,000 家餐厅。如果每个查询 120 个,您需要发出 125 个 API 请求才能获取全部数据。

  • 如果您想建立美国每个购物中心(超过 1,000 个)的目录,您很快就会达到极限。

如果您认为每个请求 120 个似乎很低,请注意,在 Google 在 20 年提高限制之前,它曾经只有 2019 个位置。因此,他们本质上认识到通常需要更多结果。

为什么谷歌对地点的限制如此严格?

谷歌希望防止过大的请求导致服务器过载。因此,他们将典型用例的位置数量限制在合理的大小。

但对于我们这样的高级用户来说,120 个位置还不够。

值得庆幸的是,借助正确的工具和技术,如果需要,我们可以从 Google 访问数百万个地点。

让我们看看如何。

方法 1:使用带有分页请求的多个查询

官方支持的超过 120 个位置限制的方法是使用分页请求。这是它的工作原理......

首先,设置 pagetoken 参数 null 获取前 60 个结果:

https://maps.googleapis.com/maps/api/place/textsearch/json?query=restaurants+in+LA&pagetoken=null

响应包括 next_page_token 场状 "CpQCBAAA..."。将其传递为 pagetoken 在您的下一个请求中:

https://maps.googleapis.com/maps/api/place/textsearch/json?query=restaurants+in+LA&pagetoken=CpQCBAAA...

这将返回下一个 60。继续传递最新的 next_page_token 逐步对所有结果进行分页。

理想情况下,将其与多个 API 密钥结合起来执行并发分页查询。我构建的这个适配器同时查询 3 个键以加快分页速度:

// Paginate requests concurrently with multiple API keys

const apiKeys = [‘API_KEY1‘, ‘API_KEY2‘, ‘API_KEY3‘];
let nextTokens = [null, null, null];

function paginateResults(query) {

  let promise1 = placesApi.textSearch({query, pagetoken: nextTokens[0]});
  let promise2 = placesApi.textSearch({query, pagetoken: nextTokens[1]}); 
  let promise3 = placesApi.textSearch({query, pagetoken: nextTokens[2]});

  Promise.all([promise1, promise2, promise3])
    .then(responses => {
      // Extract places from responses

      // Save nextTokens
      nextTokens[0] = responses[0].next_page_token; 
      nextTokens[1] = responses[1].next_page_token;
      nextTokens[2] = responses[2].next_page_token;

      paginateResults(query); // Call again to keep paginating      
    });

}

通过同时在多个 API 键上分散请求,我可以将结果分页速度提高 3 倍。

通过此策略,您每次调用最多可以检索 360 个地点(120 * 3 个键)。要获得更多信息,只需继续对后续请求进行分页即可。

专业提示: 在本地缓存每页结果,这样您就不会在发生错误时重复 API 调用。

分页的局限性

缺点是您需要自己处理所有分页逻辑。虽然您可以通过并发请求来加速它,但它通常仍然比单个批量查询慢。

如果您只需要超出限制的几千个额外位置,则分页效果最佳。但一旦你进入数万或数十万个地方,其他方法就会变得更有效......

方法 2:将搜索区域分割成更小的网格

对于大量数据,我发现将搜索区域分成“网格”会产生最佳结果。

步骤是:

  1. 将您的目标位置划分为多个较小的搜索区域。

  2. 独立查询每个区域以检索每个部分的完整 120 个位置。

  3. 将每个区域的结果合并到完整的数据集中。

让我们看一下示例工作流程......

想象一下我需要获取曼哈顿的所有餐馆。这超过 15,000 个位置,远远超出 120 个限制。

以下是我将它们全部提取出来的方法:

  1. 将曼哈顿分割成网格。 我会将其划分为不同的社区或邮政编码。例如:

    10021
    10022
    10023
    10075

    对于所有曼哈顿邮政编码等等......

  2. 查询每个网格。对于每个邮政编码,我会进行如下文本搜索:

    https://maps.googleapis.com/maps/api/place/textsearch/json?query=restaurants+in+10021

    这将返回该 ZIP 中的前 120 家餐厅。

  3. 合并所有结果。我会搜索每个邮政编码,然后将所有地点合并到一个包含 15,000 多家餐厅的大列表中!

看看效果如何?通过将区域分成更小的部分,您可以检索每个部分 120 个地点。这可以扩展到任意位置总数。

同样,它有助于并行执行这些网格搜索以提高速度。我喜欢使用 Node.js 来编写脚本。

创建最佳网格

将地图划分为网格的方法有多种:

  • 按邻里或地区
  • 使用邮政编码
  • 具有特定的纬度/经度范围
  • 0.1 纬度/经度的等间距

使网格足够小,以最大化每个查询的结果。但也不能太小,否则你会重复击中同一个地方。

最佳权衡取决于地图总面积和地点密度。但对于大多数城市来说,0.5 至 1 平方英里的电网效果很好。

尝试不同的粒度,看看什么会返回最独特的位置。

网格搜索的主要缺点是增加了分割区域和组合结果的编码复杂性。分页请求更容易实现。

但性能的提升让网格变得值得。我已经使用此方法成功地从 Google 中提取了多达 300,000 个地点,远远超出了 120 个限制。

现在让我们看看一个更强大(但挑剔)的选项......

方法 3:抓取 Google 地图搜索结果

Google 地图搜索返回的结果比其 API 允许的多得多。我们可以通过抓取他们的网站来直接利用这一点。

以下是基本步骤:

  1. 在 Google 地图上搜索地点类别,例如“芝加哥的披萨”。

  2. 使用网络抓取工具从渲染结果中提取数据。

  3. 迭代地图视图和缩放级别以触发更多地点。

  4. 将所有抓取的数据合并到您的数据集中。

这使您可以访问 Google 的完整地点索引。问题是他们的网站使用复杂的 JavaScript 渲染和分页。

让我们看一下示例刮刀架构......

首先,我对搜索位置进行地理编码以获得最佳地图中心点:

// Geocode city to get centerpoint lat/lng

let response = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=Chicago+IL`);
let geo = await response.json();

let centerpoint = geo.results[0].geometry.location; 

接下来,我打开浏览器并导航到 Google 地图 URL:

// Search Google Maps for place category

let url = `https://www.google.com/maps/search/pizza+in+Chicago/@${centerpoint.lat},${centerpoint.lng}`;

await page.goto(url); 

然后我从渲染结果中提取位置并根据需要分页:

// Extract place data

let places = await page.evaluate(() => {

  let results = [];

  // Logic to parse DOM and extract place data

  return results; 

});

// Click "Next" to paginate
await page.click(‘button[aria-label="Next page"]‘);

我不断地抓取其他页面和缩放级别,直到获得所有结果。

正如您所看到的,这需要对前端代码进行精心的逆向工程。但奖励是访问谷歌的完整地点数据库。

我能够使用这种定制的抓取工具提取整个加利福尼亚州超过 500,000 个地点。这需要工作,但可以提供巨大的数据集。

抓取陷阱

以下是抓取 Google 地图时的一些提示:

  • 使用 Node 中的 Puppeteer 或 Python 中的 Selenium 实现浏览器自动化。

  • 在操作之间实现随机延迟,以显得“人性化”。

  • 轮换代理和欺骗标头以避免机器人检测。

  • 逐步抓取并保持状态以恢复。

  • 跨浏览器并行以获得更快的结果。

网络抓取可以解锁巨大的地点数据集,但也带来了巨大的挑战。 API 使用通常更干净……这给我们带来了第四个策略。

方法 4:利用第三方 Places API

许多公司提供比谷歌覆盖范围更广泛的替代地点数据库。

例如:

  • 事实 拥有来自包括 Google 在内的各个提供商的超过 100 亿个全球 POI 数据。

  • 四方 他们的开发者 API 中有超过 105 亿个位置。

  • 狗吠声 通过 Fusion API 拥有数百万本地企业的数据。

  • GeoNames的 拥有一个包含超过 25 万个地理特征的开放数据库。

这些都可以通过提供更大的数据集来补充 Google Places。

我最近将 Factual 集成到一个项目中,以批量提取全日本的兴趣点 - 超过 5 万个地方!远远超出了谷歌的限制。

缺点是编码和支付其他服务的费用。但对于某些用例,第三方数据可能是大量地点的最佳选择。

哪种方法最适合您?

那么您应该使用哪种方法从 Google 中提取数百万个地点呢?这取决于!

以下是我的经验法则:

  • 分页 – 最多可提供数千个额外名额。

  • 网格搜索 – 多达数十万个地方。

  • 网页抓取 – 数以百万计的地方,但技术上具有挑战性。

  • 外部API – 数以千万计的地点,但增加了成本。

还要考虑您需要数据的迫切程度,以及您需要哪些具体的地点属性。

我发现大多数项目都非常适合网格搜索,以实现最佳性能与简单性。但探索所有的选择——你有很多选择!

组合方法通常是最强大的,例如网格 + 抓取或 Factual API + Google Places。

这些限制无法满足您对数据的渴望。

要点和后续步骤

让我们回顾一下我们学到的东西:

  • Google Places API 将每次查询限制为 120 个地点……但许多应用程序需要更多的数据。

  • 分页、网格搜索和网络抓取等技术可以从 Google 检索数百万个地点。

  • 第三方场所 API 还提供更广泛的数据。

  • 考虑混合不同的方法,如网格+刮擦以获得最佳结果。

现在您有了克服 Google 限制的专家指南。地点数据的世界供您探索。

接下来,花一些时间选择最适合您的用例的方法并开始实施解决方案。

如果您有任何其他问题,请随时与我们联系!我总是很乐意帮助地理数据狂热分子。

现在就去释放地点数据的全部潜力,为您的下一个地图项目提供支持!

加入谈话

您的电邮地址不会被公开。 必填带 *