Парсинг с помощью Html Agility Pack

125
18 июля 2019, 23:00

Пытаюсь вытащить температуру из html кода страницы:

Пробую вот такой код:

        HtmlDocument hap = new HtmlDocument();
        HtmlWeb web = new HtmlWeb();
        HtmlDocument doc = web.Load("http://www.intellicast.com/Local/Weather.aspx?location=RSXX0063");
        HtmlNodeCollection nodes = hap.DocumentNode.SelectNodes("/html/body/div[1]/form/div[1]/div[2]/div[5]/table/tbody/tr[1]/td[1]/div[2]/div/table/tbody/tr[1]/td[3]/div[1]/a");
        if (nodes != null)
        {
            foreach (HtmlNode node in nodes)
            {
                Console.WriteLine(node);
            }
        }
        else
            Console.WriteLine("Ничего");
        Console.ReadLine();

Но в nodes ничего не собирается. Как я понял, с помощью моего XPath (достал я его с помощью расширения для Firefox) ищется то, что заключено в тег a, собственно температура, но он не собирает вообще ничего.

У сайта есть свой api, доступ к которому он "не хочет" отдавать просто так. Из этого можно сделать вывод, что температуру просто так не получить

Answer 1

В приведенном Вами примере кода есть ошибки. Помимо этого, используемый Вами URL перенаправляет (как минимум запросы из Германии) с 301 Moved Permanently на wunderground.com. Рабочий пример приведён ниже:

var web = new HtmlWeb();
var htmlDoc = new HtmlDocument();
string xPath = "//a[@href='/National/Temperature/Current.aspx']";
// или "//a[@title='Temperature']"
string url = "http://www.intellicast.com/Local/Weather.aspx?location=RSXX0063";
htmlDoc.LoadHtml(web.Load(url).Text);
var node = htmlDoc.DocumentNode.SelectSingleNode(xPath);

По поводу Вашей задачи...
Парсинг чужой HTML страницы для получения данных требует постоянного сопровождения кода, т.к. (как уже упомянул EvgeniyZ) может поменяться разметка на сайте, измениться URL, да мало ли может придти в голову владельцам сайта. И если уж вопрос стоит ребром и иначе никак, то (здесь позволю себе не согласиться с EvgeniyZ) привязывайтесь к элементам с Id, а не к классам, т.к. спецификация требует уникальность Id, а класс может быть добавлен хоть к каждому элементу или, как в Вашем случае, используйте уникальные (более или менее) атрибуты.
Если Вам необходимо получать сведения о погоде, то имеется огромное количество сервисов с бесплатным API, например openweathermap (разрешает не более 60 запросов в минуту бесплатно).

Answer 2

достал я его с помощью расширения для Firefox - и зря сделали.
Вы понимаете что у вас он выдал? А выдал он примерно следующее ...div[1]/div[2]/div[5]... - взять первый div / в нем взять второй div / в нем взять пятый div. Ну и так далее. То есть вся ваша портянка XPatch очень статична, а что будет если вдруг первый div окажется например 10-м? А нечего хорошего!

Правильным решением будет поиск чего то уникального в HTML (например имя или класс) и уже от этого элемента "плясать" дальше.

На скриншоте я вижу уникальное следующее:

<div class="Charcoal" ...>

Нам уже этого достаточно, что бы взять необходимые значения. Перепишем XPath примерно на следующий:

/div[@class='Charcoal']/a

Как видите в разы короче, чем у вас и менее статично.
В одно время мне очень сильно помогала эта шпаргалка, так что советую!

Но вообще я вам советую "парсить" HTML только в крайнем случае. Почти все сайты сейчас имеют динамическую подгрузку данных, они разделяют дизайн и источник данных и делается это обычно при помощи API. Например вот данные, который сайт получает в удобном JSON формате, без лишнего HTML...
Вот вам пару ответов в помощь один и два.

READ ALSO
Call Back API VK и WindowsForm С#

Call Back API VK и WindowsForm С#

Задалась целью написать простенького бота для вк на C#Хочу, чтобы бот был в сообщениях группы

150
DataGridView не отображает данные таблицы с файла

DataGridView не отображает данные таблицы с файла

Я для себя делаю кроссвордВот вопрос, почему в таблице не отображает с файла? Вот так я реализую код, все находится на 1 форме Crossword:

136
Алгоритм визуализации дерева

Алгоритм визуализации дерева

Как реализовать вертикальную иерархию дерева? Дерево - с произвольным количеством дочерних вершинУзел дерева хранит условные координаты...

174
Как сделать потоковый прием сообщений TCPClient?

Как сделать потоковый прием сообщений TCPClient?

Я не могу найти ответ на вопрос, я делаю простой чат с сервером и клиентом, сервер принимает все сообщения отправление клиентами и рассылает...

157