HtmlAgilityPack & Selenium Webdriver возвращает случайные результаты

Я пытаюсь очистить названия продуктов с веб-сайта. Как ни странно, я, кажется, только царапаю случайные 12 предметов. Я пробовал как HtmlAgilityPack, так и HTTPClient, и получаю одинаковые случайные результаты. Здесь мой код для HtmlAgilityPack:

using HtmlAgilityPack;
using System.Net.Http;

var url = @"http://www.roots.com/ca/en/men/tops/shirts-and-polos/";
HtmlWeb web = new HtmlWeb();
var doc = web.Load(url, "GET", proxy, new NetworkCredential(PROXY_UID, PROXY_PWD, PROXY_DMN));
var nodes = doc.DocumentNode.Descendants("div")
            .Where(div => div.GetAttributeValue("class", string.Empty) == "product-name")
            .Select(div => div.InnerText.Trim())
            ;

[ОБНОВЛЕНИЕ 1] @CodingKuma предложил попробовать Selenium Webdriver. Здесь мой код с использованием Selenium Webdriver:

IWebDriver chromeDriver = new ChromeDriver(@"C:\TEMP\Projects\Chrome\chromedriver_win32");
chromeDriver.Url = "http://www.roots.com/ca/en/men/tops/shirts-and-polos/";
var items = chromeDriver.FindElements(By.ClassName("product-name"));
items.Count().Dump();
chromeDriver.Quit();

Я пробовал этот код, но мне все равно не повезло. На этой странице есть более 20 элементов, но мне кажется, что я получаю только случайные 12. Как я могу очистить все элементы на этом сайте?

Ответ 1

Для большинства приложений с одной страницей или страниц, которые динамически загружают контент, вам лучше использовать фактический браузер для навигации по страницам. Я бы предложил заглянуть в селен для такого типа настроек.

https://www.nuget.org/packages/Selenium.WebDriver

Ответ 2

Итак, есть несколько проблем, которые не позволяют правильному счету.

  • Страница имеет ленивый загрузчик. Вам нужно прокрутить вниз, чтобы вызвать загрузку элементов более 12.

  • На странице используются вызовы AJAX для загрузки элементов более 12.

Итак, вам нужно перейти на страницу, прокрутить страницу до конца, дождаться завершения AJAX, а затем очистить страницу. Код ниже проверен и возвращает 20 элементов.

script

String url = "http://www.roots.com/ca/en/men/tops/shirts-and-polos/";
driver.navigate().to(url);
JavascriptExecutor js = ((JavascriptExecutor) driver);
int height = 1;
int lastHeight = 0;
while (lastHeight != height)
{
    lastHeight = height;
    js.executeScript("window.scrollTo(0, document.body.scrollHeight);");
    height = (int) (long) js.executeScript("return document.body.scrollHeight;");
}

waitForJSandJQueryToLoad(10);

List<WebElement> products = driver.findElements(By.cssSelector("div.product-name"));
System.out.println(products.size());
for (WebElement e : products)
{
    System.out.println(e.getText());
}

Функция поддержки

public boolean waitForJSandJQueryToLoad(int timeOut)
{
    WebDriverWait wait = new WebDriverWait(driver, timeOut);

    ExpectedCondition<Boolean> jQueryIsLoaded = new ExpectedCondition<Boolean>()
    {
        @Override
        public Boolean apply(WebDriver driver)
        {
            return (Boolean) ((JavascriptExecutor) driver).executeScript("return (window.jQuery != null) && (jQuery.active === 0);");
        }
    };

    ExpectedCondition<Boolean> jsIsLoaded = new ExpectedCondition<Boolean>()
    {
        @Override
        public Boolean apply(WebDriver driver)
        {
            return (Boolean) ((JavascriptExecutor) driver).executeScript("return document.readyState == 'complete'");
        }
    };

    return wait.until(jQueryIsLoaded) && wait.until(jsIsLoaded);
}

Выход

20
Rideau Flannel Shirt
Westridge Denim Shirt
Rideau Flannel Shirt
Riverside Plaid Shirt
Riverside Plaid Shirt
Heritage Peppered Polo
Heritage Peppered Polo
Heritage Peppered Polo
Cedar Jersey Polo
Cedar Jersey Polo
Hope River Shirt
Hawthorne Surplus Shacket
Acadian Linen Shirt
Camp Short Sleeve Shirt
Foxley Short Sleeve Shirt
Heritage Peppered Polo
Foxley Short Sleeve Shirt
Waterway Indigo Shirt
Waterway Indigo Shirt
Resolute Flannel Shirt

Ответ 3

Как говорили другие, страница с этого сайта загружает себя динамически с использованием некоторого javascript, поэтому в Html Agility Pack просто появляются первые элементы.

Веб-скребок может быть жестким, особенно с современными сайтами, которые используют все больше и больше javascript, и это в целом очень специфично для целевого сайта (я даже не говорю о юридических проблемах..). Вы можете использовать различные методы, чтобы определить, как получить требуемую информацию.

В этом случае, если вы используете какой-либо сетевой анализатор, вы быстро увидите, что на сайте используется параметр строки 'sz' (для размера, я думаю), который позволяет вам указать количество элементов, которые вы хотите.

Итак, просто измените свой URL для этого:

var url = @"http://www.roots.com/ca/en/men/tops/shirts-and-polos/?sz=9999";

и получите любое количество элементов, которые вы хотите.

Ответ 4

Так как v1.5.0-beta92,

HtmlAgilityPack имеет метод FromBrowser, который позволяет подождать, пока все нужные вам элементы не будут готовы.

Документация: http://html-agility-pack.net/from-browser

string url = "http://html-agility-pack/from-browser";

var web1 = new HtmlWeb();
var doc1 = web1.LoadFromBrowser(url, o =>
{
    var webBrowser = (WebBrowser) o;

    // WAIT until the dynamic text is set
    return !string.IsNullOrEmpty(webBrowser.Document.GetElementById("uiDynamicText").InnerText);
});
var t1 = doc1.DocumentNode.SelectSingleNode("//div[@id='uiDynamicText']").InnerText

var web2 = new HtmlWeb();
var doc2 = web2.LoadFromBrowser(url, html =>
{
    // WAIT until the dynamic text is set
    return !html.Contains("<div id=\"uiDynamicText\"></div>");
});
var t2 = doc2.DocumentNode.SelectSingleNode("//div[@id='uiDynamicText']").InnerText

Console.WriteLine("Text 1: " + t1);
Console.WriteLine("Text 2: " + t2);

Хитрость здесь заключается в том, чтобы найти что-то, что говорит вам, когда страница готова, так как это невозможно для библиотеки.