From 5df1d82eefd8d889b0fa58b4c5d7ef2ee69b063a Mon Sep 17 00:00:00 2001
From: ableyyyx <2724475986@qq.com>
Date: Wed, 10 Sep 2025 23:40:45 +0800
Subject: [PATCH 1/4] update gitignore
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 0731664..89e00a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,4 @@ dmypy.json
.langgraph_api
.idea
+.DS_Store
From 14f1c48cc1e321176fda556a38d5288a8e9b8ba8 Mon Sep 17 00:00:00 2001
From: ableyyyx <2724475986@qq.com>
Date: Wed, 10 Sep 2025 23:41:31 +0800
Subject: [PATCH 2/4] visualize nearby search & place details API
---
CallAPIs/Place_API_test.ipynb | 1152 +++++++++++++++++++++++++++++++++
1 file changed, 1152 insertions(+)
create mode 100644 CallAPIs/Place_API_test.ipynb
diff --git a/CallAPIs/Place_API_test.ipynb b/CallAPIs/Place_API_test.ipynb
new file mode 100644
index 0000000..cff8382
--- /dev/null
+++ b/CallAPIs/Place_API_test.ipynb
@@ -0,0 +1,1152 @@
+{
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "provenance": []
+ },
+ "kernelspec": {
+ "name": "python3",
+ "display_name": "Python 3"
+ },
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "id": "jOvvMS1NZnrB"
+ },
+ "outputs": [],
+ "source": [
+ "\n",
+ "import os, getpass, requests, time\n",
+ "from typing import Dict, Any, List\n",
+ "\n",
+ "# 安全地注入 API Key(建议在 GCP 控制台为 Places API 启用后再粘贴)\n",
+ "if \"GOOGLE_MAPS_API_KEY\" not in os.environ:\n",
+ " os.environ[\"GOOGLE_MAPS_API_KEY\"] = getpass.getpass(\"请输入你的 Google Maps API Key(不可见): \")\n",
+ "\n",
+ "API_KEY = os.environ[\"GOOGLE_MAPS_API_KEY\"]\n",
+ "BASE = \"https://places.googleapis.com/v1\"\n",
+ "\n",
+ "def call_places(method: str, path: str, field_mask: str,\n",
+ " json_body: Dict[str, Any] | None = None,\n",
+ " params: Dict[str, Any] | None = None) -> Dict[str, Any]:\n",
+ " \"\"\"通用调用器:封装 X-Goog-FieldMask / X-Goog-Api-Key 头\"\"\"\n",
+ " headers = {\n",
+ " \"Content-Type\": \"application/json\",\n",
+ " \"X-Goog-Api-Key\": API_KEY,\n",
+ " \"X-Goog-FieldMask\": field_mask, # 必须!否则报错\n",
+ " }\n",
+ " url = f\"{BASE}{path}\"\n",
+ " resp = requests.request(method, url, headers=headers, json=json_body, params=params, timeout=30)\n",
+ " resp.raise_for_status()\n",
+ " return resp.json()\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#1.Nearby Search(指定点与半径找“餐厅”)\n",
+ "\n",
+ "• 仅支持 POST,请求体里写范围(圆形中心 + 半径)。\n",
+ "\n",
+ "• 示例字段掩码只拿到 ID、地理位置、地址、评分、价格等用于做餐厅画像的关键字段"
+ ],
+ "metadata": {
+ "id": "ECWMXYJbaDEk"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# 你可以换成自己的坐标与半径;这里示例:新加坡 Orchard Road 附近\n",
+ "center_lat, center_lng = 1.3049, 103.8318 # Orchard 附近\n",
+ "center_lat, center_lng = 45.553360, -122.674934 # 官方示例坐标(美国波特兰)\n",
+ "radius_m = 1500.0\n",
+ "\n",
+ "# 为 Nearby 准备一个最小够用的字段掩码(不要包含 nextPageToken —— 官方页未明确 Nearby 的翻页字段)\n",
+ "SEARCH_MASK_NEARBY = \",\".join([\n",
+ " \"places.id\",\n",
+ " \"places.displayName\",\n",
+ " \"places.location\",\n",
+ " \"places.formattedAddress\",\n",
+ " # \"places.primaryType\",\n",
+ " # \"places.types\",\n",
+ " # \"places.rating\",\n",
+ " # \"places.userRatingCount\",\n",
+ " # \"places.priceLevel\",\n",
+ " # \"places.googleMapsUri\",\n",
+ " # \"places.generativeSummary\",\n",
+ " # \"places.editorialSummary\"\n",
+ "])\n",
+ "\n",
+ "nearby_body = {\n",
+ " \"includedTypes\": [\"restaurant\"], # 也可用 includedPrimaryTypes\n",
+ " \"maxResultCount\": 20, # Nearby 单页最多 20\n",
+ " \"rankPreference\": \"POPULARITY\", # 或 \"DISTANCE\"\n",
+ " \"locationRestriction\": {\n",
+ " \"circle\": {\n",
+ " \"center\": {\"latitude\": center_lat, \"longitude\": center_lng},\n",
+ " \"radius\": radius_m\n",
+ " }\n",
+ " }\n",
+ "}\n",
+ "\n",
+ "nearby = call_places(\"POST\", \"/places:searchNearby\", SEARCH_MASK_NEARBY, json_body=nearby_body)\n",
+ "len(nearby.get(\"places\", [])), nearby.get(\"places\", [])[:2] # 看下总数与前两个示例\n"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "CmP2rTXxZ1NO",
+ "outputId": "1251b758-da61-4b9c-e12e-dc0552f9a66e"
+ },
+ "execution_count": 46,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "(20,\n",
+ " [{'id': 'ChIJOa08KlqnlVQR_ZZx1jEcTYY',\n",
+ " 'formattedAddress': '3808 N Williams Ave #127, Portland, OR 97227, USA',\n",
+ " 'location': {'latitude': 45.5506551, 'longitude': -122.66652119999998},\n",
+ " 'displayName': {'text': 'Eem - Thai BBQ & Cocktails',\n",
+ " 'languageCode': 'en'}},\n",
+ " {'id': 'ChIJU4OzoWynlVQRxlQMpGenSvA',\n",
+ " 'formattedAddress': '4237 N Mississippi Ave, Portland, OR 97217, USA',\n",
+ " 'location': {'latitude': 45.554515699999996,\n",
+ " 'longitude': -122.67573579999998},\n",
+ " 'displayName': {'text': 'Prost!', 'languageCode': 'en'}}])"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 46
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "#可视化\n",
+ "rows: List[Dict[str, Any]] = []\n",
+ "for p in nearby.get(\"places\", []):\n",
+ " # 注意:Nearby 返回的 location 可能是 {\"latitude\":..., \"longitude\":...}\n",
+ " loc = p.get(\"location\") or {}\n",
+ " # 生成式摘要(Search 侧路径:places.generativeSummary)\n",
+ " gsum = p.get(\"generativeSummary\") or {}\n",
+ " g_overview = ((gsum.get(\"overview\") or {}).get(\"text\")) if isinstance(gsum, dict) else None\n",
+ " # 编辑摘要\n",
+ " esum = p.get(\"editorialSummary\") or {}\n",
+ " e_text = esum.get(\"text\") if isinstance(esum, dict) else None\n",
+ "\n",
+ " rows.append({\n",
+ " \"id\": p.get(\"id\"),\n",
+ " \"name\": (p.get(\"displayName\") or {}).get(\"text\"),\n",
+ " \"lat\": loc.get(\"latitude\"),\n",
+ " \"lng\": loc.get(\"longitude\"),\n",
+ " \"address\": p.get(\"formattedAddress\"),\n",
+ " # \"primaryType\": p.get(\"primaryType\"),\n",
+ " # \"types\": \", \".join(p.get(\"types\", [])),\n",
+ " # \"rating\": p.get(\"rating\"),\n",
+ " # \"ratingCount\": p.get(\"userRatingCount\"),\n",
+ " # \"priceLevel\": p.get(\"priceLevel\"),\n",
+ " # \"googleMapsUrl\": p.get(\"googleMapsUri\"),\n",
+ " # 摘要拍平列\n",
+ " # \"genOverview\": g_overview,\n",
+ " # \"editorialText\": e_text,\n",
+ " })\n",
+ "\n",
+ "pd.DataFrame(rows)"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 677
+ },
+ "id": "BUlQllHuMUAV",
+ "outputId": "f0a0ef7f-59f1-4200-bd76-52d33893a5d9"
+ },
+ "execution_count": 47,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ " id \\\n",
+ "0 ChIJOa08KlqnlVQR_ZZx1jEcTYY \n",
+ "1 ChIJU4OzoWynlVQRxlQMpGenSvA \n",
+ "2 ChIJIxfmG0KnlVQR3ZPSgF46ahE \n",
+ "3 ChIJeaQuoUeFhVQR5k_yPdK_gvk \n",
+ "4 ChIJL9S2VWmnlVQRUhyawDjpzjY \n",
+ "5 ChIJT9ZbCWunlVQRIryTTXOWkEw \n",
+ "6 ChIJb1BVEBenlVQRWQZoL6tdhpw \n",
+ "7 ChIJr8AyrWunlVQR_w411-qtqkw \n",
+ "8 ChIJ9SRcAkKnlVQRU2wR1eFxEew \n",
+ "9 ChIJzQfQ8b2hlVQRz8RLZLvD_ps \n",
+ "10 ChIJUe0ZJGynlVQRj5j7YnzeHwc \n",
+ "11 ChIJX9VXlj-nlVQRnJy2Up4d58Q \n",
+ "12 ChIJC3JflEOnlVQRTgXBnXO_Pto \n",
+ "13 ChIJ3TR1jQ2nlVQRo0XThDocw_w \n",
+ "14 ChIJj-0nJrSnlVQRLAkmEOu3DI0 \n",
+ "15 ChIJTzIkE1WnlVQR8UCJX2Clmmg \n",
+ "16 ChIJXaSbYjinlVQR8dLXhKW654Y \n",
+ "17 ChIJ8-KumFqnlVQRyTdcK1RP-Vc \n",
+ "18 ChIJ5feGCGqnlVQRV2Lc8MyL8e0 \n",
+ "19 ChIJHXqQqmunlVQRSyFCcmcf3AU \n",
+ "\n",
+ " name lat lng \\\n",
+ "0 Eem - Thai BBQ & Cocktails 45.550655 -122.666521 \n",
+ "1 Prost! 45.554516 -122.675736 \n",
+ "2 ¿Por Qué No? 45.548156 -122.675325 \n",
+ "3 Cafe Olli 45.551158 -122.661911 \n",
+ "4 The Alibi Tiki Lounge 45.552537 -122.680687 \n",
+ "5 Lovely's Fifty Fifty 45.552860 -122.675850 \n",
+ "6 Matt's BBQ 45.554346 -122.675788 \n",
+ "7 Gravy 45.551708 -122.675706 \n",
+ "8 Mississippi Pizza & Atlantis Lounge 45.548614 -122.675199 \n",
+ "9 Kate's Ice Cream 45.549804 -122.675777 \n",
+ "10 Fire On the Mountain Buffalo Wings | Interstate 45.554035 -122.681788 \n",
+ "11 Kayo's Ramen Bar 45.550278 -122.666389 \n",
+ "12 Matador North Portland 45.553413 -122.666966 \n",
+ "13 Sweedeedee 45.560571 -122.674873 \n",
+ "14 Churn Cafe 45.551343 -122.675179 \n",
+ "15 Migration Brewing x Pápa's Frita - Williams 45.551351 -122.666898 \n",
+ "16 Popeyes Louisiana Kitchen 45.545798 -122.661322 \n",
+ "17 Broder Nord 45.550212 -122.675691 \n",
+ "18 StormBreaker Brewing 45.549428 -122.675145 \n",
+ "19 The 1905 45.551970 -122.675274 \n",
+ "\n",
+ " address \n",
+ "0 3808 N Williams Ave #127, Portland, OR 97227, USA \n",
+ "1 4237 N Mississippi Ave, Portland, OR 97217, USA \n",
+ "2 3524 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "3 3925 NE Martin Luther King Jr Blvd, Portland, ... \n",
+ "4 4024 N Interstate Ave, Portland, OR 97227, USA \n",
+ "5 4039 N Mississippi Ave, Portland, OR 97217, USA \n",
+ "6 4233 N Mississippi Ave, Portland, OR 97217, USA \n",
+ "7 3957 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "8 3552 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "9 3713 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "10 4225 N Interstate Ave, Portland, OR 97217, USA \n",
+ "11 3808 N Williams Ave # 124, Portland, OR 97227,... \n",
+ "12 4111 N Williams Ave, Portland, OR 97217, USA \n",
+ "13 5202 N Albina Ave, Portland, OR 97217, USA \n",
+ "14 3928 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "15 3947 N Williams Ave, Portland, OR 97227, USA \n",
+ "16 3120 NE Martin Luther King Jr Blvd, Portland, ... \n",
+ "17 3765 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "18 832 N Beech St, Portland, OR 97227, USA \n",
+ "19 830 N Shaver St, Portland, OR 97227, USA "
+ ],
+ "text/html": [
+ "\n",
+ "
\n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " id | \n",
+ " name | \n",
+ " lat | \n",
+ " lng | \n",
+ " address | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " ChIJOa08KlqnlVQR_ZZx1jEcTYY | \n",
+ " Eem - Thai BBQ & Cocktails | \n",
+ " 45.550655 | \n",
+ " -122.666521 | \n",
+ " 3808 N Williams Ave #127, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " ChIJU4OzoWynlVQRxlQMpGenSvA | \n",
+ " Prost! | \n",
+ " 45.554516 | \n",
+ " -122.675736 | \n",
+ " 4237 N Mississippi Ave, Portland, OR 97217, USA | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " ChIJIxfmG0KnlVQR3ZPSgF46ahE | \n",
+ " ¿Por Qué No? | \n",
+ " 45.548156 | \n",
+ " -122.675325 | \n",
+ " 3524 N Mississippi Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " ChIJeaQuoUeFhVQR5k_yPdK_gvk | \n",
+ " Cafe Olli | \n",
+ " 45.551158 | \n",
+ " -122.661911 | \n",
+ " 3925 NE Martin Luther King Jr Blvd, Portland, ... | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " ChIJL9S2VWmnlVQRUhyawDjpzjY | \n",
+ " The Alibi Tiki Lounge | \n",
+ " 45.552537 | \n",
+ " -122.680687 | \n",
+ " 4024 N Interstate Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 5 | \n",
+ " ChIJT9ZbCWunlVQRIryTTXOWkEw | \n",
+ " Lovely's Fifty Fifty | \n",
+ " 45.552860 | \n",
+ " -122.675850 | \n",
+ " 4039 N Mississippi Ave, Portland, OR 97217, USA | \n",
+ "
\n",
+ " \n",
+ " 6 | \n",
+ " ChIJb1BVEBenlVQRWQZoL6tdhpw | \n",
+ " Matt's BBQ | \n",
+ " 45.554346 | \n",
+ " -122.675788 | \n",
+ " 4233 N Mississippi Ave, Portland, OR 97217, USA | \n",
+ "
\n",
+ " \n",
+ " 7 | \n",
+ " ChIJr8AyrWunlVQR_w411-qtqkw | \n",
+ " Gravy | \n",
+ " 45.551708 | \n",
+ " -122.675706 | \n",
+ " 3957 N Mississippi Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 8 | \n",
+ " ChIJ9SRcAkKnlVQRU2wR1eFxEew | \n",
+ " Mississippi Pizza & Atlantis Lounge | \n",
+ " 45.548614 | \n",
+ " -122.675199 | \n",
+ " 3552 N Mississippi Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 9 | \n",
+ " ChIJzQfQ8b2hlVQRz8RLZLvD_ps | \n",
+ " Kate's Ice Cream | \n",
+ " 45.549804 | \n",
+ " -122.675777 | \n",
+ " 3713 N Mississippi Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 10 | \n",
+ " ChIJUe0ZJGynlVQRj5j7YnzeHwc | \n",
+ " Fire On the Mountain Buffalo Wings | Interstate | \n",
+ " 45.554035 | \n",
+ " -122.681788 | \n",
+ " 4225 N Interstate Ave, Portland, OR 97217, USA | \n",
+ "
\n",
+ " \n",
+ " 11 | \n",
+ " ChIJX9VXlj-nlVQRnJy2Up4d58Q | \n",
+ " Kayo's Ramen Bar | \n",
+ " 45.550278 | \n",
+ " -122.666389 | \n",
+ " 3808 N Williams Ave # 124, Portland, OR 97227,... | \n",
+ "
\n",
+ " \n",
+ " 12 | \n",
+ " ChIJC3JflEOnlVQRTgXBnXO_Pto | \n",
+ " Matador North Portland | \n",
+ " 45.553413 | \n",
+ " -122.666966 | \n",
+ " 4111 N Williams Ave, Portland, OR 97217, USA | \n",
+ "
\n",
+ " \n",
+ " 13 | \n",
+ " ChIJ3TR1jQ2nlVQRo0XThDocw_w | \n",
+ " Sweedeedee | \n",
+ " 45.560571 | \n",
+ " -122.674873 | \n",
+ " 5202 N Albina Ave, Portland, OR 97217, USA | \n",
+ "
\n",
+ " \n",
+ " 14 | \n",
+ " ChIJj-0nJrSnlVQRLAkmEOu3DI0 | \n",
+ " Churn Cafe | \n",
+ " 45.551343 | \n",
+ " -122.675179 | \n",
+ " 3928 N Mississippi Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 15 | \n",
+ " ChIJTzIkE1WnlVQR8UCJX2Clmmg | \n",
+ " Migration Brewing x Pápa's Frita - Williams | \n",
+ " 45.551351 | \n",
+ " -122.666898 | \n",
+ " 3947 N Williams Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 16 | \n",
+ " ChIJXaSbYjinlVQR8dLXhKW654Y | \n",
+ " Popeyes Louisiana Kitchen | \n",
+ " 45.545798 | \n",
+ " -122.661322 | \n",
+ " 3120 NE Martin Luther King Jr Blvd, Portland, ... | \n",
+ "
\n",
+ " \n",
+ " 17 | \n",
+ " ChIJ8-KumFqnlVQRyTdcK1RP-Vc | \n",
+ " Broder Nord | \n",
+ " 45.550212 | \n",
+ " -122.675691 | \n",
+ " 3765 N Mississippi Ave, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 18 | \n",
+ " ChIJ5feGCGqnlVQRV2Lc8MyL8e0 | \n",
+ " StormBreaker Brewing | \n",
+ " 45.549428 | \n",
+ " -122.675145 | \n",
+ " 832 N Beech St, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ " 19 | \n",
+ " ChIJHXqQqmunlVQRSyFCcmcf3AU | \n",
+ " The 1905 | \n",
+ " 45.551970 | \n",
+ " -122.675274 | \n",
+ " 830 N Shaver St, Portland, OR 97227, USA | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ "
\n",
+ "
\n"
+ ],
+ "application/vnd.google.colaboratory.intrinsic+json": {
+ "type": "dataframe",
+ "summary": "{\n \"name\": \"pd\",\n \"rows\": 20,\n \"fields\": [\n {\n \"column\": \"id\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"ChIJOa08KlqnlVQR_ZZx1jEcTYY\",\n \"ChIJ8-KumFqnlVQRyTdcK1RP-Vc\",\n \"ChIJTzIkE1WnlVQR8UCJX2Clmmg\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"name\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"Eem - Thai BBQ & Cocktails\",\n \"Broder Nord\",\n \"Migration Brewing x P\\u00e1pa's Frita - Williams\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"lat\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.003040066899277008,\n \"min\": 45.545797799999995,\n \"max\": 45.5605707,\n \"num_unique_values\": 20,\n \"samples\": [\n 45.5506551,\n 45.5502118,\n 45.551350799999994\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"lng\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.005752372433270196,\n \"min\": -122.68178839999999,\n \"max\": -122.66132239999997,\n \"num_unique_values\": 20,\n \"samples\": [\n -122.66652119999998,\n -122.67569069999999,\n -122.66689849999999\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"address\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"3808 N Williams Ave #127, Portland, OR 97227, USA\",\n \"3765 N Mississippi Ave, Portland, OR 97227, USA\",\n \"3947 N Williams Ave, Portland, OR 97227, USA\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
+ }
+ },
+ "metadata": {},
+ "execution_count": 47
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#2.Text Search(关键词 + 区域偏置)\n",
+ "\n",
+ "• POST 到 places:searchText,textQuery 可以写 “sushi near orchard road singapore”。\n",
+ "\n",
+ "• pageSize 控制每页数量;响应里若返回 nextPageToken,用它继续翻页(放在请求体的 pageToken 字段)。\n"
+ ],
+ "metadata": {
+ "id": "tSOzZZniahS-"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# Text Search 字段掩码:与 Nearby 类似,但加入 nextPageToken 以便分页\n",
+ "SEARCH_MASK_TEXT = \",\".join([\n",
+ " \"places.id\",\n",
+ " \"places.displayName\",\n",
+ " \"places.location\",\n",
+ " \"places.formattedAddress\",\n",
+ " \"places.primaryType\",\n",
+ " \"places.types\",\n",
+ " \"places.rating\",\n",
+ " \"places.userRatingCount\",\n",
+ " \"places.priceLevel\",\n",
+ " \"places.googleMapsUri\",\n",
+ " \"places.generativeSummary\",\n",
+ " \"nextPageToken\"\n",
+ "])\n",
+ "\n",
+ "text_body = {\n",
+ " \"textQuery\": \"sushi near orchard road singapore\",\n",
+ " # 用 locationBias 把结果“往某区域靠”\n",
+ " \"locationBias\": {\n",
+ " \"circle\": {\n",
+ " \"center\": {\"latitude\": center_lat, \"longitude\": center_lng},\n",
+ " \"radius\": 1200.0\n",
+ " }\n",
+ " },\n",
+ " \"pageSize\": 10\n",
+ "}\n",
+ "\n",
+ "page1 = call_places(\"POST\", \"/places:searchText\", SEARCH_MASK_TEXT, json_body=text_body)\n",
+ "print(\"第一页条数:\", len(page1.get(\"places\", [])))\n",
+ "print(\"是否可翻页:\", \"nextPageToken\" in page1)\n",
+ "\n",
+ "# 若可翻页,继续拿第二页\n",
+ "page2 = {}\n",
+ "if \"nextPageToken\" in page1:\n",
+ " text_body2 = {**text_body, \"pageToken\": page1[\"nextPageToken\"]}\n",
+ " # 按官方示例,翻页前稍等一小会儿更稳妥\n",
+ " time.sleep(1.2)\n",
+ " page2 = call_places(\"POST\", \"/places:searchText\", SEARCH_MASK_TEXT, json_body=text_body2)\n",
+ " print(\"第二页条数:\", len(page2.get(\"places\", [])))\n"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "xDAtX-aTakoi",
+ "outputId": "ef4f0e54-5049-4378-d9ff-4aaa892401a8"
+ },
+ "execution_count": 48,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "第一页条数: 10\n",
+ "是否可翻页: True\n",
+ "第二页条数: 10\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "#3.Place Details(对单个餐厅补充细节)\n",
+ "\n",
+ "• GET 到 /v1/places/{PLACE_ID},同样必须带 FieldMask。\n",
+ "• 支持补充电话、网站、营业时间、评分/价位等(不同字段触发不同 SKU)"
+ ],
+ "metadata": {
+ "id": "ZgDRJD4gbO6t"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "# 拿 Nearby 或 Text Search 的第一个结果做示例\n",
+ "any_place_id = (nearby.get(\"places\") or page1.get(\"places\") or page2.get(\"places\"))[0][\"id\"]\n",
+ "\n",
+ "DETAILS_MASK = \",\".join([\n",
+ " # 注意:Place Details 的字段掩码是 Place 对象顶层,不再以 \"places.\" 起头!\n",
+ " \"id\",\n",
+ " \"displayName\",\n",
+ " \"location\",\n",
+ " \"formattedAddress\",\n",
+ " \"primaryType\",\n",
+ " \"types\",\n",
+ " \"rating\",\n",
+ " \"userRatingCount\",\n",
+ " \"priceLevel\",\n",
+ " \"websiteUri\",\n",
+ " \"nationalPhoneNumber\",\n",
+ " \"currentOpeningHours\",\n",
+ " \"googleMapsUri\",\n",
+ " # 两类摘要\n",
+ " \"editorialSummary\",\n",
+ " \"generativeSummary\",\n",
+ " # 一些“场景/服务”标签(可用于画像增强)\n",
+ " \"servesBreakfast\",\n",
+ " \"servesBrunch\",\n",
+ " \"servesLunch\",\n",
+ " \"servesDinner\",\n",
+ " \"servesVegetarianFood\",\n",
+ " \"servesBeer\",\n",
+ " \"servesWine\",\n",
+ " \"servesCocktails\",\n",
+ "])\n",
+ "\n",
+ "details = call_places(\"GET\", f\"/places/{any_place_id}\", DETAILS_MASK)\n",
+ "details\n"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "Xn0NtIzsbS-b",
+ "outputId": "dc682463-7efc-40b9-a89f-b044b53a7672"
+ },
+ "execution_count": 49,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "{'id': 'ChIJOa08KlqnlVQR_ZZx1jEcTYY',\n",
+ " 'types': ['thai_restaurant',\n",
+ " 'barbecue_restaurant',\n",
+ " 'bar',\n",
+ " 'restaurant',\n",
+ " 'food',\n",
+ " 'point_of_interest',\n",
+ " 'establishment'],\n",
+ " 'nationalPhoneNumber': '(971) 295-1645',\n",
+ " 'formattedAddress': '3808 N Williams Ave #127, Portland, OR 97227, USA',\n",
+ " 'location': {'latitude': 45.5506551, 'longitude': -122.66652119999998},\n",
+ " 'rating': 4.7,\n",
+ " 'googleMapsUri': 'https://maps.google.com/?cid=9677422174665807613&g_mp=CiVnb29nbGUubWFwcy5wbGFjZXMudjEuUGxhY2VzLkdldFBsYWNlEAAYBCAA',\n",
+ " 'websiteUri': 'http://www.eempdx.com/',\n",
+ " 'priceLevel': 'PRICE_LEVEL_MODERATE',\n",
+ " 'userRatingCount': 2526,\n",
+ " 'displayName': {'text': 'Eem - Thai BBQ & Cocktails', 'languageCode': 'en'},\n",
+ " 'servesBreakfast': False,\n",
+ " 'servesLunch': True,\n",
+ " 'servesDinner': True,\n",
+ " 'servesBeer': True,\n",
+ " 'servesWine': True,\n",
+ " 'servesBrunch': False,\n",
+ " 'servesVegetarianFood': True,\n",
+ " 'currentOpeningHours': {'openNow': False,\n",
+ " 'periods': [{'open': {'day': 0,\n",
+ " 'hour': 11,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 14}},\n",
+ " 'close': {'day': 0,\n",
+ " 'hour': 21,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 14}}},\n",
+ " {'open': {'day': 1,\n",
+ " 'hour': 11,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 15}},\n",
+ " 'close': {'day': 1,\n",
+ " 'hour': 21,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 15}}},\n",
+ " {'open': {'day': 2,\n",
+ " 'hour': 11,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 16}},\n",
+ " 'close': {'day': 2,\n",
+ " 'hour': 21,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 16}}},\n",
+ " {'open': {'day': 3,\n",
+ " 'hour': 11,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 10}},\n",
+ " 'close': {'day': 3,\n",
+ " 'hour': 21,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 10}}},\n",
+ " {'open': {'day': 4,\n",
+ " 'hour': 11,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 11}},\n",
+ " 'close': {'day': 4,\n",
+ " 'hour': 21,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 11}}},\n",
+ " {'open': {'day': 5,\n",
+ " 'hour': 11,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 12}},\n",
+ " 'close': {'day': 5,\n",
+ " 'hour': 22,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 12}}},\n",
+ " {'open': {'day': 6,\n",
+ " 'hour': 11,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 13}},\n",
+ " 'close': {'day': 6,\n",
+ " 'hour': 22,\n",
+ " 'minute': 0,\n",
+ " 'date': {'year': 2025, 'month': 9, 'day': 13}}}],\n",
+ " 'weekdayDescriptions': ['Monday: 11:00\\u202fAM\\u2009–\\u20099:00\\u202fPM',\n",
+ " 'Tuesday: 11:00\\u202fAM\\u2009–\\u20099:00\\u202fPM',\n",
+ " 'Wednesday: 11:00\\u202fAM\\u2009–\\u20099:00\\u202fPM',\n",
+ " 'Thursday: 11:00\\u202fAM\\u2009–\\u20099:00\\u202fPM',\n",
+ " 'Friday: 11:00\\u202fAM\\u2009–\\u200910:00\\u202fPM',\n",
+ " 'Saturday: 11:00\\u202fAM\\u2009–\\u200910:00\\u202fPM',\n",
+ " 'Sunday: 11:00\\u202fAM\\u2009–\\u20099:00\\u202fPM'],\n",
+ " 'nextOpenTime': '2025-09-10T18:00:00Z'},\n",
+ " 'primaryType': 'thai_restaurant',\n",
+ " 'editorialSummary': {'text': 'Modern Thai eatery serving creative BBQ and craft cocktails including tiki drinks in traditional mugs.',\n",
+ " 'languageCode': 'en'},\n",
+ " 'servesCocktails': True,\n",
+ " 'generativeSummary': {'overview': {'text': 'BBQ and Thai street fare, plus imaginative tropical cocktails, served in a vibrant space.',\n",
+ " 'languageCode': 'en-US'},\n",
+ " 'overviewFlagContentUri': 'https://www.google.com/local/review/rap/report?postId=CiUweDU0OTVhNzVhMmEzY2FkMzk6MHg4NjRkMWMzMWQ2NzE5NmZkMAI&d=17924085&t=12',\n",
+ " 'disclosureText': {'text': 'Summarized with Gemini',\n",
+ " 'languageCode': 'en-US'}}}"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 49
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "loc = p.get(\"location\") or {}\n",
+ "\n",
+ "gsum = details.get(\"generativeSummary\") or {}\n",
+ "g_overview = ((gsum.get(\"overview\") or {}).get(\"text\")) if isinstance(gsum, dict) else None\n",
+ "\n",
+ "esum = details.get(\"editorialSummary\") or {}\n",
+ "e_text = esum.get(\"text\") if isinstance(esum, dict) else None\n",
+ "\n",
+ "\n",
+ "row = {\n",
+ " \"id\": details.get(\"id\"),\n",
+ " \"name\": (details.get(\"displayName\") or {}).get(\"text\"),\n",
+ " \"lat\": loc.get(\"latitude\"),\n",
+ " \"lng\": loc.get(\"longitude\"),\n",
+ " \"address\": details.get(\"formattedAddress\"),\n",
+ " \"primaryType\": details.get(\"primaryType\"),\n",
+ " \"types\": \", \".join(details.get(\"types\", [])),\n",
+ " \"rating\": details.get(\"rating\"),\n",
+ " \"ratingCount\": details.get(\"userRatingCount\"),\n",
+ " \"priceLevel\": details.get(\"priceLevel\"),\n",
+ " \"googleMapsUrl\": details.get(\"googleMapsUri\"),\n",
+ " \"servesBreakfast\": details.get(\"servesBreakfast\"),\n",
+ " \"servesBrunch\": details.get(\"servesBrunch\"),\n",
+ " \"servesLunch\": details.get(\"servesLunch\"),\n",
+ " \"servesDinner\": details.get(\"servesDinner\"),\n",
+ " \"servesVegetarianFood\": details.get(\"servesVegetarianFood\"),\n",
+ " \"servesBeer\": details.get(\"servesBeer\"),\n",
+ " \"servesWine\": details.get(\"servesWine\"),\n",
+ " \"servesCocktails\": details.get(\"servesCocktails\"),\n",
+ " \"website\": details.get(\"websiteUri\"),\n",
+ " \"phone\": details.get(\"nationalPhoneNumber\"),\n",
+ " # 摘要拍平列\n",
+ " \"gen_overview\": g_overview,\n",
+ " \"editorial_text\": e_text,\n",
+ "}\n",
+ "\n",
+ "pd.DataFrame([row])"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 252
+ },
+ "id": "JSERwr6tOV2l",
+ "outputId": "4e77bbf1-26d7-43fb-87b8-cea9c8e3ac69"
+ },
+ "execution_count": 50,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ " id name lat \\\n",
+ "0 ChIJOa08KlqnlVQR_ZZx1jEcTYY Eem - Thai BBQ & Cocktails 45.55197 \n",
+ "\n",
+ " lng address \\\n",
+ "0 -122.675274 3808 N Williams Ave #127, Portland, OR 97227, USA \n",
+ "\n",
+ " primaryType types rating \\\n",
+ "0 thai_restaurant thai_restaurant, barbecue_restaurant, bar, res... 4.7 \n",
+ "\n",
+ " ratingCount priceLevel ... servesLunch servesDinner \\\n",
+ "0 2526 PRICE_LEVEL_MODERATE ... True True \n",
+ "\n",
+ " servesVegetarianFood servesBeer servesWine servesCocktails \\\n",
+ "0 True True True True \n",
+ "\n",
+ " website phone \\\n",
+ "0 http://www.eempdx.com/ (971) 295-1645 \n",
+ "\n",
+ " gen_overview \\\n",
+ "0 BBQ and Thai street fare, plus imaginative tro... \n",
+ "\n",
+ " editorial_text \n",
+ "0 Modern Thai eatery serving creative BBQ and cr... \n",
+ "\n",
+ "[1 rows x 23 columns]"
+ ],
+ "text/html": [
+ "\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " id | \n",
+ " name | \n",
+ " lat | \n",
+ " lng | \n",
+ " address | \n",
+ " primaryType | \n",
+ " types | \n",
+ " rating | \n",
+ " ratingCount | \n",
+ " priceLevel | \n",
+ " ... | \n",
+ " servesLunch | \n",
+ " servesDinner | \n",
+ " servesVegetarianFood | \n",
+ " servesBeer | \n",
+ " servesWine | \n",
+ " servesCocktails | \n",
+ " website | \n",
+ " phone | \n",
+ " gen_overview | \n",
+ " editorial_text | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " ChIJOa08KlqnlVQR_ZZx1jEcTYY | \n",
+ " Eem - Thai BBQ & Cocktails | \n",
+ " 45.55197 | \n",
+ " -122.675274 | \n",
+ " 3808 N Williams Ave #127, Portland, OR 97227, USA | \n",
+ " thai_restaurant | \n",
+ " thai_restaurant, barbecue_restaurant, bar, res... | \n",
+ " 4.7 | \n",
+ " 2526 | \n",
+ " PRICE_LEVEL_MODERATE | \n",
+ " ... | \n",
+ " True | \n",
+ " True | \n",
+ " True | \n",
+ " True | \n",
+ " True | \n",
+ " True | \n",
+ " http://www.eempdx.com/ | \n",
+ " (971) 295-1645 | \n",
+ " BBQ and Thai street fare, plus imaginative tro... | \n",
+ " Modern Thai eatery serving creative BBQ and cr... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
1 rows × 23 columns
\n",
+ "
\n",
+ "
\n",
+ "
\n"
+ ],
+ "application/vnd.google.colaboratory.intrinsic+json": {
+ "type": "dataframe"
+ }
+ },
+ "metadata": {},
+ "execution_count": 50
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
From 31ba2ebe1cceb64dda200a3b65c031d0370f345f Mon Sep 17 00:00:00 2001
From: ableyyyx <2724475986@qq.com>
Date: Thu, 11 Sep 2025 11:56:42 +0800
Subject: [PATCH 3/4] coarse get current location by Geolocation API
---
CallAPIs/Place_API_test.ipynb | 699 ++++++++++++++++++----------------
1 file changed, 381 insertions(+), 318 deletions(-)
diff --git a/CallAPIs/Place_API_test.ipynb b/CallAPIs/Place_API_test.ipynb
index cff8382..4b25756 100644
--- a/CallAPIs/Place_API_test.ipynb
+++ b/CallAPIs/Place_API_test.ipynb
@@ -1,38 +1,29 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
- "colab": {
- "provenance": []
- },
- "kernelspec": {
- "name": "python3",
- "display_name": "Python 3"
- },
- "language_info": {
- "name": "python"
- }
- },
"cells": [
{
"cell_type": "code",
- "execution_count": 45,
+ "execution_count": null,
"metadata": {
"id": "jOvvMS1NZnrB"
},
"outputs": [],
"source": [
"\n",
- "import os, getpass, requests, time\n",
+ "import os\n",
+ "import getpass\n",
+ "import requests\n",
+ "import time\n",
"from typing import Dict, Any, List\n",
"\n",
"# 安全地注入 API Key(建议在 GCP 控制台为 Places API 启用后再粘贴)\n",
"if \"GOOGLE_MAPS_API_KEY\" not in os.environ:\n",
- " os.environ[\"GOOGLE_MAPS_API_KEY\"] = getpass.getpass(\"请输入你的 Google Maps API Key(不可见): \")\n",
+ " os.environ[\"GOOGLE_MAPS_API_KEY\"] = getpass.getpass(\n",
+ " \"请输入你的 Google Maps API Key(不可见): \")\n",
"\n",
"API_KEY = os.environ[\"GOOGLE_MAPS_API_KEY\"]\n",
"BASE = \"https://places.googleapis.com/v1\"\n",
"\n",
+ "\n",
"def call_places(method: str, path: str, field_mask: str,\n",
" json_body: Dict[str, Any] | None = None,\n",
" params: Dict[str, Any] | None = None) -> Dict[str, Any]:\n",
@@ -43,26 +34,57 @@
" \"X-Goog-FieldMask\": field_mask, # 必须!否则报错\n",
" }\n",
" url = f\"{BASE}{path}\"\n",
- " resp = requests.request(method, url, headers=headers, json=json_body, params=params, timeout=30)\n",
+ " resp = requests.request(method, url, headers=headers,\n",
+ " json=json_body, params=params, timeout=30)\n",
" resp.raise_for_status()\n",
- " return resp.json()\n"
+ " return resp.json()"
]
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "ECWMXYJbaDEk"
+ },
"source": [
"#1.Nearby Search(指定点与半径找“餐厅”)\n",
"\n",
"• 仅支持 POST,请求体里写范围(圆形中心 + 半径)。\n",
"\n",
"• 示例字段掩码只拿到 ID、地理位置、地址、评分、价格等用于做餐厅画像的关键字段"
- ],
- "metadata": {
- "id": "ECWMXYJbaDEk"
- }
+ ]
},
{
"cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "CmP2rTXxZ1NO",
+ "outputId": "1251b758-da61-4b9c-e12e-dc0552f9a66e"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(20,\n",
+ " [{'id': 'ChIJOa08KlqnlVQR_ZZx1jEcTYY',\n",
+ " 'formattedAddress': '3808 N Williams Ave #127, Portland, OR 97227, USA',\n",
+ " 'location': {'latitude': 45.5506551, 'longitude': -122.66652119999998},\n",
+ " 'displayName': {'text': 'Eem - Thai BBQ & Cocktails',\n",
+ " 'languageCode': 'en'}},\n",
+ " {'id': 'ChIJU4OzoWynlVQRxlQMpGenSvA',\n",
+ " 'formattedAddress': '4237 N Mississippi Ave, Portland, OR 97217, USA',\n",
+ " 'location': {'latitude': 45.554515699999996,\n",
+ " 'longitude': -122.67573579999998},\n",
+ " 'displayName': {'text': 'Prost!', 'languageCode': 'en'}}])"
+ ]
+ },
+ "execution_count": 46,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"# 你可以换成自己的坐标与半径;这里示例:新加坡 Orchard Road 附近\n",
"center_lat, center_lng = 1.3049, 103.8318 # Orchard 附近\n",
@@ -97,74 +119,14 @@
" }\n",
"}\n",
"\n",
- "nearby = call_places(\"POST\", \"/places:searchNearby\", SEARCH_MASK_NEARBY, json_body=nearby_body)\n",
- "len(nearby.get(\"places\", [])), nearby.get(\"places\", [])[:2] # 看下总数与前两个示例\n"
- ],
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/"
- },
- "id": "CmP2rTXxZ1NO",
- "outputId": "1251b758-da61-4b9c-e12e-dc0552f9a66e"
- },
- "execution_count": 46,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- "(20,\n",
- " [{'id': 'ChIJOa08KlqnlVQR_ZZx1jEcTYY',\n",
- " 'formattedAddress': '3808 N Williams Ave #127, Portland, OR 97227, USA',\n",
- " 'location': {'latitude': 45.5506551, 'longitude': -122.66652119999998},\n",
- " 'displayName': {'text': 'Eem - Thai BBQ & Cocktails',\n",
- " 'languageCode': 'en'}},\n",
- " {'id': 'ChIJU4OzoWynlVQRxlQMpGenSvA',\n",
- " 'formattedAddress': '4237 N Mississippi Ave, Portland, OR 97217, USA',\n",
- " 'location': {'latitude': 45.554515699999996,\n",
- " 'longitude': -122.67573579999998},\n",
- " 'displayName': {'text': 'Prost!', 'languageCode': 'en'}}])"
- ]
- },
- "metadata": {},
- "execution_count": 46
- }
+ "nearby = call_places(\"POST\", \"/places:searchNearby\",\n",
+ " SEARCH_MASK_NEARBY, json_body=nearby_body)\n",
+ "len(nearby.get(\"places\", [])), nearby.get(\"places\", [])[:2] # 看下总数与前两个示例"
]
},
{
"cell_type": "code",
- "source": [
- "#可视化\n",
- "rows: List[Dict[str, Any]] = []\n",
- "for p in nearby.get(\"places\", []):\n",
- " # 注意:Nearby 返回的 location 可能是 {\"latitude\":..., \"longitude\":...}\n",
- " loc = p.get(\"location\") or {}\n",
- " # 生成式摘要(Search 侧路径:places.generativeSummary)\n",
- " gsum = p.get(\"generativeSummary\") or {}\n",
- " g_overview = ((gsum.get(\"overview\") or {}).get(\"text\")) if isinstance(gsum, dict) else None\n",
- " # 编辑摘要\n",
- " esum = p.get(\"editorialSummary\") or {}\n",
- " e_text = esum.get(\"text\") if isinstance(esum, dict) else None\n",
- "\n",
- " rows.append({\n",
- " \"id\": p.get(\"id\"),\n",
- " \"name\": (p.get(\"displayName\") or {}).get(\"text\"),\n",
- " \"lat\": loc.get(\"latitude\"),\n",
- " \"lng\": loc.get(\"longitude\"),\n",
- " \"address\": p.get(\"formattedAddress\"),\n",
- " # \"primaryType\": p.get(\"primaryType\"),\n",
- " # \"types\": \", \".join(p.get(\"types\", [])),\n",
- " # \"rating\": p.get(\"rating\"),\n",
- " # \"ratingCount\": p.get(\"userRatingCount\"),\n",
- " # \"priceLevel\": p.get(\"priceLevel\"),\n",
- " # \"googleMapsUrl\": p.get(\"googleMapsUri\"),\n",
- " # 摘要拍平列\n",
- " # \"genOverview\": g_overview,\n",
- " # \"editorialText\": e_text,\n",
- " })\n",
- "\n",
- "pd.DataFrame(rows)"
- ],
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -173,78 +135,13 @@
"id": "BUlQllHuMUAV",
"outputId": "f0a0ef7f-59f1-4200-bd76-52d33893a5d9"
},
- "execution_count": 47,
"outputs": [
{
- "output_type": "execute_result",
"data": {
- "text/plain": [
- " id \\\n",
- "0 ChIJOa08KlqnlVQR_ZZx1jEcTYY \n",
- "1 ChIJU4OzoWynlVQRxlQMpGenSvA \n",
- "2 ChIJIxfmG0KnlVQR3ZPSgF46ahE \n",
- "3 ChIJeaQuoUeFhVQR5k_yPdK_gvk \n",
- "4 ChIJL9S2VWmnlVQRUhyawDjpzjY \n",
- "5 ChIJT9ZbCWunlVQRIryTTXOWkEw \n",
- "6 ChIJb1BVEBenlVQRWQZoL6tdhpw \n",
- "7 ChIJr8AyrWunlVQR_w411-qtqkw \n",
- "8 ChIJ9SRcAkKnlVQRU2wR1eFxEew \n",
- "9 ChIJzQfQ8b2hlVQRz8RLZLvD_ps \n",
- "10 ChIJUe0ZJGynlVQRj5j7YnzeHwc \n",
- "11 ChIJX9VXlj-nlVQRnJy2Up4d58Q \n",
- "12 ChIJC3JflEOnlVQRTgXBnXO_Pto \n",
- "13 ChIJ3TR1jQ2nlVQRo0XThDocw_w \n",
- "14 ChIJj-0nJrSnlVQRLAkmEOu3DI0 \n",
- "15 ChIJTzIkE1WnlVQR8UCJX2Clmmg \n",
- "16 ChIJXaSbYjinlVQR8dLXhKW654Y \n",
- "17 ChIJ8-KumFqnlVQRyTdcK1RP-Vc \n",
- "18 ChIJ5feGCGqnlVQRV2Lc8MyL8e0 \n",
- "19 ChIJHXqQqmunlVQRSyFCcmcf3AU \n",
- "\n",
- " name lat lng \\\n",
- "0 Eem - Thai BBQ & Cocktails 45.550655 -122.666521 \n",
- "1 Prost! 45.554516 -122.675736 \n",
- "2 ¿Por Qué No? 45.548156 -122.675325 \n",
- "3 Cafe Olli 45.551158 -122.661911 \n",
- "4 The Alibi Tiki Lounge 45.552537 -122.680687 \n",
- "5 Lovely's Fifty Fifty 45.552860 -122.675850 \n",
- "6 Matt's BBQ 45.554346 -122.675788 \n",
- "7 Gravy 45.551708 -122.675706 \n",
- "8 Mississippi Pizza & Atlantis Lounge 45.548614 -122.675199 \n",
- "9 Kate's Ice Cream 45.549804 -122.675777 \n",
- "10 Fire On the Mountain Buffalo Wings | Interstate 45.554035 -122.681788 \n",
- "11 Kayo's Ramen Bar 45.550278 -122.666389 \n",
- "12 Matador North Portland 45.553413 -122.666966 \n",
- "13 Sweedeedee 45.560571 -122.674873 \n",
- "14 Churn Cafe 45.551343 -122.675179 \n",
- "15 Migration Brewing x Pápa's Frita - Williams 45.551351 -122.666898 \n",
- "16 Popeyes Louisiana Kitchen 45.545798 -122.661322 \n",
- "17 Broder Nord 45.550212 -122.675691 \n",
- "18 StormBreaker Brewing 45.549428 -122.675145 \n",
- "19 The 1905 45.551970 -122.675274 \n",
- "\n",
- " address \n",
- "0 3808 N Williams Ave #127, Portland, OR 97227, USA \n",
- "1 4237 N Mississippi Ave, Portland, OR 97217, USA \n",
- "2 3524 N Mississippi Ave, Portland, OR 97227, USA \n",
- "3 3925 NE Martin Luther King Jr Blvd, Portland, ... \n",
- "4 4024 N Interstate Ave, Portland, OR 97227, USA \n",
- "5 4039 N Mississippi Ave, Portland, OR 97217, USA \n",
- "6 4233 N Mississippi Ave, Portland, OR 97217, USA \n",
- "7 3957 N Mississippi Ave, Portland, OR 97227, USA \n",
- "8 3552 N Mississippi Ave, Portland, OR 97227, USA \n",
- "9 3713 N Mississippi Ave, Portland, OR 97227, USA \n",
- "10 4225 N Interstate Ave, Portland, OR 97217, USA \n",
- "11 3808 N Williams Ave # 124, Portland, OR 97227,... \n",
- "12 4111 N Williams Ave, Portland, OR 97217, USA \n",
- "13 5202 N Albina Ave, Portland, OR 97217, USA \n",
- "14 3928 N Mississippi Ave, Portland, OR 97227, USA \n",
- "15 3947 N Williams Ave, Portland, OR 97227, USA \n",
- "16 3120 NE Martin Luther King Jr Blvd, Portland, ... \n",
- "17 3765 N Mississippi Ave, Portland, OR 97227, USA \n",
- "18 832 N Beech St, Portland, OR 97227, USA \n",
- "19 830 N Shaver St, Portland, OR 97227, USA "
- ],
+ "application/vnd.google.colaboratory.intrinsic+json": {
+ "summary": "{\n \"name\": \"pd\",\n \"rows\": 20,\n \"fields\": [\n {\n \"column\": \"id\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"ChIJOa08KlqnlVQR_ZZx1jEcTYY\",\n \"ChIJ8-KumFqnlVQRyTdcK1RP-Vc\",\n \"ChIJTzIkE1WnlVQR8UCJX2Clmmg\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"name\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"Eem - Thai BBQ & Cocktails\",\n \"Broder Nord\",\n \"Migration Brewing x P\\u00e1pa's Frita - Williams\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"lat\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.003040066899277008,\n \"min\": 45.545797799999995,\n \"max\": 45.5605707,\n \"num_unique_values\": 20,\n \"samples\": [\n 45.5506551,\n 45.5502118,\n 45.551350799999994\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"lng\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.005752372433270196,\n \"min\": -122.68178839999999,\n \"max\": -122.66132239999997,\n \"num_unique_values\": 20,\n \"samples\": [\n -122.66652119999998,\n -122.67569069999999,\n -122.66689849999999\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"address\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"3808 N Williams Ave #127, Portland, OR 97227, USA\",\n \"3765 N Mississippi Ave, Portland, OR 97227, USA\",\n \"3947 N Williams Ave, Portland, OR 97227, USA\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}",
+ "type": "dataframe"
+ },
"text/html": [
"\n",
" \n",
@@ -647,34 +544,150 @@
"
\n",
" \n"
],
- "application/vnd.google.colaboratory.intrinsic+json": {
- "type": "dataframe",
- "summary": "{\n \"name\": \"pd\",\n \"rows\": 20,\n \"fields\": [\n {\n \"column\": \"id\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"ChIJOa08KlqnlVQR_ZZx1jEcTYY\",\n \"ChIJ8-KumFqnlVQRyTdcK1RP-Vc\",\n \"ChIJTzIkE1WnlVQR8UCJX2Clmmg\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"name\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"Eem - Thai BBQ & Cocktails\",\n \"Broder Nord\",\n \"Migration Brewing x P\\u00e1pa's Frita - Williams\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"lat\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.003040066899277008,\n \"min\": 45.545797799999995,\n \"max\": 45.5605707,\n \"num_unique_values\": 20,\n \"samples\": [\n 45.5506551,\n 45.5502118,\n 45.551350799999994\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"lng\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.005752372433270196,\n \"min\": -122.68178839999999,\n \"max\": -122.66132239999997,\n \"num_unique_values\": 20,\n \"samples\": [\n -122.66652119999998,\n -122.67569069999999,\n -122.66689849999999\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"address\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 20,\n \"samples\": [\n \"3808 N Williams Ave #127, Portland, OR 97227, USA\",\n \"3765 N Mississippi Ave, Portland, OR 97227, USA\",\n \"3947 N Williams Ave, Portland, OR 97227, USA\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
- }
+ "text/plain": [
+ " id \\\n",
+ "0 ChIJOa08KlqnlVQR_ZZx1jEcTYY \n",
+ "1 ChIJU4OzoWynlVQRxlQMpGenSvA \n",
+ "2 ChIJIxfmG0KnlVQR3ZPSgF46ahE \n",
+ "3 ChIJeaQuoUeFhVQR5k_yPdK_gvk \n",
+ "4 ChIJL9S2VWmnlVQRUhyawDjpzjY \n",
+ "5 ChIJT9ZbCWunlVQRIryTTXOWkEw \n",
+ "6 ChIJb1BVEBenlVQRWQZoL6tdhpw \n",
+ "7 ChIJr8AyrWunlVQR_w411-qtqkw \n",
+ "8 ChIJ9SRcAkKnlVQRU2wR1eFxEew \n",
+ "9 ChIJzQfQ8b2hlVQRz8RLZLvD_ps \n",
+ "10 ChIJUe0ZJGynlVQRj5j7YnzeHwc \n",
+ "11 ChIJX9VXlj-nlVQRnJy2Up4d58Q \n",
+ "12 ChIJC3JflEOnlVQRTgXBnXO_Pto \n",
+ "13 ChIJ3TR1jQ2nlVQRo0XThDocw_w \n",
+ "14 ChIJj-0nJrSnlVQRLAkmEOu3DI0 \n",
+ "15 ChIJTzIkE1WnlVQR8UCJX2Clmmg \n",
+ "16 ChIJXaSbYjinlVQR8dLXhKW654Y \n",
+ "17 ChIJ8-KumFqnlVQRyTdcK1RP-Vc \n",
+ "18 ChIJ5feGCGqnlVQRV2Lc8MyL8e0 \n",
+ "19 ChIJHXqQqmunlVQRSyFCcmcf3AU \n",
+ "\n",
+ " name lat lng \\\n",
+ "0 Eem - Thai BBQ & Cocktails 45.550655 -122.666521 \n",
+ "1 Prost! 45.554516 -122.675736 \n",
+ "2 ¿Por Qué No? 45.548156 -122.675325 \n",
+ "3 Cafe Olli 45.551158 -122.661911 \n",
+ "4 The Alibi Tiki Lounge 45.552537 -122.680687 \n",
+ "5 Lovely's Fifty Fifty 45.552860 -122.675850 \n",
+ "6 Matt's BBQ 45.554346 -122.675788 \n",
+ "7 Gravy 45.551708 -122.675706 \n",
+ "8 Mississippi Pizza & Atlantis Lounge 45.548614 -122.675199 \n",
+ "9 Kate's Ice Cream 45.549804 -122.675777 \n",
+ "10 Fire On the Mountain Buffalo Wings | Interstate 45.554035 -122.681788 \n",
+ "11 Kayo's Ramen Bar 45.550278 -122.666389 \n",
+ "12 Matador North Portland 45.553413 -122.666966 \n",
+ "13 Sweedeedee 45.560571 -122.674873 \n",
+ "14 Churn Cafe 45.551343 -122.675179 \n",
+ "15 Migration Brewing x Pápa's Frita - Williams 45.551351 -122.666898 \n",
+ "16 Popeyes Louisiana Kitchen 45.545798 -122.661322 \n",
+ "17 Broder Nord 45.550212 -122.675691 \n",
+ "18 StormBreaker Brewing 45.549428 -122.675145 \n",
+ "19 The 1905 45.551970 -122.675274 \n",
+ "\n",
+ " address \n",
+ "0 3808 N Williams Ave #127, Portland, OR 97227, USA \n",
+ "1 4237 N Mississippi Ave, Portland, OR 97217, USA \n",
+ "2 3524 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "3 3925 NE Martin Luther King Jr Blvd, Portland, ... \n",
+ "4 4024 N Interstate Ave, Portland, OR 97227, USA \n",
+ "5 4039 N Mississippi Ave, Portland, OR 97217, USA \n",
+ "6 4233 N Mississippi Ave, Portland, OR 97217, USA \n",
+ "7 3957 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "8 3552 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "9 3713 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "10 4225 N Interstate Ave, Portland, OR 97217, USA \n",
+ "11 3808 N Williams Ave # 124, Portland, OR 97227,... \n",
+ "12 4111 N Williams Ave, Portland, OR 97217, USA \n",
+ "13 5202 N Albina Ave, Portland, OR 97217, USA \n",
+ "14 3928 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "15 3947 N Williams Ave, Portland, OR 97227, USA \n",
+ "16 3120 NE Martin Luther King Jr Blvd, Portland, ... \n",
+ "17 3765 N Mississippi Ave, Portland, OR 97227, USA \n",
+ "18 832 N Beech St, Portland, OR 97227, USA \n",
+ "19 830 N Shaver St, Portland, OR 97227, USA "
+ ]
},
+ "execution_count": 47,
"metadata": {},
- "execution_count": 47
+ "output_type": "execute_result"
}
- ]
- },
- {
- "cell_type": "markdown",
- "source": [
- "#2.Text Search(关键词 + 区域偏置)\n",
- "\n",
- "• POST 到 places:searchText,textQuery 可以写 “sushi near orchard road singapore”。\n",
- "\n",
- "• pageSize 控制每页数量;响应里若返回 nextPageToken,用它继续翻页(放在请求体的 pageToken 字段)。\n"
],
- "metadata": {
- "id": "tSOzZZniahS-"
- }
- },
- {
- "cell_type": "code",
"source": [
- "# Text Search 字段掩码:与 Nearby 类似,但加入 nextPageToken 以便分页\n",
- "SEARCH_MASK_TEXT = \",\".join([\n",
+ "# 可视化\n",
+ "rows: List[Dict[str, Any]] = []\n",
+ "for p in nearby.get(\"places\", []):\n",
+ " # 注意:Nearby 返回的 location 可能是 {\"latitude\":..., \"longitude\":...}\n",
+ " loc = p.get(\"location\") or {}\n",
+ " # 生成式摘要(Search 侧路径:places.generativeSummary)\n",
+ " gsum = p.get(\"generativeSummary\") or {}\n",
+ " g_overview = ((gsum.get(\"overview\") or {}).get(\n",
+ " \"text\")) if isinstance(gsum, dict) else None\n",
+ " # 编辑摘要\n",
+ " esum = p.get(\"editorialSummary\") or {}\n",
+ " e_text = esum.get(\"text\") if isinstance(esum, dict) else None\n",
+ "\n",
+ " rows.append({\n",
+ " \"id\": p.get(\"id\"),\n",
+ " \"name\": (p.get(\"displayName\") or {}).get(\"text\"),\n",
+ " \"lat\": loc.get(\"latitude\"),\n",
+ " \"lng\": loc.get(\"longitude\"),\n",
+ " \"address\": p.get(\"formattedAddress\"),\n",
+ " # \"primaryType\": p.get(\"primaryType\"),\n",
+ " # \"types\": \", \".join(p.get(\"types\", [])),\n",
+ " # \"rating\": p.get(\"rating\"),\n",
+ " # \"ratingCount\": p.get(\"userRatingCount\"),\n",
+ " # \"priceLevel\": p.get(\"priceLevel\"),\n",
+ " # \"googleMapsUrl\": p.get(\"googleMapsUri\"),\n",
+ " # 摘要拍平列\n",
+ " # \"genOverview\": g_overview,\n",
+ " # \"editorialText\": e_text,\n",
+ " })\n",
+ "\n",
+ "pd.DataFrame(rows)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "tSOzZZniahS-"
+ },
+ "source": [
+ "#2.Text Search(关键词 + 区域偏置)\n",
+ "\n",
+ "• POST 到 places:searchText,textQuery 可以写 “sushi near orchard road singapore”。\n",
+ "\n",
+ "• pageSize 控制每页数量;响应里若返回 nextPageToken,用它继续翻页(放在请求体的 pageToken 字段)。\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "xDAtX-aTakoi",
+ "outputId": "ef4f0e54-5049-4378-d9ff-4aaa892401a8"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "第一页条数: 10\n",
+ "是否可翻页: True\n",
+ "第二页条数: 10\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Text Search 字段掩码:与 Nearby 类似,但加入 nextPageToken 以便分页\n",
+ "SEARCH_MASK_TEXT = \",\".join([\n",
" \"places.id\",\n",
" \"places.displayName\",\n",
" \"places.location\",\n",
@@ -701,7 +714,8 @@
" \"pageSize\": 10\n",
"}\n",
"\n",
- "page1 = call_places(\"POST\", \"/places:searchText\", SEARCH_MASK_TEXT, json_body=text_body)\n",
+ "page1 = call_places(\"POST\", \"/places:searchText\",\n",
+ " SEARCH_MASK_TEXT, json_body=text_body)\n",
"print(\"第一页条数:\", len(page1.get(\"places\", [])))\n",
"print(\"是否可翻页:\", \"nextPageToken\" in page1)\n",
"\n",
@@ -711,79 +725,26 @@
" text_body2 = {**text_body, \"pageToken\": page1[\"nextPageToken\"]}\n",
" # 按官方示例,翻页前稍等一小会儿更稳妥\n",
" time.sleep(1.2)\n",
- " page2 = call_places(\"POST\", \"/places:searchText\", SEARCH_MASK_TEXT, json_body=text_body2)\n",
- " print(\"第二页条数:\", len(page2.get(\"places\", [])))\n"
- ],
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/"
- },
- "id": "xDAtX-aTakoi",
- "outputId": "ef4f0e54-5049-4378-d9ff-4aaa892401a8"
- },
- "execution_count": 48,
- "outputs": [
- {
- "output_type": "stream",
- "name": "stdout",
- "text": [
- "第一页条数: 10\n",
- "是否可翻页: True\n",
- "第二页条数: 10\n"
- ]
- }
+ " page2 = call_places(\"POST\", \"/places:searchText\",\n",
+ " SEARCH_MASK_TEXT, json_body=text_body2)\n",
+ " print(\"第二页条数:\", len(page2.get(\"places\", [])))"
]
},
{
"cell_type": "markdown",
+ "metadata": {
+ "id": "ZgDRJD4gbO6t"
+ },
"source": [
"#3.Place Details(对单个餐厅补充细节)\n",
"\n",
"• GET 到 /v1/places/{PLACE_ID},同样必须带 FieldMask。\n",
"• 支持补充电话、网站、营业时间、评分/价位等(不同字段触发不同 SKU)"
- ],
- "metadata": {
- "id": "ZgDRJD4gbO6t"
- }
+ ]
},
{
"cell_type": "code",
- "source": [
- "# 拿 Nearby 或 Text Search 的第一个结果做示例\n",
- "any_place_id = (nearby.get(\"places\") or page1.get(\"places\") or page2.get(\"places\"))[0][\"id\"]\n",
- "\n",
- "DETAILS_MASK = \",\".join([\n",
- " # 注意:Place Details 的字段掩码是 Place 对象顶层,不再以 \"places.\" 起头!\n",
- " \"id\",\n",
- " \"displayName\",\n",
- " \"location\",\n",
- " \"formattedAddress\",\n",
- " \"primaryType\",\n",
- " \"types\",\n",
- " \"rating\",\n",
- " \"userRatingCount\",\n",
- " \"priceLevel\",\n",
- " \"websiteUri\",\n",
- " \"nationalPhoneNumber\",\n",
- " \"currentOpeningHours\",\n",
- " \"googleMapsUri\",\n",
- " # 两类摘要\n",
- " \"editorialSummary\",\n",
- " \"generativeSummary\",\n",
- " # 一些“场景/服务”标签(可用于画像增强)\n",
- " \"servesBreakfast\",\n",
- " \"servesBrunch\",\n",
- " \"servesLunch\",\n",
- " \"servesDinner\",\n",
- " \"servesVegetarianFood\",\n",
- " \"servesBeer\",\n",
- " \"servesWine\",\n",
- " \"servesCocktails\",\n",
- "])\n",
- "\n",
- "details = call_places(\"GET\", f\"/places/{any_place_id}\", DETAILS_MASK)\n",
- "details\n"
- ],
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
@@ -791,10 +752,8 @@
"id": "Xn0NtIzsbS-b",
"outputId": "dc682463-7efc-40b9-a89f-b044b53a7672"
},
- "execution_count": 49,
"outputs": [
{
- "output_type": "execute_result",
"data": {
"text/plain": [
"{'id': 'ChIJOa08KlqnlVQR_ZZx1jEcTYY',\n",
@@ -897,52 +856,52 @@
" 'languageCode': 'en-US'}}}"
]
},
+ "execution_count": 49,
"metadata": {},
- "execution_count": 49
+ "output_type": "execute_result"
}
+ ],
+ "source": [
+ "# 拿 Nearby 或 Text Search 的第一个结果做示例\n",
+ "any_place_id = (nearby.get(\"places\") or page1.get(\n",
+ " \"places\") or page2.get(\"places\"))[0][\"id\"]\n",
+ "\n",
+ "DETAILS_MASK = \",\".join([\n",
+ " # 注意:Place Details 的字段掩码是 Place 对象顶层,不再以 \"places.\" 起头!\n",
+ " \"id\",\n",
+ " \"displayName\",\n",
+ " \"location\",\n",
+ " \"formattedAddress\",\n",
+ " \"primaryType\",\n",
+ " \"types\",\n",
+ " \"rating\",\n",
+ " \"userRatingCount\",\n",
+ " \"priceLevel\",\n",
+ " \"websiteUri\",\n",
+ " \"nationalPhoneNumber\",\n",
+ " \"currentOpeningHours\",\n",
+ " \"googleMapsUri\",\n",
+ " # 两类摘要\n",
+ " \"editorialSummary\",\n",
+ " \"generativeSummary\",\n",
+ " # 一些“场景/服务”标签(可用于画像增强)\n",
+ " \"servesBreakfast\",\n",
+ " \"servesBrunch\",\n",
+ " \"servesLunch\",\n",
+ " \"servesDinner\",\n",
+ " \"servesVegetarianFood\",\n",
+ " \"servesBeer\",\n",
+ " \"servesWine\",\n",
+ " \"servesCocktails\",\n",
+ "])\n",
+ "\n",
+ "details = call_places(\"GET\", f\"/places/{any_place_id}\", DETAILS_MASK)\n",
+ "details"
]
},
{
"cell_type": "code",
- "source": [
- "loc = p.get(\"location\") or {}\n",
- "\n",
- "gsum = details.get(\"generativeSummary\") or {}\n",
- "g_overview = ((gsum.get(\"overview\") or {}).get(\"text\")) if isinstance(gsum, dict) else None\n",
- "\n",
- "esum = details.get(\"editorialSummary\") or {}\n",
- "e_text = esum.get(\"text\") if isinstance(esum, dict) else None\n",
- "\n",
- "\n",
- "row = {\n",
- " \"id\": details.get(\"id\"),\n",
- " \"name\": (details.get(\"displayName\") or {}).get(\"text\"),\n",
- " \"lat\": loc.get(\"latitude\"),\n",
- " \"lng\": loc.get(\"longitude\"),\n",
- " \"address\": details.get(\"formattedAddress\"),\n",
- " \"primaryType\": details.get(\"primaryType\"),\n",
- " \"types\": \", \".join(details.get(\"types\", [])),\n",
- " \"rating\": details.get(\"rating\"),\n",
- " \"ratingCount\": details.get(\"userRatingCount\"),\n",
- " \"priceLevel\": details.get(\"priceLevel\"),\n",
- " \"googleMapsUrl\": details.get(\"googleMapsUri\"),\n",
- " \"servesBreakfast\": details.get(\"servesBreakfast\"),\n",
- " \"servesBrunch\": details.get(\"servesBrunch\"),\n",
- " \"servesLunch\": details.get(\"servesLunch\"),\n",
- " \"servesDinner\": details.get(\"servesDinner\"),\n",
- " \"servesVegetarianFood\": details.get(\"servesVegetarianFood\"),\n",
- " \"servesBeer\": details.get(\"servesBeer\"),\n",
- " \"servesWine\": details.get(\"servesWine\"),\n",
- " \"servesCocktails\": details.get(\"servesCocktails\"),\n",
- " \"website\": details.get(\"websiteUri\"),\n",
- " \"phone\": details.get(\"nationalPhoneNumber\"),\n",
- " # 摘要拍平列\n",
- " \"gen_overview\": g_overview,\n",
- " \"editorial_text\": e_text,\n",
- "}\n",
- "\n",
- "pd.DataFrame([row])"
- ],
+ "execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
@@ -951,38 +910,12 @@
"id": "JSERwr6tOV2l",
"outputId": "4e77bbf1-26d7-43fb-87b8-cea9c8e3ac69"
},
- "execution_count": 50,
"outputs": [
{
- "output_type": "execute_result",
"data": {
- "text/plain": [
- " id name lat \\\n",
- "0 ChIJOa08KlqnlVQR_ZZx1jEcTYY Eem - Thai BBQ & Cocktails 45.55197 \n",
- "\n",
- " lng address \\\n",
- "0 -122.675274 3808 N Williams Ave #127, Portland, OR 97227, USA \n",
- "\n",
- " primaryType types rating \\\n",
- "0 thai_restaurant thai_restaurant, barbecue_restaurant, bar, res... 4.7 \n",
- "\n",
- " ratingCount priceLevel ... servesLunch servesDinner \\\n",
- "0 2526 PRICE_LEVEL_MODERATE ... True True \n",
- "\n",
- " servesVegetarianFood servesBeer servesWine servesCocktails \\\n",
- "0 True True True True \n",
- "\n",
- " website phone \\\n",
- "0 http://www.eempdx.com/ (971) 295-1645 \n",
- "\n",
- " gen_overview \\\n",
- "0 BBQ and Thai street fare, plus imaginative tro... \n",
- "\n",
- " editorial_text \n",
- "0 Modern Thai eatery serving creative BBQ and cr... \n",
- "\n",
- "[1 rows x 23 columns]"
- ],
+ "application/vnd.google.colaboratory.intrinsic+json": {
+ "type": "dataframe"
+ },
"text/html": [
"\n",
" \n",
@@ -1139,14 +1072,144 @@
"
\n",
" \n"
],
- "application/vnd.google.colaboratory.intrinsic+json": {
- "type": "dataframe"
- }
+ "text/plain": [
+ " id name lat \\\n",
+ "0 ChIJOa08KlqnlVQR_ZZx1jEcTYY Eem - Thai BBQ & Cocktails 45.55197 \n",
+ "\n",
+ " lng address \\\n",
+ "0 -122.675274 3808 N Williams Ave #127, Portland, OR 97227, USA \n",
+ "\n",
+ " primaryType types rating \\\n",
+ "0 thai_restaurant thai_restaurant, barbecue_restaurant, bar, res... 4.7 \n",
+ "\n",
+ " ratingCount priceLevel ... servesLunch servesDinner \\\n",
+ "0 2526 PRICE_LEVEL_MODERATE ... True True \n",
+ "\n",
+ " servesVegetarianFood servesBeer servesWine servesCocktails \\\n",
+ "0 True True True True \n",
+ "\n",
+ " website phone \\\n",
+ "0 http://www.eempdx.com/ (971) 295-1645 \n",
+ "\n",
+ " gen_overview \\\n",
+ "0 BBQ and Thai street fare, plus imaginative tro... \n",
+ "\n",
+ " editorial_text \n",
+ "0 Modern Thai eatery serving creative BBQ and cr... \n",
+ "\n",
+ "[1 rows x 23 columns]"
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "loc = p.get(\"location\") or {}\n",
+ "\n",
+ "gsum = details.get(\"generativeSummary\") or {}\n",
+ "g_overview = ((gsum.get(\"overview\") or {}).get(\n",
+ " \"text\")) if isinstance(gsum, dict) else None\n",
+ "\n",
+ "esum = details.get(\"editorialSummary\") or {}\n",
+ "e_text = esum.get(\"text\") if isinstance(esum, dict) else None\n",
+ "\n",
+ "\n",
+ "row = {\n",
+ " \"id\": details.get(\"id\"),\n",
+ " \"name\": (details.get(\"displayName\") or {}).get(\"text\"),\n",
+ " \"lat\": loc.get(\"latitude\"),\n",
+ " \"lng\": loc.get(\"longitude\"),\n",
+ " \"address\": details.get(\"formattedAddress\"),\n",
+ " \"primaryType\": details.get(\"primaryType\"),\n",
+ " \"types\": \", \".join(details.get(\"types\", [])),\n",
+ " \"rating\": details.get(\"rating\"),\n",
+ " \"ratingCount\": details.get(\"userRatingCount\"),\n",
+ " \"priceLevel\": details.get(\"priceLevel\"),\n",
+ " \"googleMapsUrl\": details.get(\"googleMapsUri\"),\n",
+ " \"servesBreakfast\": details.get(\"servesBreakfast\"),\n",
+ " \"servesBrunch\": details.get(\"servesBrunch\"),\n",
+ " \"servesLunch\": details.get(\"servesLunch\"),\n",
+ " \"servesDinner\": details.get(\"servesDinner\"),\n",
+ " \"servesVegetarianFood\": details.get(\"servesVegetarianFood\"),\n",
+ " \"servesBeer\": details.get(\"servesBeer\"),\n",
+ " \"servesWine\": details.get(\"servesWine\"),\n",
+ " \"servesCocktails\": details.get(\"servesCocktails\"),\n",
+ " \"website\": details.get(\"websiteUri\"),\n",
+ " \"phone\": details.get(\"nationalPhoneNumber\"),\n",
+ " # 摘要拍平列\n",
+ " \"gen_overview\": g_overview,\n",
+ " \"editorial_text\": e_text,\n",
+ "}\n",
+ "\n",
+ "pd.DataFrame([row])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'lat': 1.2987599, 'lng': 103.7832421, 'accuracy_m': 3020.9490956552268}"
+ ]
},
+ "execution_count": 7,
"metadata": {},
- "execution_count": 50
+ "output_type": "execute_result"
}
+ ],
+ "source": [
+ "GEOLOCATION_URL = \"https://www.googleapis.com/geolocation/v1/geolocate\"\n",
+ "\n",
+ "\n",
+ "def get_current_location_via_geolocation_api(consider_ip: bool = True):\n",
+ " \"\"\"\n",
+ " 使用 Google Geolocation API 估算当前位置。\n",
+ " - 仅传 considerIp 时:精度≈城市级(依赖 IP)\n",
+ " - 若你在移动端/前端收集到 wifiAccessPoints/cellTowers,可附带提交以提升精度\n",
+ " (Colab/后端通常拿不到这些数据)\n",
+ " \"\"\"\n",
+ " params = {\"key\": API_KEY}\n",
+ " payload = {\"considerIp\": consider_ip}\n",
+ " r = requests.post(GEOLOCATION_URL, params=params, json=payload, timeout=15)\n",
+ " r.raise_for_status()\n",
+ " data = r.json()\n",
+ " # 返回形如 {\"location\":{\"lat\":..,\"lng\":..}, \"accuracy\":..}\n",
+ " loc = data.get(\"location\", {})\n",
+ " return {\"lat\": loc.get(\"lat\"), \"lng\": loc.get(\"lng\"), \"accuracy_m\": data.get(\"accuracy\")}\n",
+ "\n",
+ "\n",
+ "location = get_current_location_via_geolocation_api(consider_ip=True)\n",
+ "location"
]
}
- ]
-}
\ No newline at end of file
+ ],
+ "metadata": {
+ "colab": {
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "asd",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.23"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
From a870e4f031a7beb18114c4223fc3a579feb0ad20 Mon Sep 17 00:00:00 2001
From: Mia
Date: Thu, 11 Sep 2025 14:30:58 +0800
Subject: [PATCH 4/4] Youtube check channel API
---
CallAPIs/YouTube_API_test.ipynb | 820 ++++++++++++++++++++++++++++++++
1 file changed, 820 insertions(+)
create mode 100644 CallAPIs/YouTube_API_test.ipynb
diff --git a/CallAPIs/YouTube_API_test.ipynb b/CallAPIs/YouTube_API_test.ipynb
new file mode 100644
index 0000000..498e466
--- /dev/null
+++ b/CallAPIs/YouTube_API_test.ipynb
@@ -0,0 +1,820 @@
+{
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "provenance": []
+ },
+ "kernelspec": {
+ "name": "python3",
+ "display_name": "Python 3"
+ },
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "cells": [
+ {
+ "cell_type": "code",
+ "source": [
+ "!pip -q install --upgrade google-auth-oauthlib google-api-python-client pandas\n",
+ "import importlib.metadata as im, glob, os\n",
+ "print(\"google-auth-oauthlib =\", im.version(\"google-auth-oauthlib\"))\n",
+ "print(\"google-api-python-client =\", im.version(\"google-api-python-client\"))\n",
+ "print(\"client_secret present:\", bool(glob.glob(\"client_secret.json\")))\n"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "JJwRB6SVZa7t",
+ "outputId": "8c3104ca-2a16-4861-e025-623686a20d09"
+ },
+ "execution_count": 8,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "google-auth-oauthlib = 1.2.2\n",
+ "google-api-python-client = 2.181.0\n",
+ "client_secret present: True\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "from urllib.parse import urlparse, parse_qs\n",
+ "from google_auth_oauthlib.flow import InstalledAppFlow\n",
+ "from googleapiclient.discovery import build\n",
+ "from google.oauth2.credentials import Credentials\n",
+ "from google.auth.transport.requests import Request\n",
+ "from googleapiclient.errors import HttpError\n",
+ "import os, json\n",
+ "\n",
+ "SCOPES = [\"https://www.googleapis.com/auth/youtube.readonly\"]\n",
+ "TOKEN_PATH = \"token.json\"\n",
+ "\n",
+ "def get_youtube_via_loopback_copy(scopes=SCOPES, token_path=TOKEN_PATH):\n",
+ " creds = None\n",
+ " if os.path.exists(token_path):\n",
+ " creds = Credentials.from_authorized_user_file(token_path, scopes)\n",
+ "\n",
+ " if not creds or not creds.valid:\n",
+ " if creds and creds.expired and creds.refresh_token:\n",
+ " creds.refresh(Request())\n",
+ " else:\n",
+ " flow = InstalledAppFlow.from_client_secrets_file(\"client_secret.json\", scopes)\n",
+ " flow.redirect_uri = \"http://localhost:8080/\" # 关键:显式设置 redirect_uri\n",
+ " auth_url, _ = flow.authorization_url(\n",
+ " access_type=\"offline\",\n",
+ " include_granted_scopes=\"true\",\n",
+ " prompt=\"consent\",\n",
+ " )\n",
+ " print(\"在浏览器打开并完成授权:\\n\", auth_url)\n",
+ " redirect_response = input(\"\\n授权完成后,把【浏览器地址栏的完整重定向URL】粘贴到此处:\\n\").strip()\n",
+ " try:\n",
+ " code = parse_qs(urlparse(redirect_response).query)[\"code\"][0]\n",
+ " except Exception:\n",
+ " code = redirect_response # 允许只粘 code\n",
+ " flow.fetch_token(code=code)\n",
+ " creds = flow.credentials\n",
+ " with open(token_path, \"w\") as f:\n",
+ " f.write(creds.to_json())\n",
+ "\n",
+ " return build(\"youtube\", \"v3\", credentials=creds)\n",
+ "\n",
+ "def get_my_channel_id_safe(yt):\n",
+ " \"\"\"安全获取频道ID,避免 KeyError,并在失败时给出清晰提示。\"\"\"\n",
+ " try:\n",
+ " resp = yt.channels().list(part=\"id\", mine=True, fields=\"items(id)\").execute()\n",
+ " except HttpError as e:\n",
+ " print(\"YouTube API error:\", e)\n",
+ " return None\n",
+ " items = resp.get(\"items\", [])\n",
+ " if not items:\n",
+ " print(\"⚠️ 当前账号没有 YouTube 频道或无权限。请先在网页端创建频道,然后删除 token.json 重新授权。\")\n",
+ " return None\n",
+ " return items[0][\"id\"]\n",
+ "\n",
+ "yt = get_youtube_via_loopback_copy()\n",
+ "my_channel_id = get_my_channel_id_safe(yt)\n",
+ "print(\"My channel id:\", my_channel_id)\n"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "collapsed": true,
+ "id": "BAKptGQFavIi",
+ "outputId": "0032cee1-38b8-423a-b8ae-c4a805923b01"
+ },
+ "execution_count": 9,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "My channel id: UCMj60L5aE0ZsIi8fmroy_fg\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "def list_my_subscriptions(yt, max_pages=None):\n",
+ " rows, page, pages = [], None, 0\n",
+ " while True:\n",
+ " resp = yt.subscriptions().list(\n",
+ " part=\"snippet\",\n",
+ " mine=True, maxResults=50, pageToken=page,\n",
+ " fields=\"nextPageToken,items(snippet(title,publishedAt,resourceId/channelId))\"\n",
+ " ).execute()\n",
+ " for it in resp.get(\"items\", []):\n",
+ " sn = it[\"snippet\"]\n",
+ " rows.append({\n",
+ " \"ChannelTitle\": sn[\"title\"],\n",
+ " \"ChannelId\": sn[\"resourceId\"][\"channelId\"],\n",
+ " \"SubscribedAt\": sn.get(\"publishedAt\"),\n",
+ " })\n",
+ " page = resp.get(\"nextPageToken\"); pages += 1\n",
+ " if not page or (max_pages and pages >= max_pages): break\n",
+ " return pd.DataFrame(rows)\n",
+ "\n",
+ "def list_my_liked_videos(yt, max_pages=None):\n",
+ " rows, page, pages = [], None, 0\n",
+ " while True:\n",
+ " resp = yt.videos().list(\n",
+ " part=\"id,snippet,contentDetails,statistics\",\n",
+ " myRating=\"like\", maxResults=50, pageToken=page,\n",
+ " fields=(\"nextPageToken,items(\"\n",
+ " \"id,\"\n",
+ " \"snippet(title,channelTitle,publishedAt),\"\n",
+ " \"contentDetails(duration),\"\n",
+ " \"statistics(viewCount,likeCount))\")\n",
+ " ).execute()\n",
+ " for v in resp.get(\"items\", []):\n",
+ " rows.append({\n",
+ " \"VideoId\": v[\"id\"],\n",
+ " \"Title\": v[\"snippet\"][\"title\"],\n",
+ " \"ChannelTitle\": v[\"snippet\"][\"channelTitle\"],\n",
+ " \"PublishedAt\": v[\"snippet\"][\"publishedAt\"],\n",
+ " \"Duration\": v[\"contentDetails\"][\"duration\"],\n",
+ " \"ViewCount\": v[\"statistics\"].get(\"viewCount\"),\n",
+ " \"LikeCount\": v[\"statistics\"].get(\"likeCount\"),\n",
+ " })\n",
+ " page = resp.get(\"nextPageToken\"); pages += 1\n",
+ " if not page or (max_pages and pages >= max_pages): break\n",
+ " return pd.DataFrame(rows)\n",
+ "\n",
+ "# —— 实际调用 ——\n",
+ "if my_channel_id:\n",
+ " df_subs = list_my_subscriptions(yt)\n",
+ " display(df_subs.head(10)); print(\"Total subscriptions:\", len(df_subs))\n",
+ " df_likes = list_my_liked_videos(yt)\n",
+ " display(df_likes.head(10)); print(\"Total liked videos:\", len(df_likes))\n",
+ "\n",
+ " # 可选导出\n",
+ " df_subs.to_csv(\"my_subscriptions.csv\", index=False)\n",
+ " df_likes.to_csv(\"my_liked_videos.csv\", index=False)\n",
+ "else:\n",
+ " print(\"未获取到频道 ID,先按提示创建频道并重新授权。\")\n"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 539
+ },
+ "id": "4Yf_ACslv3vX",
+ "outputId": "e65bc29d-874c-4bec-eba8-49714f61d23f"
+ },
+ "execution_count": 11,
+ "outputs": [
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ " ChannelTitle ChannelId SubscribedAt\n",
+ "0 怪咖 Outcasts UCVpZkO-pOOr6z4NdxAKegPg 2025-09-11T03:08:25.051076Z\n",
+ "1 拜托了小翔哥 UCBPMSrO-Ljh_jGeFX5HDmkQ 2025-09-11T03:07:57.501044Z\n",
+ "2 美食挖掘机 UCoHcW0XwwRaMlVea5C03geA 2025-09-11T02:08:13.85328Z"
+ ],
+ "text/html": [
+ "\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " ChannelTitle | \n",
+ " ChannelId | \n",
+ " SubscribedAt | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 怪咖 Outcasts | \n",
+ " UCVpZkO-pOOr6z4NdxAKegPg | \n",
+ " 2025-09-11T03:08:25.051076Z | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 拜托了小翔哥 | \n",
+ " UCBPMSrO-Ljh_jGeFX5HDmkQ | \n",
+ " 2025-09-11T03:07:57.501044Z | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 美食挖掘机 | \n",
+ " UCoHcW0XwwRaMlVea5C03geA | \n",
+ " 2025-09-11T02:08:13.85328Z | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ "
\n",
+ "
\n"
+ ],
+ "application/vnd.google.colaboratory.intrinsic+json": {
+ "type": "dataframe",
+ "summary": "{\n \"name\": \" print(\\\"\\u672a\\u83b7\\u53d6\\u5230\\u9891\\u9053 ID\\uff0c\\u5148\\u6309\\u63d0\\u793a\\u521b\\u5efa\\u9891\\u9053\\u5e76\\u91cd\\u65b0\\u6388\\u6743\\u3002\\\")\",\n \"rows\": 3,\n \"fields\": [\n {\n \"column\": \"ChannelTitle\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"\\u602a\\u5496 Outcasts\",\n \"\\u62dc\\u6258\\u4e86\\u5c0f\\u7fd4\\u54e5\",\n \"\\u7f8e\\u98df\\u6316\\u6398\\u673a\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ChannelId\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"UCVpZkO-pOOr6z4NdxAKegPg\",\n \"UCBPMSrO-Ljh_jGeFX5HDmkQ\",\n \"UCoHcW0XwwRaMlVea5C03geA\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"SubscribedAt\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"2025-09-11T03:08:25.051076Z\",\n \"2025-09-11T03:07:57.501044Z\",\n \"2025-09-11T02:08:13.85328Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
+ }
+ },
+ "metadata": {}
+ },
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Total subscriptions: 3\n"
+ ]
+ },
+ {
+ "output_type": "display_data",
+ "data": {
+ "text/plain": [
+ " VideoId Title \\\n",
+ "0 HzkbELvR4Hc 尋找最好吃的炸鷄!吃爆10間炸雞連鎖店!| Finding the Best Fried C... \n",
+ "1 qtYt88z_tdw 在日本,吃牛肉飯代表你很窮?實際探店帶你看日本的窮人餐廳都是哪些,沒錢又怎麼在日本生活呢? \n",
+ "2 6sMA1QNerNI 从3毛到100元都能吃到什么样的泡面 \n",
+ "3 XGbVp62P64k 全球最魔性,印度航空!天上吃什么? \n",
+ "4 wZhOsKw10yA 来东北吃盒饭啦!12一份6个菜!居然还送水! #街头美食 #路边摊美味 \n",
+ "5 6iqIwXjNyH0 修杰楷跟著千千爆吃捷運美食!逼出小鳥胃極限,一路吃到投降?!【修TIME】Ep23 | ... \n",
+ "\n",
+ " ChannelTitle PublishedAt Duration ViewCount LikeCount \n",
+ "0 怪咖 Outcasts 2025-08-15T10:00:35Z PT27M21S 155653 6848 \n",
+ "1 冷水TV・日本生活與日本文化 2025-06-10T10:01:31Z PT12M22S 1621627 27392 \n",
+ "2 拜托了小翔哥 2025-09-02T10:00:10Z PT14M14S 218432 3349 \n",
+ "3 觅食Meetfood 2024-12-22T01:00:21Z PT8M22S 575688 9608 \n",
+ "4 美食挖掘机 2025-01-23T11:43:00Z PT58S 760065 30086 \n",
+ "5 修TIME 2025-09-10T06:44:41Z PT27M18S 266866 4533 "
+ ],
+ "text/html": [
+ "\n",
+ " \n",
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " VideoId | \n",
+ " Title | \n",
+ " ChannelTitle | \n",
+ " PublishedAt | \n",
+ " Duration | \n",
+ " ViewCount | \n",
+ " LikeCount | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " HzkbELvR4Hc | \n",
+ " 尋找最好吃的炸鷄!吃爆10間炸雞連鎖店!| Finding the Best Fried C... | \n",
+ " 怪咖 Outcasts | \n",
+ " 2025-08-15T10:00:35Z | \n",
+ " PT27M21S | \n",
+ " 155653 | \n",
+ " 6848 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " qtYt88z_tdw | \n",
+ " 在日本,吃牛肉飯代表你很窮?實際探店帶你看日本的窮人餐廳都是哪些,沒錢又怎麼在日本生活呢? | \n",
+ " 冷水TV・日本生活與日本文化 | \n",
+ " 2025-06-10T10:01:31Z | \n",
+ " PT12M22S | \n",
+ " 1621627 | \n",
+ " 27392 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 6sMA1QNerNI | \n",
+ " 从3毛到100元都能吃到什么样的泡面 | \n",
+ " 拜托了小翔哥 | \n",
+ " 2025-09-02T10:00:10Z | \n",
+ " PT14M14S | \n",
+ " 218432 | \n",
+ " 3349 | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " XGbVp62P64k | \n",
+ " 全球最魔性,印度航空!天上吃什么? | \n",
+ " 觅食Meetfood | \n",
+ " 2024-12-22T01:00:21Z | \n",
+ " PT8M22S | \n",
+ " 575688 | \n",
+ " 9608 | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " wZhOsKw10yA | \n",
+ " 来东北吃盒饭啦!12一份6个菜!居然还送水! #街头美食 #路边摊美味 | \n",
+ " 美食挖掘机 | \n",
+ " 2025-01-23T11:43:00Z | \n",
+ " PT58S | \n",
+ " 760065 | \n",
+ " 30086 | \n",
+ "
\n",
+ " \n",
+ " 5 | \n",
+ " 6iqIwXjNyH0 | \n",
+ " 修杰楷跟著千千爆吃捷運美食!逼出小鳥胃極限,一路吃到投降?!【修TIME】Ep23 | ... | \n",
+ " 修TIME | \n",
+ " 2025-09-10T06:44:41Z | \n",
+ " PT27M18S | \n",
+ " 266866 | \n",
+ " 4533 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
\n",
+ "
\n",
+ "
\n"
+ ],
+ "application/vnd.google.colaboratory.intrinsic+json": {
+ "type": "dataframe",
+ "summary": "{\n \"name\": \" print(\\\"\\u672a\\u83b7\\u53d6\\u5230\\u9891\\u9053 ID\\uff0c\\u5148\\u6309\\u63d0\\u793a\\u521b\\u5efa\\u9891\\u9053\\u5e76\\u91cd\\u65b0\\u6388\\u6743\\u3002\\\")\",\n \"rows\": 6,\n \"fields\": [\n {\n \"column\": \"VideoId\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 6,\n \"samples\": [\n \"HzkbELvR4Hc\",\n \"qtYt88z_tdw\",\n \"6iqIwXjNyH0\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Title\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 6,\n \"samples\": [\n \"\\u5c0b\\u627e\\u6700\\u597d\\u5403\\u7684\\u70b8\\u9dc4\\uff01\\u5403\\u720610\\u9593\\u70b8\\u96de\\u9023\\u9396\\u5e97\\uff01| Finding the Best Fried Chicken!\\u3010ENG SUBS\\u3011\",\n \"\\u5728\\u65e5\\u672c\\uff0c\\u5403\\u725b\\u8089\\u98ef\\u4ee3\\u8868\\u4f60\\u5f88\\u7aae\\uff1f\\u5be6\\u969b\\u63a2\\u5e97\\u5e36\\u4f60\\u770b\\u65e5\\u672c\\u7684\\u7aae\\u4eba\\u9910\\u5ef3\\u90fd\\u662f\\u54ea\\u4e9b\\uff0c\\u6c92\\u9322\\u53c8\\u600e\\u9ebc\\u5728\\u65e5\\u672c\\u751f\\u6d3b\\u5462\\uff1f\",\n \"\\u4fee\\u6770\\u6977\\u8ddf\\u8457\\u5343\\u5343\\u7206\\u5403\\u6377\\u904b\\u7f8e\\u98df\\uff01\\u903c\\u51fa\\u5c0f\\u9ce5\\u80c3\\u6975\\u9650\\uff0c\\u4e00\\u8def\\u5403\\u5230\\u6295\\u964d\\uff1f\\uff01\\u3010\\u4feeTIME\\u3011Ep23 | \\u00a0@Chienseating \\u200b\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ChannelTitle\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 6,\n \"samples\": [\n \"\\u602a\\u5496 Outcasts\",\n \"\\u51b7\\u6c34TV\\u30fb\\u65e5\\u672c\\u751f\\u6d3b\\u8207\\u65e5\\u672c\\u6587\\u5316\",\n \"\\u4feeTIME\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"PublishedAt\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 6,\n \"samples\": [\n \"2025-08-15T10:00:35Z\",\n \"2025-06-10T10:01:31Z\",\n \"2025-09-10T06:44:41Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Duration\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 6,\n \"samples\": [\n \"PT27M21S\",\n \"PT12M22S\",\n \"PT27M18S\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"ViewCount\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 6,\n \"samples\": [\n \"155653\",\n \"1621627\",\n \"266866\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 6,\n \"samples\": [\n \"6848\",\n \"27392\",\n \"4533\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
+ }
+ },
+ "metadata": {}
+ },
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Total liked videos: 6\n"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file