从谷歌地图获取我的地点列表

Gab*_*tin 5 google-maps

我正在尝试获取用户在 Google 地图上保存的地点列表。现在我知道没有用于此的 API(无论出于何种原因),但我在这里看到:

“我的地方”谷歌地图 API

显然曾经有一种获取 URL 的方法,但它似乎不适用于我的地点列表。

例如

https://www.google.com/maps/@46.889424,0.1194148,6z/data=!4m3!11m2!2s1KbZtik1IdXyNhwfXEb3P9vaZvzU!3e3

如果我附加 &output=kml 或 &output=json 似乎不起作用

我在谷歌地图上创建了这个列表,然后点击分享并获得了那个链接。

我什至尝试解析生成的 HTML,但似乎所有内容都由某个 Javascript 引擎处理,我在那里找不到任何对 Google Id 的引用——我什至不知道它们如何处理点击!

有什么帮助吗?有必须要以编程方式检索此信息的方式!

编辑:

我设法通过访问共享链接,然后处理 html 并存储window.APP_INITIALIZATION_STATE变量来获得一些工作。然后我将它转换为一个 javascript 数组并循环遍历它。在数组/地图结构的深处,我设法从该数组中获取了 google 名称和 google 位置 ID。这似乎有点奏效,但是当尝试使用超过 20 个项目的列表时,谷歌只获取前 20 个并等待用户“向下滚动”以获取下一个 20。这似乎触发了另一个调用以获取下一个20 个结果,看起来有点像:

https://www.google.com/search?tbm=map&fp=1&authuser=0&hl=en&gl=nl&pb=!4m8!1m3!1d54065472.4384380 ........

我可以看到原始功能 ID 包含在 url 的末尾,但不知道如何完整构建此 url 以获取接下来的 20 个项目....有什么想法吗?

bin*_*ngo 5

另请查看Joel 的答案,他做了一些研究并完善了以下一些信息。


分页

您可以使用此工具来解密 pb 参数。PB 代表协议缓冲区(protobuf),谷歌将自己的协议缓冲区用于地图。您可以通过谷歌搜索找到不同的解码器。

就我而言,分页是通过一个参数 (8iX0) 完成的。似乎它总是带有另一个类似的参数(7i20),但我不知道它确实如此。我还不能确认情况总是如此,但根据我的经验,你基本上是在寻找相距 20/40/60 等的两个整数。

这对我来说是这样的:

  • 第 2 页(7i20、8i20)
  • 第 3 页(7i20、8i40)
  • 第 4 页(7i20、8i60)

根据这些信息,我在第 1 页尝试了 7i20 8i00,这似乎有效。对于包含 >100 个项目的列表,它只是这样继续(8i120、8i140 等)

这是 python 中的代码片段(快速且肮脏)。如果您的列表有很多页面,请确保添加(长)延迟,否则最终您将受到验证码的速率限制。注意url 中的8i%s0,确保在粘贴 pb-block 时将 %s 放回去。

url = "https://www.google.com:443/search?tbm=map&pb=!7i20!8i%s0!..."
headers = {"Referer": "https://www.google.com/"}

def fetch_stops_from_maps():
    new_results = -1
    page = 0
    results = []

    while new_results != 0:
        new_results = 0
        x = requests.get(url % page, headers=headers)
        txt = html.unescape(x.text)
        txt = txt.split("\n")[1]
        results = re.findall(r"\[null,null,[0-9]{1,2}\.[0-9]{4,15},[0-9]{1,2}\.[0-9]{4,15}]", txt)

        print(len(results))
        for cord in results:
            # curr = the description you can manually type in when saving
            curr = txt.split(cord)[1].split("\"]]")[0]
            curr = curr[curr.rindex(",\"") + 2:]

            cords = str(cord).split(",")
            lat = cords[2]
            lon = cords[3][:-1]

            results.append(s)
            new_results += 1
        page += 2
Run Code Online (Sandbox Code Playgroud)

实际上得到了正确的url

目前,获取正确的网址似乎是执行此操作时最困难的部分,而且我还没有完全弄清楚这一点。然而,对于我的用例来说,这并不是很重要,所以我提取了正确的 pb 块一次,然后就到此为止了。

正如其他答案中所解释的,当您导航到浏览器中的列表时,列表的 id 在基本 url(此处为 2sXX...)中可见。它似乎通常为 24-32 (?) 个字符长。

.../maps/<coords>/data=!4m3!11m2!2sXXXX...XXXX!3e3 
Run Code Online (Sandbox Code Playgroud)

如果你有这个 id,你可以将它放入现有的 protobuf-block 中,它可能会起作用(我只用 3 个不同的列表进行了测试,这些列表都是由同一个帐户创建的,所以这个理论还远未得到证实)。

现在,你如何获得该块?我只想分享我拥有的一个,但因为我只了解它的部分功能,我担心它可能包含一些个人信息。相反,我将分享我获得它的过程。为此,我使用Burpsuite。它是一个主要用于网络安全测试的程序,并且有一个免费的社区版本,但是对于我们的用例来说,它是一个完美的工具,因为有了它,您可以轻松地修改请求,更改请求中的小部分,再次发送它并立即查看您的更改是否改变了响应。然而,为了提取 pb 块,人们还应该能够使用任何可以拦截浏览器流量的程序。

这是 burp 的基本概要:

  1. 从 GMaps 中,共享包含 >20 个项目的列表(这很重要)并复制公共链接

  2. 在 Burp 中,转到“代理”选项卡,确保“拦截”已关闭,然后单击“打开浏览器”以打开集成的 chromium 浏览器

  3. 在那里,粘贴链接并等待地图完全加载

  4. 在 Burp 中,打开“拦截”,然后在 google 地图中,在列表中向下滚动,直到开始加载新结果(始终为 20 个块)

  5. Burp 现在拦截了自您打开拦截以来浏览器发出的所有请求。单击“转发”并浏览所有请求,直到看到以下格式的请求

    GET /search?tbm=map&authuser=0&hl=de&gl=de&pb=!7i20....

这就是您要找的。

或者,您现在可以右键单击请求文本并单击“发送到转发器”,然后切换到转发器选项卡。您可以在此处编辑请求,然后再次发送,并能够立即看到响应。例如,删除authuser, hl, gl, q, ech, psiurl 参数,请求仍然可以完美运行。如果删除该tch=1参数,您收到的响应将采用更易于理解的格式。

在请求文本中,您现在应该能够搜索从之前的链接中获得的列表 ID,并将其替换为另一个列表的 ID(搜索栏位于 burp 的底部)。正如我所说,这对我有用,但 pb 块可能包含一些额外的元数据,这些元数据使来自不同 google 帐户的列表或不同类型的列表与特定 pb 块不兼容。不过只是一个理论。让我知道事情的后续!

进一步自动化

我的理论是,可以使用requests-html自动获取 pb-block ,因为它可以完全加载 html 站点,但它不再更新。另一种选择(可能是更好的选择)是 Selenium Wire,因为您应该能够加载页面并拦截请求,就像我们在 burp 中所做的那样。看起来工作量很大:D

  • ^ 添加我之前的评论:请注意,谷歌的回应相当疯狂。每个“地点”都有数千行长,解码起来很困难,但 @bingo 的脚本是一个很棒的起点。当我尝试解析某些地名和地址中包含的各种特殊字符时,我的生产语言(javascript)也会感到窒息,因此获取分页的“response.text()”数据并将其串在一起只是这里的许多试验/磨难中的第一个我。:) (2认同)

小智 4

您保存的地点列表实际上具有所谓的功能 ID 属性,这不是常见做法,Google 不赞成这种技术,但请看一下以下 URL:

https://www.google.com/maps/preview/entity?authuser=0&hl=en&gl=us&pb=!1m10!1s 0x0%3A0x3743ae09a161976 b!3m8!1m3!1d14318.72623152007!2d-98.2296425!3d26.2070353!3平方米!1i1024!2i768!4f13.1!12m3!2m2!1i392!2i106!13m57!2m2!1i203!2i100!3m2!2i4!5b1!6m6!1m2!1i86!2i86!1m2!1i408!2i200!7m42!1m3!1e1 !2b0!3e3!1m3!1e2!2b1!3e2!1m3!1e2!2b0!3e3!1m3!1e3!2b0!3e3!1m3!1e8!2b0!3e3!1m3!1e3!2b1!3e2!1m3!1e9!2b1 !3e2!1m3!1e10!2b0!3e3!1m3!1e10!2b1!3e2!1m3!1e10!2b0!3e4!2b1!4b1!9b0!14m3!1snyc5W-WeHY3r5gLwkoRI!7e81!15i10112!15m19!2b1!5m4!2b1 !3b1!5b1!6b1!10m1!8e3!14m1!3b1!17b1!24b1!25b1!26b1!30m1!2b1!36b1!52b1!53b1!21m28!1m6!1m2!1i0!2i0!2m2!1i458!2i768!1m6 !1m2!1i974!2i0!2m2!1i1024!2i768!1m6!1m2!1i0!2i0!2m2!1i1024!2i20!1m6!1m2!1i0!2i748!2m2!1i1024!2i768!22m1!1e81!29m0!30m1!3b1

突出显示的是您发布的链接中的功能 ID: https ://www.google.com/maps/@46.889424,0.1194148,6z/data=!4m3!11m2!2s1KbZtik1IdXyNhwfXEb3P9vaZvzU!3e3

以及其他地图参数;当您点击该链接时,您实际上手动触发了与 Google 自己的地图脚本相同的回调,该回调用于解析数据以反馈到地图 UI;如果您查看数组项 2 或 {c:..} 您会发现一个包含列表内容的字符串化数组,现在根据您使用的程序语言,需要做一些调整(查找/替换、循环、lint 和修剪等)到该数组,您可以提取结果;最酷的是,如果您在下次到达该终点时添加或删除某个地点,它会实时更新。

有些人可能称之为“hack”;但它完成了工作。:)

如果您还没有找到解决方案,希望我能为您指明方向;试一试。

请注意,必须完整粘贴 URL,因此截断了超链接;一次复制并粘贴整个内容,就会生成一个来自 Google 的带有数组的文本文件;就我而言,我会卷曲我需要的 URL,并根据需要解析返回的字符串,以便从 Google 提取数据,而 Google 的 API 有限制。只是一个提示。:)