我正在尝试从包含
leaflet
地图(osm 数据)的网站上抓取标记坐标。我一直在网上寻找答案,由于网站的动态特性,对解析后的 html 进行简单查询似乎是不够的。因此我一直在使用RSelenium
。在查看了 html 并使用 ChatGPT 后,我已经做到了这一点:
library(RSelenium)
library(rvest)
library(xml2)
remote_driver <- rsDriver(browser = "firefox",
chromever = NULL,
verbose = FALSE,
port = 4445L)
remDr <- remote_driver$client
remDr$navigate("https://www.hejfish.com/d/1356-strobl-wasser-fliegenstrecke-traun")
# Scroll to the end of the page to trigger marker loading
remDr$executeScript("window.scrollTo(0, document.body.scrollHeight);")
map_markers <- remDr$findElements(using = "css", value = ".MapIcons__marker_icon___vDTMo")
ChatGPT 建议我像这样提取坐标:
coordinates <- lapply(map_markers, function(marker) {
lat <- marker$getElementAttribute("data-lat")$value
lon <- marker$getElementAttribute("data-lon")$value
c(lat = as.numeric(lat), lon = as.numeric(lon))
})
不幸的是,这不起作用:
Error: attempt to apply non-function
。我假设提取的元素中没有名为 "data-lat"
或 "data-lon"
的属性。然而,通过检查网站的 html,我找不到任何看起来像标记代码中的坐标的东西。受this帖子的启发,我还检查了网络选项卡,并能够找到边界框的坐标,但找不到两个标记的坐标。其他帖子谈论隐藏在脚本标签等中的信息,但这超出了我的能力。
任何有关抓取坐标的帮助将不胜感激!
这是解决此问题的一种方法,请注意,它涉及一个在此示例中被截断的 API 密钥,因此您需要自己提取它。
我首先想出一些在开发的网络选项卡中使用的搜索字符串。工具。传单标记弹出窗口包括 Google 地图链接,这可能会很方便:
链接本身很可能是由 javascript 生成的,但坐标值可能按原样传输;这里太具体可能行不通,所以让我们只搜索纬度,
48.235585
。另外,请确保捕获所有请求,即根据需要刷新页面。这将引导我们到达 api.hejfish.com/fisher/areas/1356/map
API 端点:我们可以尝试打开该 URL,但即使在同一个浏览器会话中,我们也会收到错误 403 - Zugriff verweigert 。检查请求标头时,会设置多个会话 cookie 和额外标头,最值得注意的是
X-Api-Key
。只是为了检查我们是否可以自己复制该请求,让我们将其复制为 cURL 命令:我们可以通过命令行使用它,或者尝试通过 https://curlconverter.com/r/ 或类似工具将其转换为 R 或 Python,但让我们看看
httr2::curl_translate()
是否可以处理这个问题:
library(httr2)
# read copied cURL command from clipboard, ends up as a vector of lines;
# paste it back into a single string and feed to curl_translate():
clipr::read_clip(allow_non_interactive = T) |>
paste0(collapse = "\n") |>
curl_translate()
#> request("https://api.hejfish.com/fisher/areas/1356/map") %>%
#> req_headers(
#> authority = "api.hejfish.com",
#> accept = "application/json",
#> `accept-language` = "en-GB,en;q=0.9,et-EE;q=0.8,et;q=0.7,en-US;q=0.6",
#> origin = "https://www.hejfish.com",
#> referer = "https://www.hejfish.com/",
#> `sec-ch-ua` = "\"Not_A Brand\";v=8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120",
#> `sec-ch-ua-mobile` = "?0",
#> `sec-ch-ua-platform` = "\"Windows\"",
#> `sec-fetch-dest` = "empty",
#> `sec-fetch-mode` = "cors",
#> `sec-fetch-site` = "same-site",
#> `user-agent` = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
#> `x-api-key` = "4O...",
#> `x-locale` = "de_DE",
#> `x-requested-with` = "XMLHttpRequest",
#> ) %>%
#> req_perform()
看起来很扎实!有了完整的 API 密钥,它实际上会以状态 200 OK 完成。我们可以像这样保留它,或者稍微修剪一下,为了处理 JSON 响应,我们可以使用
httr2::resp_body_json()
:
library(httr2)
map_ <-
request("https://api.hejfish.com/fisher/areas/1356/map") |>
req_headers(`x-api-key` = "4O...") |>
req_perform() |>
resp_body_json(simplifyVector = TRUE)
map_$data$locations
#> lat lng
#> 1 48.23559 14.29808
#> 2 48.24744 14.32493