12

我試圖從網站上刮取產品名稱。奇怪的是,我似乎只是隨機抽取了12件物品。我已經嘗試HtmlAgilityPack和HTTPClient,並得到相同的隨機結果。這裏是我的HtmlAgilityPack代碼: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()) 
      ; 

[更新1] @CodingKuma建議我嘗試硒的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.我怎樣才能颳去該網站上的所有項目?

+0

嘗試不同的用戶代理?其他人是否加載了ajax? –

+0

由於該頁面以滾動方式加載,刮板不是人。 –

+0

@ DanielA.White您推薦哪些其他代理商? –

回答

3

對於大多數單頁面應用程序或動態加載內容的頁面,最好使用實際瀏覽器來瀏覽頁面。我建議尋找硒這種類型的設置。

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

+0

這也行不通。這裏是我的代碼: '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();' 我仍然得到12而不是24的計數。 –

+0

我相應地更新了答案。 – CodingKuma

+0

我想大多數人都會同意,在沒有任何重大貢獻的情況下采取其他答案並將其添加到自己的答案是一種不好的做法。 – JeffC

3

所以有防止計數被正確的一對夫婦的問題。

  1. 該頁面有一個懶惰的加載程序。你必須向下滾動到觸發物品的負荷超過12

  2. 該頁面使用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()); 
} 

支持功能

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敏捷包只是獲得第一項。

Web Scraping可能很難,尤其是對於使用越來越多JavaScript的現代網站,它通常對目標站點非常特殊(我甚至沒有談論法律問題)。您可以使用各種技術來確定如何獲取所需的信息。

在這種情況下,如果您使用任何網絡分析器,您會很快看到該網站使用'sz'(對於我猜的大小)查詢字符串參數,該參數允許您指定所需的項目數。

所以,只要修改網址爲這樣:

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

,並得到你想要的物品的任何數字。

+0

雖然這是有用的信息,但它不回答問題。他已經獲得了20種產品,只看到了前12種產品。獲得9999種產品並不能解決這個問題。 – JeffC

+0

@JeffC - ???沒有sz參數,你不會在一個HTTP GET中獲得所有產品,只有一部分,這正是問題所在。使用大的值定義sz將獲得一個GET中最大可能的項數(在我的示例中最大爲9999),即對於此查詢爲20。試試這兩個urls會提琴手,你會明白。 –

+0

不,問題是,「嘿...網頁上有20種產品,我只能得到12種,爲什麼?」如果OP使用你的答案,下一個問題將是,「嘿......網頁上有9999個產品,我只得到12個,爲什麼?」參考:「該網頁上有超過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,並可以使用一些API,如webBrowser.Document.Window.ScrollTo(0,webBrowser.Document.Body.ScrollRectangle.Height); –

相關問題