首页 > 解决方案 > R网页抓取> 1000页,超时

问题描述

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

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 个列表,但每个都是字符(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()
                    })

标签: rweb-scraping

解决方案


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")intohtml_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
    })

}

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


推荐阅读