R webscraping设置关键字

时间:2017-12-06 09:28:44

标签: r web-scraping keyword

我正在从联合国网站的世界粮食计划署进行网络搜索,以建立一个包括粮食安全更新的数据集(http://www.fao.org/countryprofiles/en/)。 包是:rvest,stringr,tidyr,data.table,plyr,xml2,jsonlite。 然而,我已导入我的数据集国家名称,文章的URL,文章的标题和文章的文本。 现在,为了更容易解析,我将建立一个新的变量,包括我感兴趣的一些关键词(例如“食物安全”,“干旱”等),并注意上述关键词的副本。 这个变量将极大地简化我的研究。 有什么建议吗?

这是我正在使用的基本代码。

## 01. Creating a function in order to scrape data from a website (in this case, FAO's)

WFP_get_news <- function(countries) {                                                      GET(
url = "http://www1.wfp.org/countries/common/allnews/en/",
query = list(countries=countries)
 ) -> res

 warn_for_status(res)

 if (status_code(res) > 399) return(NULL)

 out <- content(res, as="text", encoding="UTF-8")
 out <- jsonlite::fromJSON(out)
 out$countries <- countries

 tbl_df(out)
 }


## 02. Setting all the Country urls in order for them to be automatically scraped 

pb <- progress_estimated(length(countrycode_data$countries[]))   
map_df(countrycode_data$countries[], ~{
pb$tick()$print()
Sys.sleep(5) 
wfp_get_news(.x)
}) -> xdf



## 03. Setting keywords (of course, this process is arbitrary: one can    decide any keywor s/he prefers)
keywords <- c("drought", "food security")                                        


keyword_regex <- sprintf("(%s)", paste0(keywords, collapse="|"))


## 04. Setting the keywords search
bind_cols(                                                                                  
 xdf,
 stri_match_all_regex(tolower(xdf$bodytext), keyword_regex) %>% 
 map(~.x[,2]) %>% 
 map_df(~{ 
 res <- table(.x, useNA="always")
 nm <- names(res)
 nm <- ifelse(is.na(nm), "NONE", stri_replace_all_regex(nm, "[ -]", "_"))
 as.list(set_names(as.numeric(res), nm))
 })
 ) %>% 
 select(-NONE) -> xdf_with_keyword_counts

我从第04点得到的结果是

Error in overscope_eval_next(overscope, expr) : 
 object "NONE" not found
Furthermore: Warning message:
Unknown or uninitialised column: 'data.frame'. 

有任何线索吗?

1 个答案:

答案 0 :(得分:0)

首先,要保留的一般规则是切割/粘贴&gt;这是功能的2-3倍。

我们需要一些帮助:

library(countrycode)
library(httr)
library(rvest)
library(stringi)
library(tidyverse)

这是一个函数,您可以使用iso3代码调用以获取所需的数据[框架]:

fao_get_news <- function(iso3) {

  GET(
    url = "http://www.fao.org/countryprofiles/common/allnews/en/",
    query = list(iso3=iso3)
  ) -> res

  warn_for_status(res)

  if (status_code(res) > 399) return(NULL)

  out <- content(res, as="text", encoding="UTF-8")
  out <- jsonlite::fromJSON(out)
  out$iso3 <- iso3

  tbl_df(out)

}

现在,我们使用iso3包中的辅助数据帧迭代所有可能的countrycode代码。

注意:在接下来的2行中删除[1:20]以进行制作以获得所有我不需要的所有数据,因此我没有燃烧时间/带宽。如果你完全关心道德规范,不要被禁止或者打击非营利组织的服务器,那么请将Sys.sleep(5)放在那里。如果你自私,那么仍然保持在那里b / c你的需求不是&gt; t&gt;粮农组织。

pb <- progress_estimated(length(countrycode_data$iso3c[1:20]))
map_df(countrycode_data$iso3c[1:20], ~{
  pb$tick()$print()
  Sys.sleep(5) # no crawl delay specified in site robots.txt so this is the ethical default
  fao_get_news(.x)
}) -> xdf

这为我们提供了一个漂亮,整洁的数据框,其中包含所有新闻(带有iso3字段):

glimpse(xdf)
## Observations: 736
## Variables: 10
## $ uid         <chr> "1069933", "1069560", "1045264", "1044139", "103833...
## $ table       <chr> "news", "news", "news", "news", "news", "news", "ne...
## $ title       <chr> "FAO Calls for Stronger Collaboration on Transbound...
## $ date        <chr> "1511823600", "1511737200", "1508191200", "15081048...
## $ bodytext    <chr> "28 November 2017- Chief Veterinary Officers and ex...
## $ date_format <chr> "28/11/2017", "27/11/2017", "17/10/2017", "16/10/20...
## $ image       <chr> "http://www.fao.org/fileadmin/user_upload/rne/img/I...
## $ pid         <chr> "50840", "16275", "70992", "16275", "2330", "40990"...
## $ detail_pid  <chr> "/neareast/news/view/en/c/1069933/", "/asiapacific/...
## $ iso3        <chr> "AFG", "AFG", "AFG", "AFG", "AFG", "AFG", "AFG", "A...

将所有关键字(小写)放在此处:

keywords <- c("drought", "food security")

我们将构建一个正则表达式

keyword_regex <- sprintf("(%s)", paste0(keywords, collapse="|"))

现在,我们将关键字列添加到现有数据框中。 stri_match… ++正在做的大纲是针对每个新闻blob:

  • 小写新闻blob
  • 查找新闻blob中每个关键字(如果有)的所有匹配项
  • 捕获出现次数和关键字
  • 的计数
  • (轻轻地)确保关键字可以是有效的列名
  • 为每个找到的关键字创建一个新列
  • 没有任何关键字的blob只有NA找到的计数值

我们可以制作关键字结果数据框count()spread(),但不是快速操作。使用table()意味着更多的输入,但更快的结果。

bind_cols(
  xdf,
  stri_match_all_regex(tolower(xdf$bodytext), keyword_regex) %>% 
    map(~.x[,2]) %>% 
    map_df(~{ 
      res <- table(.x, useNA="always")
      nm <- names(res)
      nm <- ifelse(is.na(nm), "NONE", stri_replace_all_regex(nm, "[ -]", "_"))
      as.list(set_names(as.numeric(res), nm))
    })
) %>% 
  select(-NONE) -> xdf_with_keyword_counts

结果如下:

glimpse(xdf_with_keyword_counts)
## Observations: 736
## Variables: 12
## $ uid           <chr> "1069933", "1069560", "1045264", "1044139", "1038339", "...
## $ table         <chr> "news", "news", "news", "news", "news", "news", "news", ...
## $ title         <chr> "FAO Calls for Stronger Collaboration on Transboundary A...
## $ date          <chr> "1511823600", "1511737200", "1508191200", "1508104800", ...
## $ bodytext      <chr> "28 November 2017- Chief Veterinary Officers and experts...
## $ date_format   <chr> "28/11/2017", "27/11/2017", "17/10/2017", "16/10/2017", ...
## $ image         <chr> "http://www.fao.org/fileadmin/user_upload/rne/img/IMG_64...
## $ pid           <chr> "50840", "16275", "70992", "16275", "2330", "40990", "40...
## $ detail_pid    <chr> "/neareast/news/view/en/c/1069933/", "/asiapacific/news/...
## $ iso3          <chr> "AFG", "AFG", "AFG", "AFG", "AFG", "AFG", "AFG", "ALA", ...
## $ food_security <int> NA, NA, 2, 1, NA, 1, NA, NA, NA, 1, NA, NA, NA, NA, 1, N...
## $ drought       <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ...