【问题标题】:How do I add a loop when using R to scrape data?使用 R 抓取数据时如何添加循环?
【发布时间】:2017-11-20 03:44:05
【问题描述】:

我正在尝试根据 Trulia.com 的数据按邮政编码创建犯罪数据数据库。我有下面的代码,但到目前为止它只产生 1 行数据。在下面的代码中,Zipcodes 只是美国邮政编码的列表。谁能告诉我我需要添加什么才能使它贯穿我的整个列表“i”?

这里是 Trulia 页面之一的链接供参考:https://www.trulia.com/real_estate/20004-Washington/crime/

更新: 以下是可供下载的邮政编码:https://www.dropbox.com/s/uxukqpu0v88d7tf/Zip%20Code%20Database%20wo%20Boston.xlsx?dl=0

在意识到犯罪统计数据根据邮政编码以不同的顺序显示后,我这次也稍微更改了代码。是否可以让循环每个邮政编码产生 4 行?这目前有效,但仅生成数据集中的最后一个邮政编码。我不知道如何确保每个邮政编码的数据记录在不同的行上,因此它不会覆盖并且只留下最后一个邮政编码的一行。

请帮忙!!

 library(rvest)

 data=data.frame(Zipcodes)
 for(i in data$Zip.Code)
 {  
 site <- paste("https://www.trulia.com/real_estate/",i,"-Boston/crime/", sep="")
 site <- html(site)

 crime<- data.frame(zip =i,
        type =site %>% html_nodes(".brs") %>% html_text() ,
        stringsAsFactors=FALSE)
}
View(crime)

如果该代码不起作用,请尝试以下操作:

data=data.frame(Zillow_Data_for_R_Test)
for(i in data$Zip.Code)
site <- paste("https://www.trulia.com/real_estate/",i,"-Boston/crime/", sep="")
site <- read_html(site)
crime<- data.frame(zip =i,
         theft =site %>% html_nodes(".crime-text-0") %>% html_text() ,
         assault =site %>% html_nodes(".crime-text-1") %>% html_text() ,
         arrest =site %>% html_nodes(".crime-text-2") %>% html_text() ,
         vandalism =site %>% html_nodes(".crime-text-3") %>% html_text() ,
         robbery =site %>% html_nodes(".crime-text-4") %>% html_text() ,
         type =site %>% html_nodes(".clearfix") %>% html_text() ,
         stringsAsFactors=FALSE)
View(crime)

【问题讨论】:

  • 如果不包含一些示例数据(即Zipcodes),将很难回答您的问题。作为记录,尽管您的 for 循环不应该工作,因为 for(i in data$Zip.Code) 之后的代码应该用大括号括起来;即使这确实有效,您的 crime 对象也会在每次迭代时被覆盖。
  • 现在是考虑使用ret &lt;- lapply(data$Zip.Code, function(zc) { ... }) 的好时机,将所有data.frames 捕获到一个列表中,然后do.call(rbind, ret)。它需要对您当前的方法进行最少的更改(假设每个邮政编码都能正常工作)。
  • @jruf003 我已经添加了我正在使用的邮政编码数据库,还添加了您建议的括号。如何修复它,以便在每次迭代时都不会覆盖犯罪对象?
  • 对于一个完全可重现的示例,您应该添加类似head(Zipcodes) 的内容,以便我们知道您的邮政编码实际是什么。关于您的循环,@r2evans 已经提供了如何避免覆盖的答案。它使用 lapply 而不是 for 循环。 lapply 在您的情况下效率更高,R 代码也更优雅。效率较低/优雅的方法是初始化一个空的 data.frame 犯罪,其行数等于邮政编码的数量,然后在 for 循环中执行类似于 crime[i,] &lt;- scrapeddata 的分配。
  • 嗨@ManuelBickel 谢谢你的回复,我不知道如何使用 lapply 功能......我会为这种情况写什么代码?

标签: r loops web-scraping


【解决方案1】:

@r2evans 的评论已经给出了答案。由于@ShanCham 询问如何实际实现这一点,我想用以下代码进行指导,这比评论更冗长,因此不能作为附加评论发布。

library(rvest)

#only two exemplary zipcodes, could be more, of course
zipcodes <- c("02110", "02125")

crime <- lapply(zipcodes, function(z) {

  site <- read_html(paste0("https://www.trulia.com/real_estate/",z,"-Boston/crime/"))

           #for illustrative purposes:
           #introduced as.numeric to numeric columns
           #exluded some of your other columns and shortenend the current text in type
           data.frame(zip = z,
                      theft = site %>% html_nodes(".crime-text-0") %>% html_text() %>% as.numeric(),
                      assault = site %>% html_nodes(".crime-text-1") %>% html_text() %>% as.numeric() ,
                      type = site %>% html_nodes(".clearfix") %>% html_text() %>% paste(collapse = " ") %>% substr(1, 50) ,
                      stringsAsFactors=FALSE)
})

class(crime)
#list

#Output are lists that can be bound together to one data.frame
crime <- do.call(rbind, crime)

#crime is a data.frame, hence, classes/types are kept
class(crime$type)
# [1] "character"
class(crime$assault)
# [1] "numeric"

【讨论】:

  • 不错的答案,但我认为site &lt;- read_html(paste0("https://www.trulia.com/real_estate/",i,"-Boston/crime/")) 中的i 应该替换为z
  • 你是对的,很抱歉错字并感谢您强调它,我在复制部分代码时忘记更改它。我现在已经在我的回答中更正了。
猜你喜欢
  • 2019-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
  • 2016-05-03
  • 1970-01-01
  • 2018-10-20
  • 1970-01-01
相关资源
最近更新 更多