Форум программистов, компьютерный форум, киберфорум
Наши страницы
C#: Web, ASP.NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
holod2014
30 / 11 / 4
Регистрация: 01.03.2014
Сообщений: 344
1

Трудности с HtmlAgilityPack

05.05.2018, 23:55. Просмотров 992. Ответов 10

Добрый день, форумчане.

Осваиваю HtmlAgilityPack. Пытаюсь из заранее загруженной страницы получить данные. А именно:
Есть страница 1.htm.
Хочу получить значение из таблицы напротив строки "Операционная система". (сам документ прикрепил).
Делаю так:
C#
1
2
3
4
5
6
7
8
9
        private void simpleButton1_Click(object sender, EventArgs e)
        {
            // Создаю экземпляр класса
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            // Загружаю файл
            doc.Load(@"D:\(тут путь к файлу)\1.htm");
            // Пытаюсь получить информацию из ноды, но получаю null
            HtmlAgilityPack.HtmlNode bodyNode = doc.DocumentNode.SelectSingleNode("//TD[@CLASS=pt]");
            ...
Вообще надо много информации из файлика вытащить, но думаю, что если с одной строчкой получится, то дальше по аналогии.
0
Вложения
Тип файла: rar 1.rar (33.2 Кб, 3 просмотров)
Лучшие ответы (1)
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.05.2018, 23:55
Ответы с готовыми решениями:

Какие-то странности с html, из-за этого трудности с парсингом в HtmlAgilityPack.dll
Есть таблица в html коде: <table cellspacing="0" cellpadding="0" width="100%" border="1"> ...

HtmlAgilityPack
Есть html код,использующий класс abcsd_aktive (к примеру), соответственно есть класс...

Парсинг, HtmlAgilityPack
В общем давно хотел затронуть тему парсинга, сейчас появился повод... В общем полазил я по инету...

Обход php на HtmlAgilityPack
Всем привет! Кто знает как обойти php? Код отображает до <div class="react" id="root">, а дальше не...

Получить XPath HtmlAgilityPack
Всем доброго времени суток! Представилась задача получить XPath элементов Html страницы, я...

10
holod2014
30 / 11 / 4
Регистрация: 01.03.2014
Сообщений: 344
06.05.2018, 00:25  [ТС] 2
Необходимую строку получил так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
 
        private void simpleButton1_Click(object sender, EventArgs e)
        {
            // Создаю экземпляр класса
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            // Загружаю файл
            doc.Load(@"D:\(тут путь к файлу)\1.htm");
 
            foreach (HtmlAgilityPack.HtmlNode node in doc.DocumentNode.SelectNodes("//body/table[2]/tr[8]/td[4]"))
            {
                string stroka = node.InnerText;
            }
Но это вариант "в лоб". Если не будет изменяться структура моего документа. А как можно с помощь поиска пока не разобрался.
0
OwenGlendower
Супер-модератор
Эксперт .NET
11419 / 9621 / 4046
Регистрация: 17.03.2014
Сообщений: 19,242
Записей в блоге: 1
Завершенные тесты: 2
10.05.2018, 23:36 3
holod2014, интересная задача из-за кривого html с которым у HtmlAgilityPack явные трудности. Но обойти их все-таки можно
C#
1
2
3
4
5
6
7
8
Dictionary<string, string> dict = doc.DocumentNode.SelectSingleNode("//td[@class='pt']")
    .ParentNode.NextSibling
    .SelectNodes("./tr/td")
    .Select(el => el.InnerText).First().Split('\n')
    .Where(text => text.Contains("&nbsp;&nbsp;"))
    .Select(text => text.Split(new[]{"&nbsp;&nbsp;"}, StringSplitOptions.None))
    .ToDictionary(arr => arr[0], arr => arr[1]);
string os = dict["Операционная система"];
1
holod2014
30 / 11 / 4
Регистрация: 01.03.2014
Сообщений: 344
10.05.2018, 23:48  [ТС] 4
Ругается на последней строке, "Данный ключ отсутствует в словаре."
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        private void button1_Click(object sender, EventArgs e)
        {
            HtmlAgilityPack.HtmlDocument doc1 = new HtmlAgilityPack.HtmlDocument();
            doc1.Load(@"путь");
 
            Dictionary<string, string> dict = doc1.DocumentNode.SelectSingleNode("//td[@class='pt']")
            .ParentNode.NextSibling
            .SelectNodes("./tr/td")
            .Select(el => el.InnerText).First().Split('\n')
            .Where(text => text.Contains("&nbsp;&nbsp;"))
            .Select(text => text.Split(new[] { "&nbsp;&nbsp;" }, StringSplitOptions.None))
            .ToDictionary(arr => arr[0], arr => arr[1]);
            string os = dict["Компьютер  "];
        }
0
10.05.2018, 23:48
OwenGlendower
Супер-модератор
Эксперт .NET
11419 / 9621 / 4046
Регистрация: 17.03.2014
Сообщений: 19,242
Записей в блоге: 1
Завершенные тесты: 2
10.05.2018, 23:50 5
holod2014, попробуй без пробелов в конце - dict["Компьютер"]
0
holod2014
30 / 11 / 4
Регистрация: 01.03.2014
Сообщений: 344
10.05.2018, 23:51  [ТС] 6
Как-то так.
0
Изображения
Тип файла: png Снимок.PNG (17.8 Кб, 6 просмотров)
OwenGlendower
Супер-модератор
Эксперт .NET
11419 / 9621 / 4046
Регистрация: 17.03.2014
Сообщений: 19,242
Записей в блоге: 1
Завершенные тесты: 2
10.05.2018, 23:54 7
holod2014, покажи какие элементы есть в dict
0
holod2014
30 / 11 / 4
Регистрация: 01.03.2014
Сообщений: 344
11.05.2018, 00:03  [ТС] 8
Ничего...
0
Изображения
Тип файла: png Снимок.PNG (24.1 Кб, 3 просмотров)
OwenGlendower
Супер-модератор
Эксперт .NET
11419 / 9621 / 4046
Регистрация: 17.03.2014
Сообщений: 19,242
Записей в блоге: 1
Завершенные тесты: 2
11.05.2018, 00:25 9
holod2014, по ошибке воспользовался старой версией HtmlAgilityPack и поэтому похоже у нас разные результаты. Попробуй такой вариант формирования словаря
C#
1
2
3
4
5
6
7
8
Dictionary<string, string> dict = doc1.DocumentNode.SelectSingleNode("//td[@class='pt']")
    .ParentNode.NextSibling
    .SelectNodes("./tr")
    .Skip(1)
    .ToDictionary(
        el => el.ChildNodes[2].InnerText.Replace("&nbsp;", "").Trim(),
        el => el.ChildNodes[3].InnerText
    );
1
holod2014
30 / 11 / 4
Регистрация: 01.03.2014
Сообщений: 344
11.05.2018, 08:42  [ТС] 10
Спасибо, так работает.
А что надо сделать, чтобы в словарь помещалась не только первая таблица, а скажем и вторая тоже ("Суммарная информация")?
0
OwenGlendower
Супер-модератор
Эксперт .NET
11419 / 9621 / 4046
Регистрация: 17.03.2014
Сообщений: 19,242
Записей в блоге: 1
Завершенные тесты: 2
11.05.2018, 14:00 11
Лучший ответ Сообщение было отмечено holod2014 как решение

Решение

holod2014, с первой таблицей нам "повезло" - там нет одинаковых названий. Дальше уже начинаются повторения. Поэтому Dictionary уже не прокатит. Нужно использовать Lookup коллекцию или делать свою иерархическую структуру данных. Вот пример с Lookup
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ILookup<string,string> lookup = doc1.DocumentNode.SelectNodes("//td[@class='pt']")
    .Take(2) // Сколько таблиц брать
    .Select(td => td.ParentNode.NextSibling)
    .SelectMany(table => table.SelectNodes("./tr")
        .Skip(1)
        .Where(tr => tr.SelectNodes("td").Any(td => td.InnerText.EndsWith("&nbsp;&nbsp;")))
        .Select(tr => new KeyValuePair<string, string>(
            tr.ChildNodes[tr.ChildNodes.Count-2].InnerText.Replace("&nbsp;", "").Trim(),
            tr.ChildNodes[tr.ChildNodes.Count-1].InnerText
        ))
    )
    .ToLookup(
        kvp => kvp.Key,
        kvp => kvp.Value
    );
1
11.05.2018, 14:00
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.05.2018, 14:00

Парсинг с помощью HtmlAgilityPack
Здравствуйте. Нужно спарсить со страницы два числа, которые стоят между тегов &lt;span...

Find Source : HtmlAgilityPack
Здравствуйте, возникла необходимость парсить страница asp, выбрал инструмент HtmlAgilityPack для...

HtmlAgilityPack: внутренний текст тега
Добрый ... В тексте с html разметкой &lt;tr&gt; &lt;th&gt;&lt;span&gt;коэффициент ... &lt;/span&gt;&lt;/th&gt;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.