🍔获取中国哪些县城有麦当劳

type
status
date
slug
summary
tags
category
icon
password
author
标签
第三方接入
 

1. 题设:全国哪些区县有麦当劳?

在制作明日故乡中,我需要的一个数据是全国哪些区县有麦当劳。因为在我看来,麦当劳代表着一个区域的城市化进程。
很显然,这个世界上并不存在一个现成的数据集里包含全国的麦当劳点位。但是,我们都知道无论是高德、百度还是腾讯地图里都能轻松查询到附近的麦当劳。这意味着,我们应该可以从这些地图服务中,判断每个区县是否有麦当劳。
本篇教程即明日故乡实际这一数据集的制作过程,你能够通过本篇教程掌握数据表操作与第三方 API 调用的一些技巧。

2. 准备工作:

准备行政区划列表

首先,我们需要准备一个 csv 文件,这个文件里要包含中国所有县级行政区划的行政代码,因为我们后面无论是使用百度地图还是高德地图的 API ,都需要这个列表来精准定位每一座县城。这个代码你可以网上自己找,我这里也会提供一个现成的:
notion image
notion image
比较简单的方法,是在飞书文档里建立一个多维表格,然后在左下角选择 新建>从其他数据源同步>组织共享数据源>中国行政区划汇总数据。这样,你的多维表格里就会多一个来自飞书官方的行政区划表,你只需要将这个表导出为 CSV 就可以了。
但导出的内容中,包含了一些杂项数据,我们需要在 Excel 里删除一下。
notion image
然后,将该 csv 文件,复制到 n8n 的永久化存储目录。如果你对这个目录很陌生,那你需要回顾一下这里

申请地图 API

作为普通用户,我们想要知道哪里有麦当劳,打开地图 App 搜一下就行了。但 n8n 是个程序,程序就要走程序的通路,也就是 API。
并且,地图服务也不会再认为你是普通用户,产品也就基本不能免费给你用了。API 一般是要单独付费的,有一定的免费额度。
我横向对比了百度、高德和腾讯地图的 API,发现尽管百度、高德在淘宝上有日租账户比较便宜(50 元一天),但腾讯地图的搜索 API 免费额度高达 200 次每天。因此,本篇将以腾讯地图 API 为例展开教学,当然你也可以用百度地图、高德地图的 API 实现完全相同的效果,只是需要根据这两个地图的官方 API 文档,调整第三步的参数。
  1. 注册腾讯位置服务:
  1. 注册后,根据提示进行个人开发者实名认证,获得免费额度。
  1. 应用管理>我的应用 中随意创建一个应用。
  1. 在新创建的应用中,添加一个 Key,如果你是在云服务器上部署的 n8n,建议开启域名白名单验证,防止你的 Key 被别人偷走:
    1. notion image
当你看到这个界面的时候,你就成功获得了腾讯地图的 Key,可以开始正式制作 Workflow 了:
notion image
Key 应当是一个由 6 组 5 个字符组合而成,用横杠连接的长字符串。我们在 Workflow 的第三步要用到。

3. 正式步骤:

完整 Workflow 概览
完整 Workflow 概览
完整示例 Workflow 下载:
行政区划列表文件:

第一步:读取文件

notion image
在 Trigger 之后,添加一个 Read/Write Files from Disk 节点。
参数设置如下:
Operation - Read File(s) From Disk
File(s) Selector - ./n8ndata/district-code.csv
这一步没什么好说的,就是把行政区划编号读到 n8n 的工作流中来,如果你不知道什么是行政区划编号,那你一定是跳过了本文的准备工作部分,快回去看吧。
如果你不知道怎么把文件放到 ./n8ndata/ 这个目录去,那你一定是跳过了我们的部署教程,你可以在这里回顾一下:。

第二步:文件转数据

notion image
添加一个 Extract from File 节点。
参数设置如下:
Operation - 选择 Extract Form CSV
Input Binary Field - 保持与上一步传进来的文件数据一致,默认的话是 data。
这一步的作用,是将读取到 n8n 里的 CSV 文件转化为后续可以使用的数据并写进内存。只有这样,我们才能在后续的步骤中以变量的形式引用这些行政区划编号。
如果顺利的话,你就能在 Output 节点看到你 CSV 里的数据了。

第三步:通过 API 获取麦当劳信息

添加一个 HTTP Request 节点。
notion image
💡
本节点的设置,需要根据不同地图 API 进行调整,本教程使用的是腾讯地图。你可以自行根据百度地图高德地图的文档修改配置。
参数设置如下:
参数名
参数值
Method
GET
URL
Authentication
None
Send Query Parameters
打开
Specify Query Parameters
Using Fields Below
Query Parameters
添加三个子参数,分别为: key - 你的腾讯地图开发者 Key keyword - 麦当劳 boundary - region({{ $json.行政区划代码 }},2)
Options - Batching
Items per Batch - 5 Batch Interval (ms) - 1000
这一步的主要作用,是利用 HTTP Request 这个节点,从腾讯地图 API 在指定范围内搜索“麦当劳”,并将这个动作重复上千次(也就是每个区县搜一下)。
如果你不理解 HTTP Request 是如何工作的,你可以先去读一下这篇教程:
我们来详细解释一下每个参数的作用:
首先是 Method ,这个是指你想让 HTTP Request 发出什么样的请求,根据腾讯地图官方的文档,这里要使用 Get。
URL,这个参数指定了 HTTP Request 向哪里发出请求,腾讯地图使用不同的地址(端点、Endpoint)来区分 API 的功能。我们需要的是“在指定区域搜索”,也就是 WebService API 里地点搜索的 URL:https://apis.map.qq.com/ws/place/v1/search
Authentication,这个参数是用来权鉴的,也就是用来辨认是谁发起的请求。但腾讯地图使用的是静态 key 的方式进行验证,所以这里我们选择 none。
Send Query Parameters,这个参数的作用是是否开启 HTTP Request 发送查询参数的功能,在大多数 API 请求的使用中我们都需要发送查询参数,所以这里选是。只有打开了这个开关,参数面板下方的 Query Parameters 才会出现。
Query Parameters ,这个部分就是用来添加对 API 发起查询到底是查什么的参数。比如在这个案例中,我们添加了三个查询参数,他们分别是:
参数名
参数值
说明
key
你的腾讯地图开发者 Key
腾讯地图根据用量扣谁的费
keyword
麦当劳
你想在腾讯地图里查什么
boundary
region({{ $json.行政区划代码 }},2)
设置查询范围。
在腾讯地图的官方文档boundary 参数,定义了多种划定范围的方法:
notion image
通过解读,我们发现使用行政区划限制并不自动扩大范围,是最适合的方式。
比如,如果我们想在北京搜索麦当劳,我们就应该用 region(北京,2) 。那么,我们的目的是为了给每个区县搜索一次,所以就要使用上游的行政区划代码变量{{ $json.行政区划代码 }}。稍微叠加一下,实例中正确的查询方法应为:region({{ $json.行政区划代码 }},2)
Options - Batching,在使用第三方 API 的时候,HTTP Request 可选项里的 Batching(分批)十分管用。因为第三方 API 为了降低服务器负担,会为不同等级的用户设置可以访问的频率。
就比如说,我们一共要进行全国 2000 多个区县的搜索,腾讯地图肯定是不允许的,不仅不允许,如果速度太快可能还会被他们封禁账号。因此,我们要通过分批功能将访问速度严格控制在对方 API 允许的范围内。
在这里,我选择了每次只搜 5 个区县,然后等待 1000 毫秒。也就是 Items per Batch 为 5 ,Batch Interval (ms) 为 1000。
💡非常有用的提示:节省 API 额度的方法!
在调用第三方 API 时,由于 API 往往有额度限制(比如每天或每月多少次),你可以先将数据在上游缩减进行测试。比如在本例中,腾讯地图的 API 额度只有每天 200 次调用,为了顺利调试,我们可以将最原始的行政区划代码 CSV 文件缩减到 10 条数据进行测试,等 Workflow 构建完成跑通,再使用完整数据。
另外,调用第三方 API 的节点一旦测通,为了防止后续测试时反复调用,你可以进行两个操作:
  1. 在 HTTP Request 下游一个节点,用 Output 面板里的 Pin Data 功能将本次测试数据固定,这样在测试后续节点时,无论 API 返回什么样的结果,节点本身输出给下游的数据都是已固定的那次数据:
    1. notion image
  1. 在编辑器页面里,将鼠标移动到 HTTP Request 节点上,点击开关小按钮将节点 Deactive。这样,在后续的运行中,该节点将不再实际向第三方 API 发送请求:
    1. notion image
经过这两步之后,你的 HTTP Request 节点将被短路,并且在后续的运行中每次都向后方输出你固定过的测试数据,从而减少 API 额度的浪费。值得注意的是,第一步固定数据,要固定在 HTTP Request 下游那个节点,因为 HTTP Request 本身被 Deactived 之后,将不再输出任何内容,包括 Pin Data。
另外,在 Workflow 正式运行的时候,要 Unpin 数据,重新激活节点哦~

第四步:合并数据

添加一个 Merge 节点,
notion image
Input 1 连接上游 HTTP Request。
Input 2 连接上上游的 Extract from File。
notion image
参数设置如下:
Mode - Combine
Combination Mode - Merge By Position
解释一下,在上一步中,我们从腾讯地图端获取了麦当劳数据,它的数据格式型如:
展开查看代码
这是一个多层级的 json,我们发现每一次请求,都返回了 status、message、request_id、count 和 data 五个一级 item。其中 data 包含了该次搜索的详细结果,里面列出了具体有哪些麦当劳门店,以及这些门店的一些 POI 信息。
考虑到我们的课题是某个区/县是否有麦当劳,那么我们其实所需要保留的只是 count 这个 item,也就是返回结果的计数(有几个麦当劳)。
为了让 count 数据和原始数据表中的行政区划对应,我们需要先将刚获得的数据和原始数据表合并。在这里,因为我们是通过原始数据表分行发起的请求(每个区/县一次),所以我们可以认为,腾讯地图返回的数据与原始数据之间行对行是一致的,也因此 Combination Mode 选择最简单的 Merge By Position(通过位置合并)就行了。
测试运行后,我们会发现在 HTTP Request 获得的数据表的右方,出现了原始数据表中的三列也就是行政区划代码省份、直辖市、自治区城市区县。就像是我们在 Excel 中把一个表中的四列,贴到了另外一个表的末尾一样。

第五步:整理数据

添加一个 Edit Fields 节点。
notion image
参数设置如下:
Mode - Manual Mapping
Fields to Set - 从 Input 面板拖拽五个我们想要的字段到 Fields 里:
Name
Value
行政区划代码
{{ $json['行政区划代码'] }}
省份、直辖市、自治区
{{ $json['省份、直辖市、自治区'] }}
城市
{{ $json['城市'] }}
区县
{{ $json['区县'] }}
count
{{ $json.count }}
Name 是可以自己定义的,我们可以将 count 修改为“是否有麦当劳?”。但 count 值本身是麦当劳的数量,并非“是”或“否”,我们可以单独修改这一字段的 Value。根据 n8n 变量编辑器的提示,我们可以通过 .toBoolean() 这个方法来实现。
notion image
因此,修改后的 Fileds 应该是:
Name
Value
行政区划代码
{{ $json['行政区划代码'] }}
省份、直辖市、自治区
{{ $json['省份、直辖市、自治区'] }}
城市
{{ $json['城市'] }}
区县
{{ $json['区县'] }}
麦当劳
{{ $json.count.toBoolean }}
通过查看 OutPut 面板,我们发现新的数据表已经生成,它看起来十分简洁,一眼就能看出哪个区县有麦当劳,哪个区县没有麦当劳。我们会发现,麦当劳那一列不再是麦当劳门店的实际数字,而是 1 或 0。这是由于 Boolean 是一种表达是与否的数据类型,它在不同的展示界面可能以 true/false 或 1/0 来表示,在 n8n 中一般是 1/0。

第六步:生成文件

添加一个 Convert to File节点。
notion image
notion image
参数设置如下:
Operation - Convert to XLS
Put Output File in Field - data
这一步没啥可说的,就是将整理好的数据,生成一个 Excel 文件。运行顺利的话,你将会在运行结束后在 Output 面板里看到一个文件的下载链接。下载后,我们就可以在 Excel 中看到表格啦。
如果你希望将文件保存在服务器,你还可以在这个后面加入一个 Read/Write Files from Disk 节点,然后根据第一步读取文件的方法举一反三,将读取改成写入就行了。

4. 发散

至此,其实距离完成我们题设里的需求其实还差一点。
毕竟,我们的原始列表可是有 2000 多个区县,而腾讯地图的免费额度每天只能完成 200 次查询。
一种解决思路是我们可以手动将原始区县列表分割成 15 个,每天执行一次,到第十五天再将所有数据合并起来。
但既然 n8n 本就是一个自动化工具,我们是否可以简化这个分割、分批、合并的流程呢?
答案是当然可以,但这里我不会给出完整的 Worklow 了。不过,我可以写一下思路:
  1. 修改 Workflow 的结尾,用 Read/Write Files from Disk 节点将读取到的麦当劳数据,回写到存储于服务器的原始数据表中。
  1. 修改 Workflow 的开头,添加一个 Filter 节点过略掉读取的列表中,“麦当劳”一列不是空值的行,也就是“之前已经查过的,今天就不查了”,并限制每次只读 200 行。
  1. 将 Trigger 改为每天定时触发。
经过上面的修改,你在激活 Workflow 之后,就完全不用管了,等 15 天后就能自动收获一个完整的数据集。
自己动手试试吧~
广告
基于 RSS 的阅读分流器如何实现一个 n*m 循环?
Loading...
目录