如何在rvest提交表单中传递多个值

时间:2017-10-15 19:22:33

标签: r web-scraping rvest

这是a prior thread的后续行动。代码对于单个值工作得非常好,但是当我尝试传递多于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

我想知道将值插入表单的循环是否是正确的方法?然而,我的循环写作技巧仍处于开发阶段,我不确定将它放在何处;另外,当我调用循环时,它不会逐行打印,只返回null结果。

#d isn't listed in the above code as it returns null    
d<-for(i in 1:3){nrow(b)}

2 个答案:

答案 0 :(得分:1)

这是一种发送多个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解释的解析步骤:How can I Scrape a CGI-Bin with rvest and 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

答案 1 :(得分:0)

您可以将值放在帖子中,如下所示

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

    }

但是因为对于每个不同的邮政编码值,&#34; res&#34;值将有所不同,您需要将其余代码放在我评论的区域内。否则你只得到最后一个值。