[英]How to load lazy content on Linkedin search page using selenium
我想在LinkedIn搜索頁面上搜索帳戶的所有第一個連接的個人資料鏈接。 但由於頁面動態加載其余內容(當您向下滾動時),我無法獲得位於頁面末尾的“下一頁”頁面按鈕。
https://linkedin.com/search/results/people/?facetGeoRegion=["tr%3A0"]&facetNetwork=["F"]&origin=FACETED_SEARCH&page=YOUR_PAGE_NUMBER
我可以使用selenium和上面的鏈接導航到搜索頁面。 我想知道有多少頁面可以導航它們只需更改上面鏈接的page=
變量。
為了實現我想要檢查是否存在Next
按鈕。 只要有下一個按鈕,我就會請求下一頁進行抓取。 但是如果你不向下滾動直到頁面底部 - 這是'下一步'按鈕的位置 - 你找不到Next
按鈕,也找不到有關其他配置文件的信息,因為它們尚未加載。
以下是當您不使用firefox截屏工具向下滾動並截取整個頁面的截圖時的外觀。
我可以通過將向下滾動操作硬編碼到我的代碼中並使驅動程序等待visibilityOfElementLocated
來解決這個問題。 但我想知道是否還有其他方法比我的做法更好。 如果通過該方法,驅動程序無法以某種方式找到“ Next
按鈕,程序將以退出代碼1退出。
當我向下滾動頁面時檢查請求時,它只是對圖像等的請求,如下所示。 當我向下滾動頁面時,我無法弄清楚頁面如何加載有關配置文件的更多信息。
以下是我在代碼中實現它的方法。 這個應用程序只是一個簡單的實現,它試圖找到頁面上的Next
按鈕。
package com.andreyuhai;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class App
{
WebDriver driver;
public static void main( String[] args )
{
Bot bot = new Bot("firefox", false, false, 0, 0, null, null, null);
int pagination = 1;
bot.get("https://linkedin.com");
if(bot.attemptLogin("username", "pw")){
bot.get("https://www.linkedin.com/" +
"search/results/people/?facetGeoRegion=" +
"[\"tr%3A0\"]&origin=FACETED_SEARCH&page=" + pagination);
JavascriptExecutor js = (JavascriptExecutor) bot.driver;
js.executeScript("scrollBy(0, 2500)");
WebDriverWait wait = new WebDriverWait(bot.driver, 10);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//button[@class='next']/div[@class='next-text']")));
WebElement nextButton = bot.driver.findElement(By.xpath("//button[@class='next']/div[@class='next-text']"));
if(nextButton != null ) {
System.out.println("Next Button found");
nextButton.click();
}else {
System.out.println("Next Button not found");
}
}
}
}
這個chrome擴展名為linkedIn Spider
這也正是我想要實現的,但我想使用JavaScript,我不確定。 但是當我在同一個搜索頁面上運行此擴展時。 這不會向下滾動或逐個加載其他頁面提取數據。
所以我的問題是:
能否請您解釋一下LinkedIn如何實現這一目標? 我的意思是它如何加載配置文件信息,因為我向下滾動,如果不做任何請求等等。我真的不知道這個。 我將不勝感激任何來源鏈接或解釋。
你有更好的(我的意思更快)想法來實現我想要實現的東西嗎?
能否請您解釋一下LinkedIn Spider
如何在不向下滾動的情況下工作等等。
我檢查了div結構和linkedin顯示結果的方式。 所以,如果你直接點擊url並按照xpath: //li[contains(@class,'search-result')]
你會發現所有結果都已經加載到頁面上,但是會顯示滾動時只有5個結果,它顯示接下來的5個結果,但是所有結果都已加載到頁面上,並且可以通過上述xpath找到。
當您在點擊網址時輸入xpath時找到結果時,請參閱此圖片,其中突出顯示了div結構和結果: https : //imgur.com/Owu4NPh
參考此圖像,在將頁面滾動到底部然后使用相同的xpath查找結果后突出顯示div結構和結果: https : //imgur.com/7WNR830
您可以看到結果集相同但是在最后5個結果中<li>標記中有一個額外的search-result__occlusion-hint
部分,並且通過此linkedin隱藏了接下來的5個結果並且僅顯示了第一個結果中的前5個結果走。
現在來了實現部分,我已經選中了“下一步”按鈕,只有當你在頁面上滾動整個結果時才會出現,所以不是滾動到一個明確的坐標,因為可以針對不同的屏幕尺寸和窗口進行更改,你可以將結果輸入一個webelement列表並獲取它的大小,然后滾動到該列表的最后一個元素。 在這種情況下,如果總共有10個結果,則頁面將滾動到第10個結果,如果只有4個結果,則頁面將滾動到第4個結果,滾動后可以檢查下一個按鈕是否存在頁面與否。 為此,您可以檢查“下一步”按鈕Web元素列表的列表大小,如果列表大小大於0,則表示頁面上存在下一個按鈕,如果不大於0,則表示下一個按鈕列表中沒有按鈕,您可以在那里停止執行。
所以為了實現它,我采用了一個布爾值,其初始值為true,代碼將在循環中運行,直到布爾值變為false,並且當Next按鈕列表大小等於0時,它將變為false。
請參考以下代碼:
public class App
{
WebDriver driver;
// For initialising javascript executor
public Object executeScript(String script, Object... args) {
JavascriptExecutor exe = (JavascriptExecutor) driver;
return exe.executeScript(script, args);
}
// Method for scrolling to the element
public void scrollToElement(WebElement element) {
executeScript("window.scrollTo(arguments[0],arguments[1])", element.getLocation().x, element.getLocation().y);
}
public static void main(String[] args) {
// You can change the driver to bot according to your usecase
driver = new FirefoxDriver();
// Add your direct URL here and perform the login after that, if necessary
driver.get(url);
// Wait for the URL to load completely
Thread.sleep(10000);
// Initialising the boolean
boolean nextButtonPresent = true;
while (nextButtonPresent) {
// Fetching the results on the page by the xpath
List<WebElement> results = driver.findElements(By.xpath("//li[contains(@class,'search-result')]"));
// Scrolling to the last element in the list
scrollToElement(results.get(results.size() - 1));
Thread.sleep(2000);
// Checking if next button is present on the page
List<WebElement> nextButton = driver.findElements(By.xpath("//button[@class='next']"));
if (nextButton.size() > 0) {
// If yes then clicking on it
nextButton.get(0).click();
Thread.sleep(10000);
} else {
// Else setting the boolean as false
nextButtonPresent = false;
System.out.println("Next button is not present, so ending the script");
}
}
}
}
我觀察到的是,內容已經加載到頁面中,當我們向下滾動時它將顯示給我們。
但是如果我們通過使用類名“next”手動加載頁面來檢查“下一步>”按鈕,例如如下所示,
//按鈕[@類= '下一個']
我們無法找到它,直到我們向下滾動,因為它對我們來說是不可見的。 但是通過使用下面的XPath,我們可以識別所有配置文件鏈接的數量,無論它們是否顯示?
// h3 [contains(@class,'search-results__total')] / parent :: div / ul / li
由於您想從頁面中獲取所有配置文件鏈接,我們可以使用上面的XPath幫助來完成此操作。 我們將使用上面的XPath獲取鏈接計數,然后我們將一次滾動到每個元素視圖,然后我們將按如下方式獲取配置文件鏈接:
// Identifying the all the profile links
List<WebElement> totalProfileLinks = driver.findElements(By.xpath("//h3[contains(@class, 'search-results__total')]/parent::div/ul/li"));
// Looping for getting the profile link
for(int i=1;i<totalProfileLinks.size();i++) {
// Scrolling so that it will be visible
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", totalProfileLinks.get(i));
// Fetching the anchor node
final WebElement link = driver.findElement(By.xpath("(//h3[contains(@class, 'search-results__total')]/parent::div/ul/li//div[contains(@class, 'search-result__info')]//a)["+i+"]"));
// Avoiding the StaleElementReferenceException
new FluentWait<WebDriver>(driver).withTimeout(1, TimeUnit.MINUTES).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class).until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver arg0) {
return link;
}
});
// Fetching and printing the link from anchor node
System.out.println(link.getAttribute("href").trim());
}
所以,如果我們想首先點擊'Next>'按鈕,我們需要檢查它是否存在(因為我們在獲取配置文件鏈接時滾動,'下一個'按鈕也被顯示)。 我們可以使用`driver.findElements();`方法的幫助來獲取該元素的匹配數,並將它存儲在某個List中(因為它返回WebElements列表),如下所示:
List<WebElement> nextButton = driver.findElements(By.className("next"));
使用上述技術的好處是,如果沒有元素匹配,腳本也不會失敗,如果沒有匹配,我們將有一個空列表。
然后我們可以使用List接口的size()方法來獲得匹配計數,如下所示:
int size = nextButton.size();
如果大小超過0然后該元素不存在,我們可以檢查如下的條件:
if(size > 0) {
nextButton.get(0).click(); // Do some operation like clicking on it
System.out.println("=> 'Next >' button is there and clicked on it...");
} else {
System.out.println("=> 'Next >' button is NOT there...");
}
當內容被加載並且元素是可查看的時,我們將使用JavaScriptExecutor來定位和點擊它。
在while循環中包含上面的代碼,並在每次單擊上一個'Next>'按鈕后檢查是否存在'Next>'按鈕,如下所示:
boolean next = true;
while(next) {
// Checking 'Next >' button is there or not in the page
List<WebElement> nextButton = driver.findElements(By.className("next"));
// If the 'Next >' button is there then clicking on it otherwise stopping the execution
if(nextButton.size() > 0) {
doClickUsingJSE(nextButton.get(0));
System.out.println("=> 'Next >' button is there and clicked on it...");
} else {
next = false;
System.out.println("=> 'Next >' button is NOT there so stopping the execution...");
}
Thread.sleep(1000);
}
如果上述代碼中的'if'條件失敗,循環將中斷,因為'next'將變為'false'。 如果我們使用Fluent Wait,它將幫助我們避免一些'Exceptions',如'WebDriverException'和'StaleElementReferenceException'。 所以我編寫了一個單獨的方法,它將等待一個元素,避免一些異常並在條件滿足時點擊它。
檢查以下代碼:
private static void doClickUsingJSE(final WebElement element) {
// Using the Fluent Wait to avoid some exceptions like WebDriverException and StaleElementReferenceException
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(1, TimeUnit.MINUTES).pollingEvery(1, TimeUnit.SECONDS).ignoring(WebDriverException.class, StaleElementReferenceException.class);
WebElement waitedElement = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return element;
}
});
wait.until(ExpectedConditions.visibilityOf(waitedElement));
wait.until(ExpectedConditions.elementToBeClickable(waitedElement));
// Clicking on the particular element using the JavaScriptExcecutor
((JavascriptExecutor) driver).executeScript("arguments[0].click();", waitedElement);
}
正如我之前提到的關於JavaScriptExecutor的,我也僅在上述方法中使用了它。
嘗試以下結束工作代碼:
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import com.google.common.base.Function;
public class BasePage
{
// Declaring WebDriver
private static WebDriver driver;
private static void doClickUsingJSE(final WebElement element) {
// Using the Fluent Wait to avoid some exceptions like WebDriverException and StaleElementReferenceException
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(1, TimeUnit.MINUTES).pollingEvery(1, TimeUnit.SECONDS).ignoring(WebDriverException.class, StaleElementReferenceException.class);
WebElement waitedElement = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return element;
}
});
wait.until(ExpectedConditions.visibilityOf(waitedElement));
wait.until(ExpectedConditions.elementToBeClickable(waitedElement));
// Clicking on the particular element using the JavaScriptExcecutor
((JavascriptExecutor) driver).executeScript("arguments[0].click();", waitedElement);
}
public static void main( String[] args ) throws Exception
{
System.setProperty("webdriver.chrome.driver", "C:\\NotBackedUp\\chromedriver.exe");
// Initializing the Chrome Driver
driver = new ChromeDriver();
// Launching the LinkedIn site
driver.get("https://linkedin.com/search/results/people/?facetGeoRegion=[\"tr%3A0\"]&facetNetwork=[\"F\"]&origin=FACETED_SEARCH&page=YOUR_PAGE_NUMBER");
// You can avoid this and it to your convience way
// As there are no connections in my page, I have used like this
//------------------------------------------------------------------------------------
// Switching to the login from - iframe involved
driver.switchTo().frame(driver.findElement(By.className("authentication-iframe")));
// Clicking on the Sign In button
doClickUsingJSE(driver.findElement(By.xpath("//a[text()='Sign in']")));
// Entering the User Name
WebElement element = driver.findElement(By.id("username"));
doClickUsingJSE(element);
element.sendKeys("something@gmail.com");
// Entering the Password
element = driver.findElement(By.id("password"));
doClickUsingJSE(element);
element.sendKeys("anything"+Keys.ENTER);
// Clicking on the People drop down
Thread.sleep(8000);
element = driver.findElement(By.xpath("//span[text()='People']"));
doClickUsingJSE(element);
// Selecting the All option
Thread.sleep(2000);
element = driver.findElement(By.xpath("//ul[@class='list-style-none']/li[1]"));
element.click();
// Searching something in the LinkedIn search box
Thread.sleep(3000);
element = driver.findElement(By.xpath("//input[@role='combobox']"));
doClickUsingJSE(element);
element.sendKeys("a"+Keys.ENTER);
Thread.sleep(8000);
//------------------------------------------------------------------------------------
boolean next = true;
while(next) {
// Identifying the all the profile links
List<WebElement> totalProfileLinks = driver.findElements(By.xpath("//h3[contains(@class, 'search-results__total')]/parent::div/ul/li"));
// Looping for getting the profile link
for(int i=1;i<totalProfileLinks.size();i++) {
// Scrolling so that it will be visible
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", totalProfileLinks.get(i));
// Fetching the anchor node
final WebElement link = driver.findElement(By.xpath("(//h3[contains(@class, 'search-results__total')]/parent::div/ul/li//div[contains(@class, 'search-result__info')]//a)["+i+"]"));
// Avoiding the StaleElementReferenceException
new FluentWait<WebDriver>(driver).withTimeout(1, TimeUnit.MINUTES).pollingEvery(1, TimeUnit.SECONDS).ignoring(StaleElementReferenceException.class).until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver arg0) {
return link;
}
});
// Fetching and printing the link from anchor node
System.out.println(link.getAttribute("href").trim());
}
// Checking 'Next >' button is there or not in the page
List<WebElement> nextButton = driver.findElements(By.className("next"));
// If the 'Next >' button is there then clicking on it otherwise stopping the execution
if(nextButton.size() > 0) {
doClickUsingJSE(nextButton.get(0));
System.out.println("=> 'Next >' button is there and clicked on it...");
} else {
next = false;
System.out.println("=> 'Next >' button is NOT there so stopping the execution...");
}
Thread.sleep(1000);
}
}
}
我希望它有所幫助...快樂編碼......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.