首页 > 解决方案 > 如何正确存储用于网络抓取的 html 文件列表?

问题描述

使用 rvest 包,我从 https://minimalistbaker.com抓取了烹饪食谱的信息(例如标题、评论数量、平均评分、烹饪时间等),一切正常。

然而,问题是存储包含配方页面的列表对象并稍后将它们重新加载到 R 中(以避免再次向页面发送垃圾邮件请求)

将 recipes_html 对象(参见下面的示例代码)保存为 .rds 文件并稍后重新加载时,我将收到以下错误:

 recipes_html
"Error in doc_is_html(x$doc) : external pointer is not valid"

虽然它应该是

 recipes_html[[1]]
{html_document}
<html lang="en-US">
[1] <head>\n<meta http-equiv="Content-Type" content="text/html; 
charset=UTF-8">\n<meta charset="UTF-8">\n<script type="tex ...
[2] <body class="post-template-default single single-post postid-42142 
single-format-standard woocommerce-no-js header-ful ...

寻找解决方案我遇到了 https://github.com/tidyverse/rvest/issues/181#issuecomment-395064636 或此 Write xml-object to disk

但是,像 xml2::write_html() 这样的函数将返回错误,因为我的对象 recipes_html 是一个列表

 Error in UseMethod("write_html") : 
 no applicable method for 'write_html' applied to an object of class "list"

class(recipes_html)
[1] "list"
class(recipes_html[[1]])
[1] "xml_document" "xml_node" 

那么,存储 recipes_html 列表对象的适用方法是什么,以便我以后可以简单地重新加载它并继续抓取?最好不要拆分列表并单独存储每个页面(作为我构建的用于在后续步骤中提取信息的函数,循环遍历页面列表,效果很好。)

 #Reproducible code
 library(rvest)

example_links<-read_html("https://minimalistbaker.com/recipe-index/")%>%html_nodes(".entry-title a")%>%html_attr("href")%>%head()

#nytnyt function to introduce random waiting time between each request
nytnyt<- function (periods= c(1, 2.5)){
   tictoc <-runif(1, periods[1], periods[2])
   cat(paste0(Sys.time()), "- Sleeping for ", round(tictoc, 2),
   "seconds\n")
   Sys.sleep(tictoc)
 }


recipes_html<-list()                            #save the list to 
  for (i in 1:length(example_links)) {
   recipes_html[[i]]<-read_html(example_links[i])
   print(i)
   nytnyt(periods = c(2, 4))                   #make R wait between 2 to 4 seconds between each request
} 


saveRDS(recipes_html, "example_recipes.rds")      
readRDS("example_recipes.rds")                     #saving and loading the object again won't work.

标签: rxmllistweb-scrapingrvest

解决方案


推荐阅读