如何在没有按钮参数的 Rvest 包中提交登录表单

Posted

技术标签:

【中文标题】如何在没有按钮参数的 Rvest 包中提交登录表单【英文标题】:How to submit login form in Rvest package w/o button argument 【发布时间】:2016-04-22 05:11:46 【问题描述】:

我正在尝试使用 rvest 包中的 html_session() 和 html_form() 来抓取需要身份验证的网页。 我发现了这个,例如由 Hadley Wickham 提供,但我无法根据我的情况对其进行自定义。

united <- html_session("http://www.united.com/")
account <- united %>% follow_link("Account")
login <- account %>%
         html_nodes("form") %>%
         extract2(1) %>%
         html_form() %>%
         set_values(
                `ctl00$ContentInfo$SignIn$onepass$txtField` = "GY797363",
                `ctl00$ContentInfo$SignIn$password$txtPassword` = password)
account <- account %>% 
submit_form(login, "ctl00$ContentInfo$SignInSecure")

在我的情况下,我找不到要在表单中设置的值,因此我试图给用户并直接传递: set_values("电子邮件","密码")

我也不知道如何引用提交按钮,所以我尝试了: submit_form(帐号,登录)

提交表单函数的错误是: 名称错误(提交)[[1]]:下标超出范围

任何关于如何解决这个问题的想法都值得赞赏。 谢谢

【问题讨论】:

【参考方案1】:

目前,此问题与rvest 包中打开的issue #159 相同,这会导致表单中并非所有字段都具有type 值的问题。此购买可能会在未来的版本中修复。

但是,我们可以通过猴子修补底层函数 rvest:::submit_request 来解决此问题。

核心问题是辅助函数is_submit。最初,它是这样定义的:

is_submit <- function(x) tolower(x$type) %in% c("submit", 
        "image", "button")

尽管如此合乎逻辑,但它在两种情况下都会失败:

    没有type 元素。 type 元素是NULL

这两种情况都发生在美联航登录表单上。我们可以通过在函数中添加两个检查来解决这个问题。

custom.submit_request <- function (form, submit = NULL) 

  is_submit <- function(x) 
    if (!exists("type", x) | is.null(x$type))
      return(F);
    
    tolower(x$type) %in% c("submit", "image", "button")
   
  submits <- Filter(is_submit, form$fields)
  if (length(submits) == 0) 
    stop("Could not find possible submission target.", call. = FALSE)
  
  if (is.null(submit)) 
    submit <- names(submits)[[1]]
    message("Submitting with '", submit, "'")
  
  if (!(submit %in% names(submits))) 
    stop("Unknown submission name '", submit, "'.\n", "Possible values: ", 
         paste0(names(submits), collapse = ", "), call. = FALSE)
  
  other_submits <- setdiff(names(submits), submit)
  method <- form$method
  if (!(method %in% c("POST", "GET"))) 
    warning("Invalid method (", method, "), defaulting to GET", 
            call. = FALSE)
    method <- "GET"
  
  url <- form$url
  fields <- form$fields
  fields <- Filter(function(x) length(x$value) > 0, fields)
  fields <- fields[setdiff(names(fields), other_submits)]
  values <- pluck(fields, "value")
  names(values) <- names(fields)
  list(method = method, encode = form$enctype, url = url, values = values)

要猴子补丁,我们需要使用R.utils 包(如果没有,请通过install.packages("R.utils") 安装)。

library(R.utils)

reassignInPackage("submit_request", "rvest", custom.submit_request)

从那里,我们可以发出我们自己的请求。

account <- account %>% 
     submit_form(login, "ctl00$ContentInfo$SignInSecure")

这行得通!

(好吧,“works”是用词不当。由于 United 采用更严格的身份验证要求 - 包括已知浏览器 - 这导致 301 Unauthorized。但是,它修复了错误)。

一个完整的可重现示例涉及其他一些小的代码更改:

library(magrittr)
library(rvest)

url <- "https://www.united.com/web/en-US/apps/account/account.aspx"
account <- html_session(url)
login <- account %>%
  html_nodes("form") %>%
  extract2(1) %>%
  html_form() %>%
  set_values(
    `ctl00$ContentInfo$SignIn$onepass$txtField` = "USER",
    `ctl00$ContentInfo$SignIn$password$txtPassword` = "PASS")
account <- account %>% 
  submit_form(login, "ctl00$ContentInfo$SignInSecure")

【讨论】:

以上是关于如何在没有按钮参数的 Rvest 包中提交登录表单的主要内容,如果未能解决你的问题,请参考以下文章

使用 rvest 或 httr 登录网页上的非标准表单

高分求教:如何实现java web 按钮点击弹出登陆界面,并登陆

如何在提交按钮表单中使用路由 - Angular2

如何将帐户信息放入 Facebook 登录表单并单击 Web 浏览器控件中的提交按钮?

如何在 WebBrowser 中以编程方式提交没有提交按钮的表单

如何在没有按钮的情况下提交表单?