Как отправить форму входа в пакет Rvest без аргумента кнопки
Я пытаюсь очистить веб-страницу, требующую аутентификации, используя html_session() & html_form() из пакета rvest. Я нашел это, например, предоставленное Хэдли Уикхем, но не могу настроить его для своего случая.
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 ("email","password")
Я также не знаю, как ссылаться на кнопку отправки, поэтому я попытался: submit_form(учетная запись, логин)
Ошибка, которую я получил для функции submit_form: Ошибка в именах (отправляет)[[1]]: индекс за пределами границ
Любая идея о том, как это сделать, приветствуется. Спасибо
1 ответ
В настоящее время этот номер совпадает с открытым № 159 в rvest
пакет, который вызывает проблемы, когда не все поля в форме имеют 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")
И это работает!
(Ну, "работает" - это неправильное название. Из-за того, что 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")