R网页抓取> 1000页,超时

时间:2019-02-27 22:32:06

标签: r web-scraping

我有以下代码来抓取工作评价。

reviewDate <- lapply(paste0('https://www.glassdoor.com/Interview/Sears-Interview-Questions-E37984_P', 1:1100, '.htm', sep=''),
                    function(url){
                        url %>% read_html() %>% 
                            html_nodes(".date") %>% 
                            html_text()
                    })

如果我只有几百页(我可以运行1:280),则此代码有效,但是有两个问题: 1)似乎重复了所有内容,所以我每条信息都有2条信息,并且 2)当我为所有1100页运行它时,出现以下错误,这将停止循环:

Error in open.connection(x, "rb") : HTTP error 504.

我阅读了有关将Sys.sleep()添加到代码中的信息,但是我不确定它在代码中的位置以使其正常工作。我也想知道是否还有其他更好的解决方法?

最后,我有多个节点。我可以将它们全部添加到一个函数中并将所有内容对齐到一个数据框中吗?以下代码对我不起作用,因为它返回的列表为2,但是每个都是character(0)。 (我只按1:2进行了快速试用。)

reviewDate <- lapply(paste0('https://www.glassdoor.com/Interview/Sears-Interview-Questions-E37984_P', 1:2, '.htm', sep=''),
                    function(url){
                        url %>% read_html() %>% 
                            html_nodes(".date") %>% 
                            html_nodes(".summary") %>% 
                            html_nodes(".authorJobTitle") %>% 
                            html_nodes(".pros") %>% 
                            html_nodes(".cons") %>% 
                            html_nodes(".adviceMgmt") %>% 
                            html_text()
                    })

1 个答案:

答案 0 :(得分:0)

Sys.sleep仅用于使循环在每次迭代时暂停。因此它可以循环到任何地方。在这里,我们可以将其放在开头,这样就不会干扰输出,因为您没有使用return语句从该函数显式返回某些内容

reviewDate <- lapply(paste0('https://www.glassdoor.com/Interview/Sears-Interview-Questions-E37984_P', 1:1100, '.htm', sep=''),
                    function(url){
                        Sys.sleep(.1)
                        url %>% read_html() %>% 
                            html_nodes(".date") %>% 
                            html_text()
                    })

请注意,这不能保证您不会收到超时错误。垃圾邮件可能会导致此类错误,但也可能由于您无法控制的原因而发生。理想情况下,您将希望逃避或坚持尝试获取所需的数据。 tryCatch在那里,因此您的程序不会在出现故障时立即停止。这是一种方法

getData = function(url){
    Sys.sleep(.1)
    tryCatch({
        url %>% read_html() %>% 
            html_nodes(".date") %>% 
            html_text()
    }, error = function(e){
        NULL
    })

}

n = 1100
scrapedData = vector(length = n,mode = 'list')
while(TRUE){
    indexes = which(sapply(scrapedData,is.null))
    for (i in indexes){
        scrapedData[[i]] = getData(paste0('https://www.glassdoor.com/Interview/Sears-Interview-Questions-E37984_P', i, '.htm'))
    }
    if(!any(sapply(scrapedData,is.null))){
        break
    }
}

在完成一轮请求后,我回去问所有我错过的事情。 tryCatch确保不会停止执行。请注意,如果您的链接确实很糟糕,它将永远运行,因此您可能希望限制它的运行次数。

对于您的第二点,我不知道您为什么认为您的方法应该有效,但这暗示了对管道或html_nodes函数的基本误解。将html_nodes(".date")的输出通过管道传输到html_nodes(".summary")时,该对象不再具有summary部分。您将date与上一条命令隔离开,因此您一无所获。这些需要分别调用并分配给不同的变量

您需要做的就是确保函数返回一个可以稍后合并到数据框中的数组。

喜欢

getData = function(url){
    Sys.sleep(.1)
    tryCatch({
        html = url %>% read_html()
        date =html %>% 
            html_nodes(".date") %>% 
            html_text()
        summary = html %>% 
            html_nodes('.summary') %>%
             html_text
        return(list(date,summary))
    }, error = function(e){
        NULL
    })

}

请注意,这里我返回一个列表,因为读取的对象数量似乎不匹配,并且使它们匹配的确切方法不在问题范围内。您需要查看页面并获得更好的选择器来抓取您想要的内容。