我正在看这个很好的答案:https : //stackoverflow.com/a/58211397/3502164。
解决方案的开头包括:
library(httr)
library(xml2)
gr <- GET("https://nzffdms.niwa.co.nz/search")
doc <- read_html(content(gr, "text"))
xml_attr(xml_find_all(doc, ".//input[@name='search[_csrf_token]']"), "value")
Run Code Online (Sandbox Code Playgroud)
输出在多个请求中保持不变:
"59243d3a2....61f8f73136118f9"
Run Code Online (Sandbox Code Playgroud)
到目前为止,我的默认方式是:
doc <- read_html("https://nzffdms.niwa.co.nz/search")
xml_attr(xml_find_all(doc, ".//input[@name='search[_csrf_token]']"), "value")
Run Code Online (Sandbox Code Playgroud)
结果与上面的输出不同,并在多个请求中发生变化。
题:
两者有什么区别:
read_html(url)read_html(content(GET(url), "text"))为什么它会导致不同的值,为什么只有“GET”解决方案会返回链接问题中的 csv?
(我希望可以在三个子问题的种类中对其进行结构化)。
我试过的:
走下函数调用的兔子洞:
read_html
(ms <- methods("read_html"))
getAnywhere(ms[1])
xml2:::read_html
xml2:::read_html.default
#xml2:::read_html.response
read_xml
(ms <- methods("read_xml"))
getAnywhere(ms[1])
Run Code Online (Sandbox Code Playgroud)
但这导致了这个问题:Find the used method for R wrapper functions
想法:
我没有看到 get 请求采用任何标头或 Cookie,这可以解释不同的响应。
从我的理解都read_html和read_html(content(GET(.),
"text"))返回XML / HTML。
好的,在这里我不确定检查是否有意义,但因为我的想法用完了:我检查了是否有某种缓存正在进行。
代码:
with_verbose(GET("https://nzffdms.niwa.co.nz/search"))
....
<- Expires: Thu, 19 Nov 1981 08:52:00 GMT
<- Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Run Code Online (Sandbox Code Playgroud)
--> 在我看来,缓存可能是解决方案。
help("GET")给出了一个关于“条件获取”的有趣部分:如果请求消息包含 If-Modified-Since、If-Unmodified-Since、If-Match、If-None-Match 或 If-Range 头字段,则 GET 方法的语义将更改为“条件 GET”。条件 GET 方法请求仅在条件标头字段描述的情况下传输实体。条件 GET 方法旨在通过允许刷新缓存实体而不需要多个请求或传输客户端已持有的数据来减少不必要的网络使用。
但据我所见,with_verbose()没有If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, or If-Range设置。
不同之处在于,重复调用 时httr::GET,句柄在调用之间保持不变。使用xml2::read_html(),每次都会建立一个新的连接。
从 httr 文档:
句柄池用于为相同的方案/主机/端口组合自动重用 Curl 句柄。这可确保自动重用 http 会话,并且在无需用户干预的情况下跨站点请求维护 cookie。
从 xml2 文档中,讨论传递给的字符串参数read_html():
字符串可以是路径、url 或文字 xml。Urls 将被转换为连接,
base::url或者,如果安装,curl::curl
因此,您的答案read_html(GET(url))就像刷新浏览器一样,但read_html(url)就像关闭浏览器并打开一个新浏览器一样。服务器在其传送的页面上提供唯一的会话 ID。新会话,新 ID。您可以通过调用来证明这一点httr::reset_handle(url):
library(httr)
library(xml2)
# GET the page (note xml2 handles httr responses directly, don't need content("text"))
gr <- GET("https://nzffdms.niwa.co.nz/search")
doc <- read_html(gr)
print(xml_attr(xml_find_all(doc, ".//input[@name='search[_csrf_token]']"), "value"))
# A new GET using the same handle gets exactly the same response
gr <- GET("https://nzffdms.niwa.co.nz/search")
doc <- read_html(gr)
print(xml_attr(xml_find_all(doc, ".//input[@name='search[_csrf_token]']"), "value"))
# Now call GET again after resetting the handle
httr::handle_reset("https://nzffdms.niwa.co.nz/search")
gr <- GET("https://nzffdms.niwa.co.nz/search")
doc <- read_html(gr)
print(xml_attr(xml_find_all(doc, ".//input[@name='search[_csrf_token]']"), "value"))
Run Code Online (Sandbox Code Playgroud)
就我而言,采购上述代码给了我:
[1] "ecd9be7c75559364a2a5568049c0313f"
[1] "ecd9be7c75559364a2a5568049c0313f"
[1] "d953ce7acc985adbf25eceb89841c713"
Run Code Online (Sandbox Code Playgroud)