197 lines
7.6 KiB
Markdown
197 lines
7.6 KiB
Markdown
|
||
|
||
**Place ID 是 Google Maps/Places API 中用于唯一标识一个地点(place)的字符串**,常用于构建 URL(如 `https://maps.google.com/?place_id=ChIJ...`)或调用 Places API(如 Place Details)。
|
||
|
||
### 最简单的方法:使用 Google 官方 Place ID Finder
|
||
1. 打开 Google 的 **Place ID Finder** 工具:
|
||
- 推荐链接:https://developers.google.com/maps/documentation/javascript/examples/places-placeid-finder
|
||
- 或官方文档中的查找器:https://developers.google.com/maps/documentation/places/web-service/place-id
|
||
|
||
2. 在搜索框中输入地点名称、地址或关键词(例如“上海东方明珠”或具体地址)。
|
||
|
||
3. 从下拉建议或地图上选择正确的地点。
|
||
|
||
4. 工具会自动显示 **Place ID**(以 `ChIJ` 开头的一长串字符),直接复制即可。
|
||
|
||
这个方法最推荐,不需要写代码。
|
||
|
||
### 通过 Google Maps 网页手动获取(无需 API)
|
||
- 在 [Google Maps](https://www.google.com/maps) 搜索并打开你要的地点页面。
|
||
- 点击 **分享** → **嵌入地图**(Embed a map),或直接查看页面源代码(右键 → 查看页面源代码,搜索 “place_id” 或 “ChIJ”)。
|
||
- 有些 Chrome 扩展(如 “Place ID Finder for Google Maps”)可以点击地点后直接显示 Place ID。
|
||
|
||
### 通过 Places API 编程获取(推荐用于批量或自动化)
|
||
使用 **Text Search**(文本搜索)、**Nearby Search**(附近搜索)或 **Find Place** 等接口,响应结果中会包含 `place_id`。
|
||
|
||
示例(Text Search):
|
||
```
|
||
https://maps.googleapis.com/maps/api/place/textsearch/json?query=你的地点名称&key=YOUR_API_KEY
|
||
```
|
||
|
||
响应中会有 `"place_id": "ChIJ..."`。
|
||
|
||
然后可以用这个 Place ID 调用 Place Details 获取更多信息,或拼接到 URL 中。
|
||
|
||
### 构建带 Place ID 的 Google Maps URL
|
||
- 简单格式:`https://www.google.com/maps/place/?q=place_id:你的PlaceID`
|
||
- 或者:`https://maps.google.com/?place_id=你的PlaceID`(你提到的格式)
|
||
- 推荐搜索动作:`https://www.google.com/maps/search/?api=1&query_place_id=你的PlaceID`
|
||
|
||
**注意**:
|
||
- Place ID 长期稳定,但 Google 建议如果超过 12 个月,最好刷新一次。
|
||
- 使用 Places API 需要启用对应服务并获取 API Key,会有费用(免费额度有限)。
|
||
- 对于某些服务区企业(无实体地址),可能需要额外技巧(如查看 “Write a review” 按钮的 data-pid)。
|
||
|
||
如果你有具体地点名称或地址,告诉我,我可以帮你进一步说明!
|
||
|
||
---
|
||
|
||
是否可以将这个程序封装成有gui的界面程序。在界面上加载一个google 地图,或者百度地图之类,通过鼠标可以选择任何一个点,获得其经纬度!
|
||
同时,界面提供一个输入框,允许用户输入查询的关键字,如 咖啡店
|
||
最终查询的效果可能跟这个命令行差不多!?
|
||
npm run scrape "https://www.google.com/maps/place/The+Coffee+Shop/@40.7484,-73.9857,17z"
|
||
|
||
我的上述需求,是否可以实现?
|
||
|
||
● 完全可以实现。这个需求的核心是把现有的 CLI 流程变成一个带地图交互的 GUI。
|
||
|
||
方案分析
|
||
|
||
有几种实现路径:
|
||
|
||
方案 A:浏览器 Web 应用 + 本地服务(推荐)
|
||
|
||
在现有 Node.js 项目基础上,添加一个本地 Web 服务器和前端页面:
|
||
|
||
- 地图:使用 Leaflet + OpenStreetMap(免费、无需 API Key、全球覆盖)
|
||
- 交互:点击地图任意位置获取经纬度,搜索框输入关键词(如 "咖啡店")
|
||
- 后端:复用现有的 src/placesApi.ts、src/transformer.ts 等全部代码,通过 API 端点暴露
|
||
- 结果展示:在页面上直接渲染 JSON/Markdown 结果
|
||
|
||
优点:无需额外依赖、免费地图、完全复用现有代码、浏览器打开即用
|
||
|
||
方案 B:Electron 桌面应用
|
||
|
||
打包成独立的桌面窗口应用,内嵌地图。
|
||
|
||
优点:更像"桌面软件"
|
||
缺点:Electron 体积大(~150MB),对这个小工具来说过重
|
||
|
||
方案 C:Python GUI(Tkinter/PyQt + WebView)
|
||
|
||
优点:Python 生态丰富
|
||
缺点:需要把 TypeScript 逻辑用 Python 重写一遍,重复劳动
|
||
|
||
---
|
||
建议
|
||
|
||
方案 A 最合理。具体来说就是:
|
||
|
||
浏览器打开 localhost:3000
|
||
├── 左侧/上方:Leaflet 地图(OSM 瓦片,免费)
|
||
│ ├── 点击任意位置 → 获取经纬度
|
||
│ └── 搜索框输入 "咖啡店 北京"
|
||
├── 右侧/下方:结果展示
|
||
│ ├── JSON 选项卡
|
||
│ └── Markdown 选项卡
|
||
└── 后端:Express 提供 /api/search?lat=xxx&lng=xxx&keyword=xxx
|
||
|
||
工作流程:
|
||
1. 用户在地图上点击,或在搜索框输入关键词
|
||
2. 前端发送经纬度 + 关键词到后端
|
||
3. 后端调用 Google Places API(Nearby Search 或 Text Search)
|
||
4. 返回结果在前端渲染展示
|
||
|
||
更好的做法是直接用 Places API 的 nearby search(基于坐标搜索周边),而不是原来的 URL 解析方式,这样更自然匹配地图点击的交互。
|
||
|
||
---
|
||
要我按方案 A开始实现吗?大概需要新增 2-3 个文件(Express 服务端 + HTML 前端页面),不改动现有的 src/ 代码。
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
首先需要确认你的代理是否配置好了。
|
||
|
||
步骤:
|
||
|
||
1. 在 .env 中配置代理
|
||
|
||
HTTPS_PROXY=http://127.0.0.1:你的代理端口
|
||
|
||
你的代理地址是什么?比如 Clash 一般默认 http://127.0.0.1:7890,V2Ray 一般是 http://127.0.0.1:10809。
|
||
|
||
2. 启动
|
||
|
||
npm run gui
|
||
|
||
看到终端输出 Using proxy: http://... 就说明代理生效了。
|
||
|
||
3. 使用方式
|
||
|
||
|
||
---
|
||
|
||
代理已经正常工作了! 但 Google 返回了 403 错误,原因是你 API Key 的限制。
|
||
|
||
问题
|
||
|
||
Google API returned:The provided API key has an IP address restriction.
|
||
The originating IP address of the call (62.72.181.132) violates this restriction.
|
||
|
||
你的 API Key 在 Google Cloud Console 里设置了 IP 地址白名单,而你的代理出站 IP(62.72.181.132)不在白名单里。
|
||
|
||
解决方法
|
||
|
||
去 Google Cloud Console 修改 API Key 的限制:
|
||
|
||
1. 打开 https://console.cloud.google.com/apis/credentials
|
||
2. 找到你的 API Key:AIzaSyBShHAVWz4caxrAy6X1Abxw4iTXjnSUv3U
|
||
3. 在 应用限制(Application restrictions) 中:
|
||
- 把 62.72.181.132 加入白名单地址
|
||
- 或者直接设为 "无限制"(None)(最简单)
|
||
|
||
改完后重新 npm run gui 即可。
|
||
|
||
---
|
||
代码本身的修复总结:
|
||
- 用 undici 的 setGlobalDispatcher() 来设置代理(而非每个请求手动传 dispatcher),解决了 Node.js 内置 fetch 和 npm
|
||
undici 版本不兼容的问题
|
||
- 修复了 .env 值的前导空格 bug
|
||
- 启动时添加了连通性检测,直接可以判断代理和 API Key 是否正常
|
||
|
||
|
||
---
|
||
|
||
|
||
|
||
总结一下排查结果:
|
||
|
||
发现的问题
|
||
|
||
1. Bug 修复: places:searchNearby 不支持 textQuery 参数
|
||
|
||
Google Places API 的 Nearby Search 端点不支持关键词搜索 — 它只接受 includedTypes(预定义的场所类型)。"coffee shop"
|
||
这种自由文本只能用 Text Search。
|
||
|
||
修复: 当有关键词时,自动路由到 places:searchText(Text Search),只在纯坐标搜索时用 places:searchNearby。
|
||
|
||
2. 网络问题: Google API 在国内被墙
|
||
|
||
# 你的服务器日志显示的:
|
||
[ERROR] Network error during search: TypeError: fetch failed
|
||
# 我用 curl 直接测试确认:
|
||
* Connection timed out after 10015 milliseconds
|
||
# places.googleapis.com 无法从你的网络直接访问
|
||
|
||
修复: 添加了代理支持。在你的 .env 中加上:
|
||
|
||
HTTPS_PROXY=http://127.0.0.1:7890 # 换成你的代理地址
|
||
|
||
然后重新 npm run gui 即可。服务器启动时会显示 Using proxy: http://...。
|
||
|
||
|
||
---
|
||
|