Подтвердить что ты не робот

HtmlAgilityPack и выбор узлов и субнодов

Надеюсь, кто-то может мне помочь.

Предположим, у меня есть html-документ, содержащий несколько div, подобных этому примеру:

<div class="search_hit">

    <span prop="name">Richard Winchester</span>
    <span prop="company">Kodak</span>
    <span prop="street">Arlington Road 1</span>

</div>
<div class="search_hit">

    <span prop="name">Ted Mosby</span>
    <span prop="company">HP</span>
    <span prop="street">Arlington Road 2</span>

</div>

Я использую HtmlAgilityPack для получения html-документа. Мне нужно знать, как я могу получить промежутки для каждого "search_hit" -div?

Моя первая мысль была примерно такой:

foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
     foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("//span[@prop]"))
     {

     }
}

Каждый div должен быть объектом с включенными пролетами как свойствами. I. e.

public class Record
    {
        public string Name { get; set; }
        public string company { get; set; }
        public string street { get; set; }
    }

И этот список будет заполнен:

public List<Record> Results = new List<Record>();

Но XPATH, который я использую, не выполняет поиск в подзоне, как он должен делать. Он швыряет, что он снова и снова ищет весь документ.

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

Кто-нибудь знает решение? Я уже так много играл, что теперь я полностью смущен:)

Любая помощь приветствуется!

4b9b3361

Ответ 1

Следующие работы для меня. Важный бит точно так же, как BeniBela отметил добавление точки во втором вызове "SelectNodes".

List<Record> lstRecords=new List<Record>();
foreach (HtmlNode node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']"))
{
  Record record=new Record();
  foreach (HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
  {
    string attributeValue = node2.GetAttributeValue("prop", "");
    if (attributeValue == "name")
    {
      record.Name = node2.InnerText;
    }
    else if (attributeValue == "company")
    {
      record.company = node2.InnerText;
    }
    else if (attributeValue == "street")
    {
      record.street = node2.InnerText;
    }
  }
  lstRecords.Add(record);
}

Ответ 2

Если вы используете //, он ищет от начала документа.

Используйте .// для поиска всех из текущего node

 foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))

Или полностью отбросить префикс для поиска только для прямых детей:

 foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes("span[@prop]"))

Ответ 3

Прежде всего, взгляните на это: Html Agility Pack - проблема выбора подноса

Вот полное рабочее решение для вашего вопроса:

IList<Record> results = new List<Record>();
foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
    var record = new Record();
    record.Name = node.SelectSingleNode(".//span[@prop='name']").InnerText;
    record.company = node.SelectSingleNode(".//span[@prop='company']").InnerText;
    record.street = node.SelectSingleNode(".//span[@prop='street']").InnerText;
    results.Add(record);
}

Если вы прочитаете вопрос, на который я указал вам, вы увидите, что выполнение ./span[@prop='name'] точно такое же, поскольку те span узлы являются (прямыми) дочерними элементами div node.


Если узлы span не имеют этих атрибутов prop, и вы хотите назначить их в зависимости от того, какой порядок они отображаются, вы можете сделать:

foreach (var node in doc.DocumentNode.SelectNodes("//div[@class='search_hit']")) {
    var spanNodes = node.SelectNodes("./span");
    var record = new Record();
    record.Name = spanNodes[0].InnerText;
    record.company = spanNodes[1].InnerText;
    record.street = spanNodes[2].InnerText;
    results.Add(record);
}

Ответ 4

Позор мне:)

Все вы были правы.

Я нашел проблему. Это исключение NullReferenceException продолжало насмехаться, поэтому я потратил больше времени, чтобы подробно рассмотреть его. Между всеми этими divs был один div с тем же атрибутом class= 'search-hit' ', но без внутренних интервалов. Вот почему он пропускает ошибку во втором цикле.

foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//span[@prop]/ancestor::div[@class='search_hit']"))
   {
        Record rec = new Record();
        foreach (HtmlAgilityPack.HtmlNode node2 in node.SelectNodes(".//span[@prop]"))
           {
           }
           rList.Results.Add(rec);
   }

Работающий выше код.

Спасибо, ребята, за ваше время и помощь!

Ответ 5

Я использовал это. class convert id

  HtmlNodeCollection nodes = dokuman.DocumentNode.SelectNodes("//div[@id='search_hit']//span[@prop]");


            for (int i = 0; i < nodes .Count; i++)
        {
            var record = new Record();


                record.Name = links[i].InnerText;   results.Add(record);  }