【问题标题】:Efficient scraping using rvest and for loop使用 rvest 和 for 循环进行高效抓取
【发布时间】:2020-04-03 21:57:47
【问题描述】:

我正在尝试使用 rvest 收集大量辩论。辩论在不同的网页上进行,我从搜索结果中收集这些网页的网址。有超过 1000 页的搜索结果,以及 20,000 页的辩论(即 20,000 个网址)。

我目前的方法成功地从辩论页面中抓取了我需要的数据,但是,对于超过 20 页的搜索结果(即只有 20,000 个网址中的 400 个),处理需要很长时间。

我目前正在使用一个 forloop,它遍历我的 url 列表并使用我需要的内容刮取 5 个 html 节点(见下文)。这会为我正在抓取的每个内容节点创建一个向量,然后将其组合成一个数据框进行分析。我认为这种方法意味着我为我需要的不同 html 节点分别调用每个网页 5 次。

有什么方法可以更有效地抓取它吗?我确信有一种方法可以做到这一点,这样它会在一次调用每个 url 时刮掉所有 5 个节点,而不是迭代 5 次。此外,是否可以在 for 循环中动态填充数据帧,而不是存储 5 个不同的向量。另外,也许我可以使用并行处理同时抓取多个网址?我很困惑。

#create empty
speakerid <- c()
parties <- c()
contributions <- c()
titles <- c()
debatedates <- c()

#for loop to scrape relevant content
for(i in debate_urls$url) { 

  debate_urls <- read_html(i)
  speaker <- debate_urls %>% html_nodes(".debate-speech__speaker__name") %>% html_text("")
  speakerid = append(speakerid, speaker)

  debate_urls <- read_html(i)
  party <- debate_urls %>% html_nodes(".debate-speech__speaker__position") %>% html_text("")
  parties = append(parties, party)

  debate_urls <- read_html(i)
  contribution <- debate_urls %>% html_nodes(".debate-speech__speaker+ .debate-speech__content") %>% html_text("p")
  contributions = append(contributions, contribution)

  debate_urls <- read_html(i)
  title <- debate_urls %>%
    html_node(".full-page__unit h1") %>%
    html_text()
  titles = append(titles, rep(title,each=length(contribution)))

  debate_urls <- read_html(i)
  debatedate <- debate_urls %>%
    html_node(".time") %>%
    html_text("href")
  debatedates = append(debatedates, rep(debatedate,each=length(contribution)))
  }

debatedata <- data.frame(Title=titles, Date=debatedates,Speaker=speakerid,Party=parties,Utterance=contributions)

注意:debate_urls 是辩论页面的 url 列表。

任何有关如何更有效地完成任何部分的帮助将不胜感激!

【问题讨论】:

  • 减慢进程的一个问题是在循环的每次迭代中重复调用debate_urls &lt;- read_html(i)。每次拨打read_html 都需要访问互联网并等待回复。在循环开始时调用一次,然后使用“debate_urls”作为循环剩余部分的常量。另外,请参阅下面有关在循环中增长向量的答案。
  • 啊,是的,这很愚蠢,感谢您强调它。现在已经修好了。可能会有所帮助,但不确定有多少。

标签: r for-loop web-scraping rvest


【解决方案1】:

有一件事肯定是低效的,因为向量不断增长。您知道它们有多长 (length(debate_urls$url)),因此您可以提前设置向量:

n <- length(debate_urls$url)
speakerid <- character(n)
parties <- character(n)
contributions <- character(n)
titles <- character(n)
debatedates <- character(n)

然后你的 for 循环会这样做:

for(idx in seq_along(debate_urls$url)){
    i <- debate_urls$url[idx]

    debate_urls <- read_html(i)
    speaker <- debate_urls %>% html_nodes(".debate-speech__speaker__name") %>% html_text("")
    speakerid[idx] <- speaker
    ...
}

我不太确定的是,与抓取时间相比,这是否有很大的影响。

【讨论】:

  • 谢谢,不幸的是我不这么认为。每个辩论页面可能(通常确实)有多个未知的“贡献”,每个都是一个新条目,因此无法预先确定向量的长度。这些贡献中的每一个都与演讲者、partyid 以及辩论标题和日期相关联(这对于后续分析是必要的)。因此,即使我们提前知道辩论标题和日期的数量,我们也不知道它们将关联的贡献数量。
  • @MCC89,参见:burns-stat.com/pages/Tutor/R_inferno.pdf,第 2 章,第 14 页!关键是制作一个数据框列表,然后在最后绑定它们。
  • 啊-是的。没有发现rep() 电话。除了@Dave2e 关于绑定数据框的评论之外,另一件事是将这些视为单独的表可能更简洁。有些变量在贡献中是不变的,所以你真正得到的是一组相关的表。我怀疑这是速度的主要贡献者,但更好地捕捉数据结构
  • 另外,假设这是Hansard,看起来应该有一个API,这可能比抓取HTML更容易?我认为这就是这些家伙正在做的事情:theyworkforyou.com/api/docs/getDebates
猜你喜欢
  • 1970-01-01
  • 2019-05-09
  • 2015-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-03
  • 2018-10-13
相关资源
最近更新 更多