R - 等待页面加载到带有 PhantomJS 的 RSelenium 中

R - Waiting for page to load in RSelenium with PhantomJS

我整理了一个从 Expedia 上抓取 prices/airlines 的粗糙抓取工具:

# Start the Server
rD <- rsDriver(browser = "phantomjs", verbose = FALSE)

# Assign the client
remDr <- rD$client

# Establish a wait for an element
remDr$setImplicitWaitTimeout(1000)

# Navigate to Expedia.com
appurl <- "https://www.expedia.com/Flights-Search?flight-type=on&starDate=04/30/2017&mode=search&trip=oneway&leg1=from:Denver,+Colorado,to:Oslo,+Norway,departure:04/30/2017TANYT&passengers=children:0,adults:1"
remDr$navigate(appURL)

# Give a crawl delay to see if it gives time to load web page
Sys.sleep(10)   # Been testing with 10

###ADD JAVASCRIPT INJECTION HERE###
remDr$executeScript(?)

# Extract Prices
webElem <- remDr$findElements(using = "css", "[class='dollars price-emphasis']")
prices <- unlist(lapply(webElem, function(x){x$getElementText()}))
print(prices)

# Extract Airlines
webElem <- remDr$findElements(using = "css", "[data-test-id='airline-name']")
airlines <- unlist(lapply(webElem, function(x){x$getElementText()}))
print(airlines)

# close client/server
remDr$close()
rD$server$stop()

如您所见,我内置了一个 ImplicitWaitTimeout 和一个 Sys.Sleep 调用,以便页面有时间在 phantomJS 中加载并且不会因请求而使网站超载。

一般来说,在日期范围内循环时,抓取工具效果很好。但是,当连续循环 10 个以上的日期时,Selenium 有时会抛出 StaleElementReference 错误并停止执行。我知道这是因为页面尚未完全加载并且 class='dollars price-emphasis' 尚不存在。 URL 构造很好。

每当页面成功加载时,爬虫就会接近 60 个价格和航班。我提到这个是因为有时脚本 returns 只有 15-20 个条目(通常在浏览器上检查这个日期时,有 60 个)。在这里,我得出结论,我只找到 60 个元素中的 20 个,这意味着页面只加载了部分内容。

我想通过 injecting JavaScript 让这个脚本更健壮,它在查找元素之前等待页面完全加载。我知道这样做的方法是 remDr$executeScript(),并且我发现了许多有用的 JS 片段来实现这一点,但由于对 JS 的了解有限,我在调整这些解决方案以在语法上与我的脚本一起工作时遇到了问题。

以下是Wait for page load in Selenium & Selenium - How to wait until page is completely loaded提出的几个解决方案:

基本代码:

remDr$executeScript(
WebDriverWait wait = new WebDriverWait(driver, 20);
By addItem = By.cssSelector("class=dollars price-emphasis");, args = list()
)

对基本脚本的补充:

1) 检查元素是否过时

# get the "Add Item" element
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(addItem));
# wait the element "Add Item" to become stale
wait.until(ExpectedConditions.stalenessOf(element));

2) 等待元素的可见性

wait.until(ExpectedConditions.visibilityOfElementLocated(addItem));

我试过用 remDr$executeScript("return document.readyState").equals("complete") 作为继续抓取之前的检查,但页面始终显示为完整,即使它不是。

有没有人对我如何调整这些解决方案之一以使用我的 R 脚本有任何建议?关于如何完全等待页面加载近 60 个找到的元素的任何想法?我还在学习,所以任何帮助将不胜感激。

使用while/tryCatch的解决方案:

remDr$navigate("<webpage url>")
webElem <-NULL
while(is.null(webElem)){
  webElem <- tryCatch({remDr$findElement(using = 'name', value = "<value>")},
  error = function(e){NULL})
 #loop until element with name <value> is found in <webpage url>
}

为了更加方便 Victor 的出色回答,大量页面上的一个共同元素是正文,可以通过 css 访问它。我还把它变成了一个函数,并添加了一个快速随机睡眠(总是很好的做法)。这应该可以工作,而无需在大多数网页上使用文本分配元素:

##use double arrow to assign to global environment permanently
#remDr <<- remDr
wetest <- function(sleepmin,sleepmax){
  remDr <- get("remDr",envir=globalenv())
  webElemtest <-NULL
  while(is.null(webElemtest)){
    webElemtest <- tryCatch({remDr$findElement(using = 'css', "body")},
                            error = function(e){NULL})
    #loop until element with name <value> is found in <webpage url>
  }
  randsleep <- sample(seq(sleepmin, sleepmax, by = 0.001), 1)
  Sys.sleep(randsleep)
}

用法:

remDr$navigate("https://bbc.com/news")
clickable <- remDr$findElements(using='xpath','//button[contains(@href,"")]')
clickable[[1]]$clickElement()
wetest(sleepmin=.5,sleepmax=1)