【问题标题】:Difference between read_html(url) and read_html(content(GET(url), "text"))read_html(url) 和 read_html(content(GET(url), "text")) 之间的区别
【发布时间】:2020-02-01 19:04:33
【问题描述】:

我正在查看这个很棒的答案: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")

输出在多个请求中保持不变:

"59243d3a2....61f8f73136118f9"

到目前为止,我的默认方式是:

doc <- read_html("https://nzffdms.niwa.co.nz/search")
xml_attr(xml_find_all(doc, ".//input[@name='search[_csrf_token]']"), "value")

结果与上面的输出不同,并且在多个请求中发生变化。

问题:

两者有什么区别:

  • 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])

但这导致了这个问题:Find the used method for R wrapper functions

想法:

  • 我没有看到 get 请求采用任何标头或 Cookie,即 可以解释不同的反应。

  • 据我了解,read_htmlread_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

--> 在我看来,缓存可能不是解决方案。

  • 查看help("GET") 给出了一个关于“条件GET”的有趣部分:

GET 方法的语义更改为“条件 GET”,如果 请求消息包括一个 If-Modified-Since、If-Unmodified-Since、 If-Match、If-None-Match 或 If-Range 头字段。有条件的 GET 方法要求实体仅在 条件头字段描述的情况。这 有条件的 GET 方法旨在减少不必要的网络使用 通过允许刷新缓存的实体而不需要多个 请求或传输客户端已持有的数据。

但据我所知,with_verbose() 没有设置任何If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match, or If-Range

【问题讨论】:

  • 哇...由于代理(我已经有set_config),我收到read_html("http://httpbin.org/") 的连接超时错误,但read_html(GET("http://httpbin.org/")) 却没有...似乎是一个错误.. .回到你的 qn,我不是 100% 确定,但你的最终想法似乎是合理的,也许保持连接活动设置在第一个但不是第二个......另请参阅 stackoverflow.com/questions/5207160/…

标签: r get rvest xml2


【解决方案1】:

不同之处在于重复调用httr::GET,句柄在调用之间保持不变。使用xml2::read_html(),每次都会建立一个新连接。

来自 httr 文档:

句柄池用于为相同的方案/主机/端口组合自动重用 Curl 句柄。这可确保自动重用 http 会话,并在对站点的请求之间维护 cookie,而无需用户干预。

来自 xml2 文档,讨论传递给 read_html() 的字符串参数:

字符串可以是路径、url 或文字 xml。网址将使用base::urlcurl::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"))

就我而言,采购上面的代码给了我:

[1] "ecd9be7c75559364a2a5568049c0313f"
[1] "ecd9be7c75559364a2a5568049c0313f"
[1] "d953ce7acc985adbf25eceb89841c713"

【讨论】:

  • 所以如果 read_html 在安装后使用 curl,那么(理论上)应该可以配置 read_html,就像在 httr curl 处理中一样,它也可以重用 curl 句柄,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
  • 2018-09-08
  • 2019-01-27
  • 2016-04-05
  • 2019-04-15
  • 2011-05-10
相关资源
最近更新 更多