Как передать несколько значений в форму представления rvest
Это продолжение предыдущей темы. Код работает фантастически для одного значения, но я получаю следующую ошибку при попытке передать более 1 значения, я получаю ошибку, основанную на длине функции. Ошибка в vapply(элементы, кодирование, символ (1)): значения должны быть длиной 1, а результат FUN (X [ 1]) - длиной 3
Вот пример кода. В большинстве случаев мне удавалось просто назвать объект и очистить его.
library(httr)
library(rvest)
library(dplyr)
b<-c('48127','48180','49504')
POST(
url = "http://www.nearestoutlet.com/cgi-bin/smi/findsmi.pl",
body = list(zipcode = b),
encode = "form"
) -> res
Мне было интересно, если цикл для вставки значений в форму будет правильным путем? Однако мои навыки написания циклов все еще находятся в стадии разработки, и я не уверен, где их разместить; кроме того, когда я вызываю цикл, он не печатает построчно, он просто возвращает нулевые результаты.
#d isn't listed in the above code as it returns null
d<-for(i in 1:3){nrow(b)}
2 ответа
Вот подход для отправки нескольких запросов POST
library(httr)
library(rvest)
b <- c('48127','48180','49504')
Для каждого элемента в b выполните функцию, которая отправит соответствующий запрос POST
res <- lapply(b, function(x){
res <- POST(
url = "http://www.nearestoutlet.com/cgi-bin/smi/findsmi.pl",
body = list(zipcode = x),
encode = "form"
)
res <- read_html(content(res, as="raw"))
})
Теперь для каждого элемента списка res
Вы должны выполнить шаги синтаксического анализа, описанные в hrbrmstr: Как я могу очистить CGI-корзину с помощью rvest и R?
library(tidyverse)
Я буду использовать код hrbrmstr, так как он король, и он вам уже понятен. Единственное, что мы делаем здесь, это выполняем это на каждом элементе res
список.
res_list = lapply(res, function(x){
rows <- html_nodes(x, "table[width='300'] > tr > td")
ret <- data_frame(
record = !is.na(html_attr(rows, "bgcolor")),
text = html_text(rows, trim=TRUE)
) %>%
mutate(record = cumsum(record)) %>%
filter(text != "") %>%
group_by(record) %>%
summarise(x = paste0(text, collapse="|")) %>%
separate(x, c("store", "address1", "city_state_zip", "phone_and_or_distance"), sep="\\|", extra="merge")
return(ret)
}
)
или используя map
от purrr
res %>%
map(function(x){
rows <- html_nodes(x, "table[width='300'] > tr > td")
data_frame(
record = !is.na(html_attr(rows, "bgcolor")),
text = html_text(rows, trim=TRUE)
) %>%
mutate(record = cumsum(record)) %>%
filter(text != "") %>%
group_by(record) %>%
summarise(x = paste0(text, collapse="|")) %>%
separate(x, c("store", "address1", "city_state_zip", "phone_and_or_distance"),
sep="\\|", extra="merge") -> ret
return(ret)
}
)
Если вы хотите это в кадре данных:
res_df <- data.frame(do.call(rbind, res_list), #rbinds list elements
b = rep(b, times = unlist(lapply(res_list, length)))) #names the rows according to elements in b
Вы можете поместить значения в пост, как показано ниже,
b<-c('48127','48180','49504')
for(i in 1:length(b)) {
POST(
url = "http://www.nearestoutlet.com/cgi-bin/smi/findsmi.pl",
body = list(zipcode =b[i]),
encode = "form"
) -> res
# YOUR CODES HERE (for getting content of the page etc.)
}
Но поскольку для каждого другого значения почтового индекса значение res будет отличаться, вам нужно поместить остальные коды в область, которую я прокомментировал. В противном случае вы получите только последнее значение.