Результаты поиска с веб-очисткой в R

#r #xml #web-scraping #httr

#r #xml #веб-очистка #httr

Вопрос:

Я пытаюсь создать функцию, которая будет извлекать результаты поиска с этой веб-страницы, но я застрял, потому что я хочу, чтобы функция автоматизировала поиск нескольких фондов, и я не уверен, как пересмотреть функцию, чтобы она либо перебирала все строки в ‘mydf’, либо использовала один из apply() работает для получения того же эффекта цикла, чтобы очистить результаты для каждой строки в ‘mydf’.

Когда я запускаю приведенную ниже функцию для одной строки ‘mydf’, результаты верны, но когда я не указываю конкретную строку, я получаю следующую ошибку: Error in parse_url(url) : length(url) == 1 is not TRUE

Образец данных.фрейм:

 # construct sample data frame with Name, City, State:
name <- c("johnny carson foundation", "melinda gates foundation", "macarthur foundation")
city <- c("", "", "")
state <- c("", "", "")
mydf <- data.frame(name, city, state)

#replace spaces between words with ' ' for consistent formatting of 'url' object:
mydf$name <- str_replace_all(mydf$name, " ", " ")
mydf$city <- str_replace_all(mydf$city, " ", " ")
  

И моя текущая попытка выполнить функцию:

 get_data <- function(df) {
        # root components of url:
        root <- "http://apps.irs.gov/app/eos/allSearch.do?ein1=amp;names="
        root2 <- "amp;resultsPerPage=25amp;indexOfFirstRow=0amp;dispatchMethod=searchAllamp;city="
        root3 <- "amp;country=USamp;postDateFrom=amp;postDateTo=amp;exemptTypeCode=alamp;deductibility=allamp;sortColumn=orgNameamp;isDescending=falseamp;submitName=Search"
        
     
        # construct url by adding roots and search strings from 'mydf':
        url <- paste(root, mydf$name, root2, mydf$city, 'amp;state=', mydf$state, root3, sep = "")
        
        gt <- GET(url)
        
        content2 <- content(gt)
        
        parsedHtml <- htmlParse(content2, asText = TRUE)
        
        
        # Scraped results to be populated into 'mydf':
        mydf$result_org <- ifelse(str_starts(xpathSApply(parsedHtml, "//div[@class='row results-body-row']", xmlValue, trim = TRUE), 
                                             "Your search did not return any results"), NA,
                                  xpathSApply(parsedHtml, "//h3[@class='result-orgname']", xmlValue, trim = TRUE)) # Name
        mydf$result_ein <- ifelse(str_starts(xpathSApply(parsedHtml, "//div[@class='row results-body-row']", xmlValue, trim = TRUE), 
                                             "Your search did not return any results"), NA,
                                  xpathSApply(parsedHtml, "/html/body/div[3]/div[13]/div/div/div[1]/div[2]/div/ul/li/div[1]/span[1]", xmlValue)) # EIN
        mydf$result_city <- ifelse(str_starts(xpathSApply(parsedHtml, "//div[@class='row results-body-row']", xmlValue, trim = TRUE), 
                                              "Your search did not return any results"), NA,
                                   xpathSApply(parsedHtml, "/html/body/div[3]/div[13]/div/div/div[1]/div[2]/div/ul/li/div[1]/span[2]", xmlValue)) # City
        mydf$result_state <- ifelse(str_starts(xpathSApply(parsedHtml, "//div[@class='row results-body-row']", xmlValue, trim = TRUE), 
                                               "Your search did not return any results"), NA,
                                    xpathSApply(parsedHtml, "/html/body/div[3]/div[13]/div/div/div[1]/div[2]/div/ul/li/div[1]/span[3]", xmlValue, trim = TRUE)) # State
        mydf$result_country <- ifelse(str_starts(xpathSApply(parsedHtml, "//div[@class='row results-body-row']", xmlValue, trim = TRUE), 
                                                 "Your search did not return any results"), NA,
                                      xpathSApply(parsedHtml, "/html/body/div[3]/div[13]/div/div/div[1]/div[2]/div/ul/li/div[1]/span[4]", xmlValue)) # Country
        
}


get_data(mydf)


mydf
  

Заранее большое спасибо и приношу извинения за мой беспорядочный и неэлегантный код!

Ответ №1:

  1. Вам нужно указать состояние как All States .
  2. Вам необходимо сопоставить URL-адреса с purrr::map_dfr()
 
library(rvest)
# construct sample data frame with Name, City, State:
name <- c("johnny carson foundation", "melinda gates foundation", "macarthur foundation")
city <- c("", "", "")
state <- c("All States", "All States", "All States")
mydf <- data.frame(name, city, state)

#replace spaces between words with ' ' for consistent formatting of 'url' object:
mydf$name <- str_replace_all(mydf$name, " ", " ")
mydf$city <- str_replace_all(mydf$city, " ", " ")

# root components of url:
root <- "http://apps.irs.gov/app/eos/allSearch.do?ein1=amp;names="
root2 <- "amp;resultsPerPage=25amp;indexOfFirstRow=0amp;dispatchMethod=searchAllamp;city="
root3 <- "amp;country=USamp;postDateFrom=amp;postDateTo=amp;exemptTypeCode=alamp;deductibility=allamp;sortColumn=orgNameamp;isDescending=falseamp;submitName=Search"


# construct url by adding roots and search strings from 'mydf':
url <- paste(root, mydf$name, root2, mydf$city, 'amp;state=', mydf$state, root3, sep = "")

data <- 
  purrr::map_dfr(
    url,
    function(url) {
      items <- read_html(url) %>% html_nodes("ul.views-row > li")
      data.frame(
        name = items %>% html_node("h3") %>% html_text() %>% stringi::stri_trans_totitle(),
        ein = items %>% html_node(xpath = "./div[@class='search-excerpt']/span[1]") %>% html_text(),
        city = items %>% html_node(xpath = "./div[@class='search-excerpt']/span[2]") %>% html_text(),
        state = items %>% html_node(xpath = "./div[@class='search-excerpt']/span[3]") %>% html_text(),
        country = items %>% html_node(xpath = "./div[@class='search-excerpt']/span[4]") %>% html_text()
      )
    }
  )
  

Комментарии:

1. Спасибо, @xwhitelight это большое улучшение по сравнению с моей неуклюжей попыткой. Два последующих вопроса: во время моих попыток я смог получить результаты с пустыми («») записями для состояния (а также с фактическими значениями: WA, NY и т. Д.). Была ли причина, по которой вам нужно было заполнить его «Все состояния»? Кроме того, в идеале хотелось бы, чтобы мои результаты включали NAs для любых строк, которые не возвращают результаты, и только верхний результат для каждого поиска (или, возможно, 2-й / 3-й / 4-й … результаты отображаются в виде дополнительных столбцов в той же строке, что и верхний результат), так что исходный ‘mydf’ будет объединен срезультаты легко. Есть идеи?