【问题标题】:Web-Scraping with R使用 R 进行网页抓取
【发布时间】:2014-12-28 19:26:06
【问题描述】:

我在从网站抓取数据时遇到了一些问题。首先,我对网页抓取没有太多经验...... 我的计划是使用 R 从以下网站抓取一些数据: http://spiderbook.com/company/17495/details?rel=300795

特别想提取本站文章的链接。

到目前为止我的想法:

xmltext <- htmlParse("http://spiderbook.com/company/17495/details?rel=300795")
sources <- xpathApply(xmltext,  "//body//div")
sourcesCharSep <- lapply(sourcesChar,function(x) unlist(strsplit(x, " "))) 
sourcesInd <- lapply(sourcesCharSep,function(x) grep('"(http://[^"]*)"',x)) 

但这并没有显示预期的信息。一些帮助将在这里非常感激!谢谢!

最好的 克里斯托夫

【问题讨论】:

  • 好吧,对于初学者,您需要将 url 放在第一行的引号中...
  • 是的,没错。我只是将它粘贴在那里,因为它是一个更大的脚本的一部分,它在多个页面和 URL 上循环。

标签: r web-scraping web-crawler


【解决方案1】:

你选择了一个棘手的问题来学习。

本网站使用 javascript 加载文章信息。换句话说,链接加载了一组脚本,这些脚本在页面加载时运行以获取信息(可能来自数据库)并将其插入到 DOM 中。 htmlParse(...) 只是抓取基本 html 并对其进行解析。所以你想要的链接根本不存在。

AFAIK 解决这个问题的唯一方法是使用 RSelenium 包。这个包本质上允许你通过看起来像浏览器模拟器的东西传递基本的 html,它确实运行脚本。 Rselenium 的问题在于你不仅需要下载包,还需要一个“Selenium Server”。 This link 很好地介绍了RSelenium

完成此操作后,在浏览器中检查源代码会发现文章链接都位于具有class=doclink 的锚标记的href 属性中。这很容易使用 xPath 进行提取。 NEVER NEVER NEVER 使用正则表达式解析 XML。

library(XML)
library(RSelenium)
url <- "http://spiderbook.com/company/17495/details?rel=300795"
checkForServer()        # download Selenium Server, if not already presnet
startServer()           # start Selenium Server
remDr <- remoteDriver() # instantiates a new driver
remDr$open()            # open connection
remDr$navigate(url)     # grab and process the page (including scripts)
doc   <- htmlParse(remDr$getPageSource()[[1]])
links <- as.character(doc['//a[@class="doclink"]/@href'])
links
# [1] "http://www.automotiveworld.com/news-releases/volkswagen-selects-bosch-chargepoint-e-golf-charging-solution-providers/"
# [2] "http://insideevs.com/category/vw/"                                                                                    
# [3] "http://www.greencarcongress.com/2014/07/20140711-vw.html"                                                             
# [4] "http://www.vdubnews.com/volkswagen-chooses-bosch-and-chargepoint-as-charging-solution-providers-for-its-e-golf-2"     
# [5] "http://investing.businessweek.com/research/stocks/private/snapshot.asp?privcapId=84543228"                            
# [6] "http://insideevs.com/volkswagen-selects-chargepoint-bosch-e-golf-charging/"                                           
# [7] "http://www.calcharge.org/2014/07/"                                                                                    
# [8] "http://nl.anygator.com/search/volkswagen+winterbanden"                                                                
# [9] "http://nl.anygator.com/search/winterbanden+actie+volkswagen+caddy"

【讨论】:

【解决方案2】:

正如@jihoward 所说,RSelenium 将解决这个问题,并且不需要检查底层网站的净流量/解剖来找到合适的数量。我还要注意,如果phantomjs 安装在用户系统上,RSelenium 可以在没有Selenium Server 的情况下运行。在这种情况下RSelenium 可以直接驱动phantomjshttp://cran.r-project.org/web/packages/RSelenium/vignettes/RSelenium-headless.html有一个与无头浏览相关的小插曲

使用浏览器检查网络流量

在这种情况下,但是对流量的检查会产生以下名为 http://spiderbook.com/company/details/docs?rel=300795&docs_page=0 的 json 文件,它不受 cookie 保护或对用户代理字符串等不敏感。在这种情况下,可以执行以下操作:

library(RJSONIO)
res <- fromJSON("http://spiderbook.com/company/details/docs?rel=300795&docs_page=0")
> sapply(res$data, "[[", "url")
[1] "http://www.automotiveworld.com/news-releases/volkswagen-selects-bosch-chargepoint-e-golf-charging-solution-providers/"
[2] "http://insideevs.com/category/vw/"                                                                                    
[3] "http://www.greencarcongress.com/2014/07/20140711-vw.html"                                                             
[4] "http://www.vdubnews.com/volkswagen-chooses-bosch-and-chargepoint-as-charging-solution-providers-for-its-e-golf-2"     
[5] "http://investing.businessweek.com/research/stocks/private/snapshot.asp?privcapId=84543228"                            
[6] "http://insideevs.com/volkswagen-selects-chargepoint-bosch-e-golf-charging/"                                           
[7] "http://www.calcharge.org/2014/07/"                                                                                    
[8] "http://nl.anygator.com/search/volkswagen+winterbanden"                                                                
[9] "http://nl.anygator.com/search/winterbanden+actie+volkswagen+caddy"      

为 phantomJS 编写一个简单的函数来检查网络流量

使用RSeleniumphantomJS,我们还可以使用它来实时检查流量(目前仅在直接驱动phantomJS 时)。举个简单的例子,我们记录当前正在查看的网页请求和接收的呼叫,并将其存储在当前工作目录的“traffic.txt”中:

library(RSelenium)
pJS <- phantom()
remDr <- remoteDriver(browserName = "phantom")
remDr$open()
appUrl <- "http://spiderbook.com/company/17495/details?rel=300795"
psScript <- "var page = this;
             var fs = require(\"fs\");
             fs.write(\"traffic.txt\", 'WEBSITE CALLS\\n', 'w');
             page.onResourceRequested = function(request) {
                fs.write(\"traffic.txt\", 'Request: ' + request.url + '\\n', 'a');
             };
             page.onResourceReceived = function(response) {
                fs.write(\"traffic.txt\", 'Receive: ' + response.url + '\\n', 'a');
             };"

result <- remDr$phantomExecute(psScript)

remDr$navigate(appUrl)
urlTraffic <- readLines("traffic.txt")
> head(urlTraffic)
[1] "WEBSITE CALLS"                                                        
[2] "Request: http://spiderbook.com/company/17495/details?rel=300795"      
[3] "Receive: http://spiderbook.com/company/17495/details?rel=300795"      
[4] "Request: http://spiderbook.com/static/js/jquery-1.10.2.min.js"        
[5] "Request: http://spiderbook.com/static/js/lib/jquery.dropkick-1.0.2.js"
[6] "Request: http://spiderbook.com/static/js/jquery.textfill.js"          

> urlTraffic[grepl("Receive: http://spiderbook.com/company/details", urlTraffic)]
[1] "Receive: http://spiderbook.com/company/details/docs?rel=300795&docs_page=0"
[2] "Receive: http://spiderbook.com/company/details/docs?rel=300795&docs_page=0"

pJS$stop() # stop phantomJS

在这里我们可以看到收到的文件之一是"Receive: http://spiderbook.com/company/details/docs?rel=300795&amp;docs_page=0"

使用 phantomJS/ghostdriver 内置的 HAR 支持来检查流量

事实上phantomJS/ghostscript 会创建自己的HAR 文件,因此只需在我们驾驶phantomJS 时浏览页面,我们就可以访问所有请求/响应数据:

library(RSelenium)
pJS <- phantom()
remDr <- remoteDriver(browserName = "phantom")
remDr$open()
appUrl <- "http://spiderbook.com/company/17495/details?rel=300795"
remDr$navigate(appUrl)
harLogs <- remDr$log("har")[[1]]
harLogs <- fromJSON(harLogs$message)
# HAR contain alot of detail will just illustrate here accessing the data
requestURLs <- sapply(lapply(harLogs$log$entries, "[[", "request"), "[[","url")
requestHeaders <- lapply(lapply(harLogs$log$entries, "[[", "request"), "[[", "headers")
XHRIndex <- which(grepl("XMLHttpRequest", sapply(requestHeaders, sapply, "[[", "value")))

> harLogs$log$entries[XHRIndex][[1]]$request$url
[1] "http://spiderbook.com/company/details/docs?rel=300795&docs_page=0"

所以最后一个示例显示了查询phantomJS 生成的HAR 文件以查找XMLHttpRequest 请求,然后返回我们希望对应于我们在答案开头找到的json 文件的特定url。

【讨论】:

【解决方案3】:

任何浏览器的网络检查器都会告诉您它从哪里获取数据。在这种情况下,它似乎是通过 http://spiderbook.com/company/details/docs?rel=300795 的 JSON - 这意味着它是一个带有 jsonlite 的两个内衬:

> require(jsonlite)
> x=fromJSON("http://spiderbook.com/company/details/docs?rel=300795")
> x$data$url
[1] "http://www.automotiveworld.com/news-releases/volkswagen-selects-bosch-chargepoint-e-golf-charging-solution-providers/"
[2] "http://insideevs.com/category/vw/"                                                                                    
[3] "http://www.greencarcongress.com/2014/07/20140711-vw.html"                                                             
[4] "http://www.vdubnews.com/volkswagen-chooses-bosch-and-chargepoint-as-charging-solution-providers-for-its-e-golf-2"     
[5] "http://investing.businessweek.com/research/stocks/private/snapshot.asp?privcapId=84543228"                            
[6] "http://insideevs.com/volkswagen-selects-chargepoint-bosch-e-golf-charging/"                                           
[7] "http://www.calcharge.org/2014/07/"                                                                                    
[8] "http://nl.anygator.com/search/volkswagen+winterbanden"                                                                
[9] "http://nl.anygator.com/search/winterbanden+actie+volkswagen+caddy"      

我怀疑这部分 JSON 会告诉你返回的数据是否有更多页面:

> x$has_next
[1] FALSE

然后我怀疑从某个页面获取数据的 URL 有一个参数。

如何从公共 URL 中获取 JSON url?我不完全确定,因为我不知道“17495”在那里做什么......

【讨论】:

    猜你喜欢
    • 2018-02-15
    • 1970-01-01
    • 2015-09-06
    • 2017-10-05
    相关资源
    最近更新 更多