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

时间:2016-01-16 18:59:54

标签: r web-scraping html-form rvest

我正在尝试使用html_session()&amp ;;来抓取需要身份验证的网页。来自rvest包的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(帐户,登录)

我为submit_form函数获得的错误是:     名称错误(提交)[[1]]:下标超出范围

对于如何解决这个问题的任何想法表示赞赏。 谢谢

1 个答案:

答案 0 :(得分:11)

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

但是,我们可以通过猴子修补基础函数rvest:::submit_request来解决这个问题。

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

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

然而,尽管如此,它在两种情况下失败了:

  1. 没有type元素。
  2. type元素为NULL
  3. 这两种碰巧发生在美联航登录表单上。我们可以通过在函数内添加两个检查来解决这个问题。

    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")
    

    这有效!

    (好吧,&#34;工作&#34;是用词不当。由于美联航采用更积极的身份验证要求 - 包括已知的浏览器 - 这导致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")