12

私はウェブサイトから製品名を掻き集めようとしています。奇妙なことに、私は無作為に12項目を掻き集めるようだ。私はHtmlAgilityPackとHTTPClientの両方を試してみましたが、私は同じランダムな結果を得ています。HtmlAgilityPack&Selenium Webdriverはランダムな結果を返します

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

[UPDATE 1] @CodingKuma私はセレンwebdriverをして​​みてください提案:ここにHtmlAgilityPackのための私のコードです。私のコードは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。そのサイトのすべてのアイテムをどのように削り取ることができますか?

+0

異なるユーザーエージェントを試してみませんか?他にはajaxがロードされていますか? –

+0

このページはスクロールして読み込まれるため、スクレーパーは人間ではありません。 –

+0

@ DanielA.White他にどのようなエージェントをお勧めしますか? –

答えて

3

コンテンツを動的にロードするほとんどのシングルページアプリまたはページでは、実際のブラウザを使用してページをナビゲートする方がよい場合があります。私はこのタイプのセットアップのためにセレンを調べることをお勧めします。

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

+0

それはどちらも動作しません。これは私のコードです: '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( "product-name")); items.Count()。Dump(); chromeDriver.Quit(); ' 私はまだ24の代わりにカウント12を得ます。 –

+0

私はそれに応じて答えを更新しました。 – CodingKuma

+0

私は大抵の人が他の回答を取って、重要な貢献なしに自分自身に追加するのは悪い習慣であることに同意すると思います。 – JeffC

3

だから、正しいことから、カウントを防ぐカップルの問題があります。

  1. ページにはレイジーローダーがあります。あなたは、アイテムの負荷ページはAJAXだから

12上の項目をロードするために呼び出して使用する

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

    サポート機能

    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の敏捷性パックは最初のアイテムを取得します。

    ウェブスクラップするのは厳しいかもしれません。特に、現代のサイトではJavaScriptがますます使用されていますが、一般的にターゲットサイトに固有です(私は法的な問題について話していません)。さまざまな手法を使用して、必要な情報を取得する方法を判断できます。

    この場合、任意のネットワークアナライザを使用すると、サイトで希望する項目の数を指定できるクエリ文字列パラメータ'sz'(Size I guessの場合)を使用することがすぐにわかります。

    ので、これだけのためにあなたのURLを変更します。

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

    して、必要な項目のいずれかの番号を取得します。

    +0

    これは有用な情報ですが、質問には答えません。彼はすでに20の製品を手に入れており、最初の12個だけを見ています。9999個の製品を入手することは、その問題を解決するつもりはありません。 – JeffC

    +0

    @JeffC - ??? szパラメータがなければ、すべての製品を1つのHTTP GETで取得するのではなく、正確にはその部分だけを取得します。大きな値でszを定義すると、1つのGET(サンプルでは9999まで)のアイテムの最大数が得られます。つまり、このクエリでは20です。両方のURLを試してみてくださいとあなたは理解します。 –

    +0

    いいえ、質問は "ちょっと...ページに20の商品があり、私は12点しか得ていません、なぜですか?" OPがあなたの答えを使用している場合、次の質問は、 "ちょっと...ページに9999の製品があり、私は12点しか得ていません、なぜですか?" Ref: 'そのページには20以上の項目がありますが、ランダムな12点しか得られないようです.' – JeffC

    3

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

    ここのトリックは、ライブラリを知ることは不可能ですので、ページの準備が完了したときにわかります何かを見つけることです。

    +0

    OPのサイトでこれを試しましたか?これはレイジーローダーを使用しているため動作しないと思います。ページが読み込まれ、下にスクロールする必要があり、ページの読み込みが完了するまで待ちます。詳細は私の答えを見てください。 – JeffC

    +0

    @JeffC、いいえ、私は試していませんでした。しかし、WebBrowserにアクセスし、webBrowser.Document.Window.ScrollTo(0、webBrowser.Document.Body.ScrollRectangle.Height)のようなAPIを使用できるため、同じ結果が得られます。 –

    関連する問題