我整理了一个刮擦价格/航空公司的原油刮刀:
# 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个价格和航班。我之所以提到这一点是因为有时候脚本只返回15-20个条目(通常在浏览器上检查这个日期时有60个)。在这里,我得出结论,我只找到60个元素中的20个,这意味着页面只有部分加载。
我希望injecting JavaScript
使这个脚本更加健壮,等待页面在查找元素之前完全加载。我知道这样做的方法是remDr$executeScript()
,我找到了很多有用的JS片段来完成这个,但是由于JS知识有限,我在调整这些解决方案以便在语法上与我的脚本一起工作时遇到了问题。 / p>
以下是Wait for page load in Selenium&amp;提出的几种解决方案。 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个已发现元素的任何想法?我还在倾斜,所以任何帮助都会非常感激。
答案 0 :(得分:4)
使用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>
}
答案 1 :(得分:1)
为了让 Victor 的精彩回答更加方便,大量页面上的一个常见元素是 body,它可以通过 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)