C# HtmlAgilityPack&;SeleniumWebDriver返回随机结果

C# HtmlAgilityPack&;SeleniumWebDriver返回随机结果,c#,selenium-webdriver,web-scraping,web-crawler,html-agility-pack,C#,Selenium Webdriver,Web Scraping,Web Crawler,Html Agility Pack,我正试图从网站上搜刮产品名称。奇怪的是,我似乎只随机挑选了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 d

我正试图从网站上搜刮产品名称。奇怪的是,我似乎只随机挑选了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建议我试试SeleniumWebDriver。以下是我使用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个。如何清除该站点上的所有项目?

对于大多数单页应用程序或动态加载内容的页面,最好使用实际浏览器浏览页面。我建议为这种类型的设置研究selenium


因此,有几个问题妨碍了计数的正确性

  • 页面有一个延迟加载程序。您必须向下滚动以触发超过12个项目的加载

  • 该页面使用AJAX调用加载12个以上的项目

  • 因此,您需要导航到页面,滚动到页面底部,等待AJAX完成,然后刮取页面。下面的代码经过测试并返回20项

    剧本

    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());
    }
    

    正如其他人所说,这个站点的页面使用一些javascript动态加载自己,因此Html敏捷包只获取第一项

    网页抓取可能很困难,尤其是使用越来越多javascript的现代网站,而且通常针对目标网站(我甚至不谈论法律问题)。您可以使用各种技术来确定如何获取所需的信息

    在这种情况下,如果您使用任何网络分析器,您将很快看到该站点使用了一个
    'sz'
    (我猜是大小)查询字符串参数,该参数允许您指定所需的项数

    因此,只需修改您的url即可:

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

    并获取您想要的任意数量的项目。

    自v1.5.0-beta92以来

    HtmlAgilityPack有一个
    FromBrowser
    方法,允许您等待所有需要的元素就绪

    文件:

    stringurl=”http://html-agility-pack/from-browser";
    var web1=新的HtmlWeb();
    var doc1=web1.LoadFromBrowser(url,o=>
    {
    var webBrowser=(webBrowser)o;
    //等待动态文本设置完成
    return!string.IsNullOrEmpty(webBrowser.Document.GetElementById(“uiDynamicText”).InnerText);
    });
    var t1=doc1.DocumentNode.SelectSingleNode(//div[@id='uiDynamicText'])。InnerText
    var web2=新的HtmlWeb();
    var doc2=web2.LoadFromBrowser(url,html=>
    {
    //等待动态文本设置完成
    return!html.Contains(“”);
    });
    var t2=doc2.DocumentNode.SelectSingleNode(//div[@id='uiDynamicText'])。InnerText
    控制台写入线(“文本1:+t1”);
    控制台写入线(“文本2:+t2”);
    

    这里的诀窍是找到一些信息,告诉您页面何时准备就绪,因为库不可能知道。

    尝试不同的用户代理?其他人是否加载了ajax?因为该页面在滚动时加载,所以刮板不是人。@DanielA.White您还推荐其他代理吗?我不知道。试验和尝试。这取决于那个网站。我们不能合理地为你回答这个问题。@AlexK。有没有办法强制HAP先加载整个页面?这也不行。这是我的代码:
    IWebDriver chromeDriver=新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(“产品名称”);items.Count().Dump();chromeDriver.Quit()我的计数仍然是12,而不是24。我想大多数人都会同意,采用其他答案并将其添加到自己的答案中而没有任何重大贡献是一种不好的做法。@JeffC抱歉,我已调整为从其他答案中删除对大小参数的引用。至于滚动部分,我只是回答他为什么没有得到所有的评论。我不是从你的回答中得到的。跟我做了之后你建议的硒没什么不同。@CodingKuma,这很不一样。我并不是说“使用硒”,而是对问题进行了描述,然后提供了包括代码在内的解决方案。您的答案是一周半以前的,您最近编辑了您的答案,并方便地包含了其他两个答案的评论。@JeffC fine我删除了我的更新,尽管我在答复和添加之前甚至没有阅读您的答案。虽然这是有用的信息,但它不能回答问题。他已经得到了20种产品,只看到了前12种。获得9999产品并不能解决这个问题。@JeffC-???如果没有sz参数,您不会在一个httpget中获得所有产品,只有一部分,这正是问题所在。用一个大值定义sz将在一次get中获得最大可能的项数(在我的示例中最多可达9999项),即此查询为20项。试试这两个URL,你就会明白。不,问题是,“嘿……页面上有20个产品,我只得到12个,为什么?”如果OP使用你的答案,下一个问题是,“嘿……页面上有9999个产品,我只得到12个,为什么?”参考:
    页面上有20多个项目,但我似乎只得到了随机的12分。
    你在发布的网站上试过这个吗?我认为这不会起作用,因为它使用了一个懒惰的加载程序。页面加载完毕,您必须向下滚动至底部,然后等待页面加载完成。。。更多细节请参见我的答案。@JeffC,不,我没有尝试。但是,由于他可以访问WebBrowser,并且可以使用WebBrowser.Document.Window.ScrollTo(0,WebBrowser.Document.Body.ScrollRectangle.Height)等API,因此也可以获得相同的结果;
    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
    
    var url = @"http://www.roots.com/ca/en/men/tops/shirts-and-polos/?sz=9999";
    
    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);