LINQ Извлечение данных с веб-сайта с помощью HTMLAgilityPack

Я использую C# HTMLAgilityPack для извлечения названия товара, цены и символа валюты из китайский веб-сайт: https://meadjohnson.world.tmall.com/search.htm?search=y&orderType=defaultSort&s‌​cene=taobao_shop. Вот суть того, как выглядит html:

<div class="SaleItems">
    <dl class="item ">
        <dt class="photo"></dt>
        <dd class="detail">
            <a class="item-name">iPad</a>
            <div class="price-area">
                <span class="symbol">USD</span>
                <span class="price">379</span>
            </div>
        </dd>
    </dl>
    <dl class="item ">
        <dt class="photo"></dt>
        <dd class="detail">
            <a class="item-name">iPod</a>
            <div class="price-area">
                <span class="symbol">CAD</span>
                <span class="price">139</span>
            </div>
        </dd>
    </dl>
</div>

Пока моя программа выглядит так.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
    | SecurityProtocolType.Tls11
    | SecurityProtocolType.Tls12
    | SecurityProtocolType.Ssl3;

var htmlDocument = htmlWeb.Load(html);
var sItems = doc.DocumentNode.Descendants("SaleItems"); 
foreach (var item in sItems)
{
  var data = new {
         Currency  = item["symbol"].InnerText,
         Price = item["price"].InnerText,
         };
}

Это не работает. Как я могу исправить то, что я делаю неправильно?


person inquisitive_one    schedule 21.08.2015    source источник
comment
Что именно не работает с тем, что вы делаете сейчас?   -  person SamHuckaby    schedule 22.08.2015
comment
Я получаю сообщение об ошибке Невозможно применить индексирование с помощью [] к выражению типа «HtmlAgilityPack.HtmlNode».   -  person inquisitive_one    schedule 22.08.2015


Ответы (2)


Вы можете извлечь свои данные следующим образом:

var input = @"<div class='SaleItems'>
    <dl class='item '>
        <dt class='photo'></dt>
        <dd class='detail'>
            <a class='item-name'>iPad</a>
            <div class='price-area'>
                <span class='symbol'>USD</span>
                <span class='price'>379</span>
            </div>
        </dd>
    </dl>
    <dl class='item '>
        <dt class='photo'></dt>
        <dd class='detail'>
            <a class='item-name'>iPod</a>
            <div class='price-area'>
                <span class='symbol'>CAD</span>
                <span class='price'>139</span>
            </div>
        </dd>
    </dl>
</div>";
var html = new HtmlDocument();
html.LoadHtml(input);
var root = html.DocumentNode;
var list = new List<Data>();
foreach (var node in root.Descendants("dl"))
{
    var currency = node.Descendants()
       .Where(n => n.GetAttributeValue("class", "").Equals("symbol")).FirstOrDefault().InnerText;
    var price = node.Descendants()
       .Where(n => n.GetAttributeValue("class", "").Equals("price")).FirstOrDefault().InnerText;
    list.Add(new Data { Currency = currency, Price = price});
}

public class Data
{
    public string Currency { get; set; }
    public string Price { get; set; }
}

Или вы можете использовать query expression вместо части foreach:

var list = (from node in root.Descendants("dl") 
            let currency = node.Descendants().Where(n => n.GetAttributeValue("class", "").Equals("symbol")).FirstOrDefault().InnerText 
            let price = node.Descendants().Where(n => n.GetAttributeValue("class", "").Equals("price")).FirstOrDefault().InnerText 
            select new Data {Currency = currency, Price = price}).ToList();
person Sirwan Afifi    schedule 22.08.2015
comment
Это не работает. Программе не нравится root.Descendants("dl"). - person inquisitive_one; 24.08.2015
comment
@inquisitive_one root это doc.DocumentNode.root - person Sirwan Afifi; 24.08.2015
comment
Я изменил foreach stmt на foreach (var node in html.DocumentNode.Descendants("dl")) {. Это все еще не работает. Есть ли что-то еще, что мне нужно изменить? - person inquisitive_one; 24.08.2015
comment
@inquisitive_one В чем ошибка? Код работает без проблем на моем компьютере. Еще одна вещь input содержит ваш HTML в виде строки - person Sirwan Afifi; 24.08.2015
comment
Это странная часть. Я не получаю ошибку. я не попадаю в цикл foreach. Да, input, который я использую, это https://meadjohnson.world.tmall.com/search.htm?search=y&orderType=defaultSort&scene=taobao_shop. Я не уверен, почему вашему коду не нравится этот сайт. - person inquisitive_one; 24.08.2015
comment
Любые идеи о том, что мне делать дальше? - person inquisitive_one; 26.08.2015

Точная ошибка заключается в том, что в блоке foreach() "item" является переменной типа HtmlNode, но вы пытаетесь ее "индексировать". Вместо этого вы должны использовать

item.Descendants("symbol") 

or

item.SelectSingleNode(".//span[@class='symbol']");

Или Вы можете использовать этот код:

    var document = new HtmlWeb();
    var root = document.Load(url);
    var data = new List<Item>();
    foreach (var item in root.DocumentNode.SelectNodes("//dl"){
        var name = item.SelectSingleNode(".//a[@class='item-name']").InnerText;
        var price = item.SelectSingleNode(".//span[@class='price']").InnerText;
        var symbol = item.SelectSingleNode(".//span[@class='symbol']").InnerText;
        data.Add(new Item(){ Name = name, Price = price, Symbol = symbol });
    }
    public class Item{
        public string Name;
        public int Price;
        public string Symbol;
    }
person DenisFomin    schedule 22.08.2015
comment
Теперь я получаю NullReferenceException: ссылка на объект не указывает на экземпляр объекта. Я изменил запрос на: var name = item.SelectSingleNode(".//a[@class='item-name']").InnerText == null ? String.Empty : item.SelectSingleNode(".//a[@class='item-name']").InnerText; Это тоже не сработало. Что мне теперь делать? - person inquisitive_one; 24.08.2015
comment
Любые другие идеи, которые я мог бы использовать? - person inquisitive_one; 26.08.2015
comment
где именно вы получаете исключение? - person DenisFomin; 30.08.2015
comment
Примечание: я использую сайт https://meadjohnson.world.tmall.com/search.htm?search=y&orderType=defaultSort&scene=taobao_shop. Я получаю вышеупомянутую ошибку на var name = item.SelectSingleNode(".//a[@class='item-name']").InnerText;. - person inquisitive_one; 31.08.2015
comment
посмотрите, не является ли переменная элемента в блоке foreach нулевой, затем уточните, действительно ли элемент с этим именем класса существует на странице. - person DenisFomin; 31.08.2015