拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【openclaw实用Skill】goplaces 技能:把 Google Places API 的 JSON 结果接进 CLI 工作流

【openclaw实用Skill】goplaces 技能:把 Google Places API 的 JSON 结果接进 CLI 工作流

1. goplaces 技能到底解决什么问题:CLI 调用 Google Places API 并解析 JSON 返回

如果你写过跟地点相关的脚本,大概率经历过这种别扭:想查一家咖啡店的营业状态、评分、地址,得先打开浏览器搜一遍,再把信息手动抄进代码或表格里。Google Places API 本身能力很强,但它的返回是一大坨嵌套 JSON,字段名长、层级深,直接丢给 shell 脚本处理非常难受。goplaces 这个 openclaw 技能,本质就是给 Google Places API(新版)套了一层命令行外壳,让你在终端里一条命令完成文本搜索、地点详情、地址解析和评论拉取,并且默认给人看的排版,加--json就切成机器可读的结构化输出。

它适合谁?三类人最明显。第一类是经常在终端里干活的开发者,想用curl或脚本批量查地点,不想为每个查询写一遍 HTTP 请求和 JSON 解析。第二类是做 Agent 或自动化流程的人,需要把「找附近评分 4 以上的餐厅」这种自然语言意图,变成可复现的命令行调用。第三类是数据整理场景,比如把一批地址解析成标准地点信息,再喂给下游程序。goplaces 的定位不是替代地图 App,而是把地点查询变成一条可管道、可组合、可脚本化的命令。

我试过把它接进一个简单的 shell 流程:先用goplaces search拿到候选地点列表,再用jq抽出 place id,最后用goplaces details补全营业时间和评论。整个过程没有打开任何网页,输出直接进文件。这就是它相对「手动查」的核心价值——把非结构化的查询动作,变成结构化数据流。

需要先明确一点:goplaces 依赖 Google Places API 的密钥,它自己不提供地点数据。所以本文的重点有两块,一是技能本身的配置和命令用法,二是怎么把 API Key 和 Base URL 填对,让请求真正跑通。很多人卡住不是因为命令不会写,而是环境变量没配对,或者 Base URL 指向了错误的端点,导致返回 401 或空结果。下面按「先配好、再跑通、再排错」的顺序展开。

2. TaoToken 前置准备:API Key 与 Base URL 的填写位置

在 openclaw 里用 goplaces,第一步不是敲命令,而是把凭据配好。goplaces 读取两个环境变量:GOOGLE_PLACES_API_KEY是必需的,GOOGLE_PLACES_BASE_URL是可选的,用于指向自定义端点或测试环境。如果你只是本地跑通流程,最省事的方式是写进 shell 的配置文件,比如~/.zshrc或~/.bashrc,这样每个新终端都能读到。

这里要区分两个概念。Google Places API 官方端点需要你自己的 Google Cloud 项目密钥,申请和配额管理都在 Google 侧。而如果你希望通过统一的网关来管理调用、观察请求日志、或者把多个模型的调用收敛到一个入口,可以用 TaoToken 提供的 API 入口作为 Base URL。它的 API 地址是https://taotoken.net/api,注意这个地址不带任何查询参数,直接作为基础路径使用。密钥则在控制台里生成,对应填到GOOGLE_PLACES_API_KEY的位置。

具体操作上,你可以先到 TaoToken 控制台创建一个 API Key。入口在https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,登录后进入 API Keys 页面生成。生成后复制那串 key,不要截图外传。然后编辑你的 shell 配置:

# 写入 ~/.zshrc 或 ~/.bashrc export GOOGLE_PLACES_API_KEY="你的_API_Key" export GOOGLE_PLACES_BASE_URL="https://taotoken.net/api"

保存后执行source ~/.zshrc让配置生效。验证是否读到:

echo $GOOGLE_PLACES_API_KEY echo $GOOGLE_PLACES_BASE_URL

如果第一行输出你的 key、第二行输出 Base URL,说明环境变量没问题。这里有个容易忽略的点:Base URL 结尾不要多加斜杠,也不要拼上/v1之类的路径,goplaces 会自己在后面拼接具体端点。多写一段路径往往就是后面 404 的根源。

如果你不想污染全局环境,也可以在每个项目目录下放一个.env文件,用direnv或手动source加载。对于临时测试,直接在命令前加变量也行:

GOOGLE_PLACES_API_KEY="你的_API_Key" \ GOOGLE_PLACES_BASE_URL="https://taotoken.net/api" \ goplaces search "coffee" --json

这种方式适合一次性验证,不适合长期使用,因为每次都要重复输入。配好之后,建议先别急着搜复杂条件,用最简单的goplaces search "coffee"确认链路通。如果这一步就报错,问题一定在凭据或网络层,而不是命令参数。

另外提醒一句,API Key 属于敏感信息,不要写进会提交到 Git 的脚本里。如果团队协作,用环境变量注入或密钥管理服务,别硬编码。goplaces 本身不会把 key 打印到输出里,但你的 shell 历史可能会记录带 key 的命令,临时测试后记得清理历史或改用环境变量方式。

3. 可复制配置:openclaw 技能片段与 settings 写法

openclaw 的技能通常通过配置文件声明,goplaces 也不例外。你需要在一个技能配置里告诉 openclaw:这个技能叫什么、用哪个命令、需要哪些环境变量、参数怎么传。下面给一份可直接复制的 JSON 配置片段,路径按 openclaw 的约定放在 skills 目录下,比如~/.openclaw/skills/goplaces.json。如果你的 openclaw 版本用 TOML,我也在下面附了等价写法。

先看 JSON 版本:

{ "name": "goplaces", "description": "Google Places API CLI for text search, details, resolve and reviews", "command": "goplaces", "env": { "GOOGLE_PLACES_API_KEY": "${GOOGLE_PLACES_API_KEY}", "GOOGLE_PLACES_BASE_URL": "${GOOGLE_PLACES_BASE_URL}" }, "args": { "search": { "description": "Search places by keyword", "options": ["--json", "--open-now", "--min-rating", "--max-price", "--limit", "--lat", "--lng", "--radius-m", "--type", "--page-token"] }, "details": { "description": "Get place details by place id", "options": ["--reviews", "--json"] }, "resolve": { "description": "Resolve an address text to places", "options": ["--limit", "--json"] } } }

这份配置的关键点有三个。第一,env里用${VAR}引用外部环境变量,而不是把 key 写死,这样配置可以安全地提交或分享。第二,command指向goplaces可执行文件,前提是它已经在 PATH 里;如果不在,写绝对路径。第三,args把子命令和常用选项列出来,方便 openclaw 在生成调用时知道有哪些参数可用。注意--type只接受一个值,API 侧只认第一个,所以别指望传多个类型做并集。

如果你用 TOML,等价写法是这样:

name = "goplaces" description = "Google Places API CLI for text search, details, resolve and reviews" command = "goplaces" [env] GOOGLE_PLACES_API_KEY = "${GOOGLE_PLACES_API_KEY}" GOOGLE_PLACES_BASE_URL = "${GOOGLE_PLACES_BASE_URL}" [args.search] description = "Search places by keyword" options = ["--json", "--open-now", "--min-rating", "--max-price", "--limit", "--lat", "--lng", "--radius-m", "--type", "--page-token"] [args.details] description = "Get place details by place id" options = ["--reviews", "--json"] [args.resolve] description = "Resolve an address text to places" options = ["--limit", "--json"]

配置写好后,openclaw 在加载技能时会读取它,并把环境变量注入到子进程。这里有个细节:${GOOGLE_PLACES_API_KEY}这种写法依赖 openclaw 的变量展开能力,如果你的版本不支持,就改成在启动 openclaw 前先export,配置里只写变量名。两种方式效果一样,选你环境能跑通的。

再补一个 settings 层面的片段,用于把 goplaces 注册到 openclaw 的技能列表里。假设主配置是~/.openclaw/settings.json:

{ "skills": { "goplaces": { "enabled": true, "path": "~/.openclaw/skills/goplaces.json" } } }

这样 openclaw 启动时会自动加载 goplaces。如果你同时用 Cline MCP 或 Codex 的auth.json管理凭据,注意别把同一份 key 在多处重复配置,容易改了一处忘了另一处。统一在环境变量里维护,配置只引用变量名,是最省心的做法。三件套始终是 Base URL、Key、Model ID——goplaces 场景里 Model ID 不涉及,但 Base URL 和 Key 必须成对出现,缺一个都会在请求阶段失败。

4. 验证请求:一条 curl 命令确认地点搜索返回结构化 JSON

配置写完,别急着在 openclaw 里跑复杂流程,先用一条curl命令确认端点、密钥、返回格式都对。这一步能把「配置问题」和「技能问题」分开,排错效率高很多。下面这条命令直接打 Google Places 新版文本搜索端点,通过 TaoToken 的 Base URL 转发:

curl -s -X POST "https://taotoken.net/api/v1/places:searchText" \ -H "Content-Type: application/json" \ -H "X-Goog-Api-Key: $GOOGLE_PLACES_API_KEY" \ -H "X-Goog-FieldMask: places.displayName,places.formattedAddress,places.rating,places.currentOpeningHours.openNow" \ -d '{ "textQuery": "coffee", "maxResultCount": 3 }' | jq .

这条命令做了几件事。-X POST指定方法,Places 新版搜索是 POST。X-Goog-Api-Key头带上你的 key,注意这里用的是$GOOGLE_PLACES_API_KEY,所以前面环境变量必须已经生效。X-Goog-FieldMask是 Places 新版的重要机制,它决定返回哪些字段,不写会报错或返回默认字段。上面这个 mask 只要了名称、地址、评分和是否营业,返回体小、看得清。-d里的textQuery是搜索词,maxResultCount限制条数。

如果一切正常,你会看到类似这样的 JSON:

{ "places": [ { "displayName": { "text": "Blue Bottle Coffee" }, "formattedAddress": "315 Linden St, San Francisco, CA 94102, USA", "rating": 4.5, "currentOpeningHours": { "openNow": true } } ] }

看到places数组里有对象,说明链路通了。接下来换成 goplaces 命令验证技能层:

goplaces search "coffee" --json | jq '.[] | .name'

如果这条能输出一串店名,说明 goplaces 已经正确读取环境变量、拼接端点、解析返回。注意--json的输出结构可能和原始 API 略有不同,goplaces 会做一层整理,字段名更友好。你可以先用goplaces search "coffee" --json | jq 'keys'看看顶层结构,再决定怎么取字段。

再验证一下详情和地址解析:

# 先拿一个 place id PLACE_ID=$(goplaces search "coffee" --json | jq -r '.[0].id') # 用 place id 查详情,带评论 goplaces details "$PLACE_ID" --reviews --json | jq '.reviews[0].text' # 地址解析 goplaces resolve "Soho, London" --limit 3 --json | jq '.[].formattedAddress'

这几条跑通,说明搜索、详情、解析三条主路径都正常。如果curl通但goplaces不通,问题在技能配置或可执行文件路径;如果curl也不通,问题在 key、Base URL 或网络。分清楚这一点,后面排错就不会瞎猜。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

实际跑的时候,报错集中在几类。下面按真实错误信息对照排查,每条都给判断依据和修法。

401 Unauthorized / API key not valid。这是最常见的一类。先确认echo $GOOGLE_PLACES_API_KEY有输出,且没有多余空格或换行。然后确认 key 本身有效、没有过期、没有在控制台被禁用。如果你用的是 TaoToken 的 Base URL,确认 key 是在对应控制台生成的,而不是 Google 官方项目的 key 混用。混用会导致端点认不出这个 key。修法:重新生成一个 key,只配一处,source后重试curl。

local proxy failed / connection refused。这类通常出现在 Base URL 写错或本地网络策略拦截时。检查GOOGLE_PLACES_BASE_URL是不是https://taotoken.net/api,结尾没有多余斜杠,也没有拼/v1。如果之前配过其他代理变量,比如HTTP_PROXY、HTTPS_PROXY,先临时unset掉再试,排除干扰。注意不要使用任何非正规的网络中转方式,保持直连官方入口即可。

reading choices / unexpected end of JSON input。这个报错说明返回体不是合法 JSON,常见原因是端点返回了 HTML 错误页,或者jq拿到空输入。先用不带jq的curl看原始返回:

curl -s -X POST "https://taotoken.net/api/v1/places:searchText" \ -H "Content-Type: application/json" \ -H "X-Goog-Api-Key: $GOOGLE_PLACES_API_KEY" \ -H "X-Goog-FieldMask: places.displayName" \ -d '{"textQuery":"coffee","maxResultCount":1}'

如果返回 HTML 或一段错误文本,按文本提示修。如果返回空,检查FieldMask是否拼错,Places 新版对字段名大小写敏感。

OAuth / permission denied。如果你在 Google Cloud 侧用的是 OAuth 而非 API Key,或者项目没启用 Places API(新版),会报权限类错误。确认项目里已启用 Places API (New),并且 key 的 API 限制里允许该 API。用 TaoToken 入口时,权限校验在网关侧完成,但仍需保证 key 有对应额度。

返回结果为空但没报错。检查textQuery是否太窄,maxResultCount是否被设成 0,--type是否传了 API 不支持的值。另外--open-now和--min-rating组合过严也会导致空结果,先去掉过滤条件看有没有数据,再逐步加回。

goplaces: command not found。说明可执行文件不在 PATH。用which goplaces确认,没有的话把安装目录加进 PATH,或在技能配置里写绝对路径。

排错时建议固定顺序:先curl验证端点,再goplaces验证技能,最后加过滤条件。每步只改一个变量,改完立刻重试,这样能快速定位是哪一层出的问题。

6. 把 goplaces 接进你的工作流:从单次查询到可复用脚本

跑通之后,goplaces 真正的价值在于组合。举一个我常用的场景:给定一个城市和关键词,批量拉取评分 4 以上、当前营业的地点,输出成 CSV 给下游用。命令可以这样写:

goplaces search "ramen" \ --lat 35.68 --lng 139.76 --radius-m 2000 \ --open-now --min-rating 4 --limit 20 --json \ | jq -r '.[] | [.name, .rating, .formattedAddress] | @csv' \ > ramen_tokyo.csv

这条命令把地理偏置、营业过滤、评分过滤、条数限制和 JSON 输出串在一起,最后用jq转 CSV。注意--lat、--lng、--radius-m三个要一起用,单独给经纬度不生效。--limit控制返回条数,避免一次拉太多。

分页场景用--page-token。第一次搜索返回里会带一个 token,把它传给下一次调用:

TOKEN=$(goplaces search "sushi" --json | jq -r '.nextPageToken') goplaces search "sushi" --page-token "$TOKEN" --json | jq '.[].name'

注意 token 有时效,别存太久。另外--no-color或NO_COLOR=1在写脚本时建议加上,避免 ANSI 颜色码污染输出。

如果你在 openclaw 里做 Agent 流程,可以把 goplaces 当成一个工具节点:用户说「找附近评分高的咖啡店」,Agent 解析出关键词和过滤条件,生成goplaces search调用,拿到 JSON 后再决定下一步。这里的关键是让 Agent 知道有哪些参数可用,也就是第 3 节配置里args的作用。参数声明清楚,Agent 生成的命令才不容易出错。

长期做编码或 Agent 编排的话,可以考虑用 Coding Plan 来统一管理调用入口和额度,入口在https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。如果你只是想先验证模型或接口的返回,用模型对话页面更直接:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。需要生成或管理 key 时,API Keys 页面在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。Claude Code 相关的接入说明在https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。

最后给一个实用技巧:把常用查询封装成 shell 函数,放在~/.zshrc里,比如coffee() { goplaces search "coffee" --open-now --min-rating 4 --limit 5 "$@"; },以后直接敲coffee就能查。参数用"$@"透传,灵活又不重复。这样 goplaces 就从一条命令变成了你终端里的一个固定动作,用起来才顺手。

返回列表