Парсер HTML для получения сообщений в блоге

Мне нужно создать синтаксический анализатор html, который с учетом URL-адреса блога возвращает список со всеми сообщениями на странице.

  • т.е. если на странице 10 сообщений, она должна вернуть список из 10 элементов div, где каждый элемент div содержит h1 и p

Я не могу использовать его rss-канал, потому что мне нужно точно знать, как он выглядит для пользователя, есть ли в нем какая-либо реклама, изображение и т. д., и, в отличие от некоторых блогов, есть только сводка его содержания, а в ленте есть все, наоборот.

Во всяком случае, я сделал один, который загружает его ленту и выполняет поиск аналогичного контента в html, он очень хорошо работает для некоторых блогов, но не для других.

Я не думаю, что смогу сделать синтаксический анализатор, который работает для 100% анализируемых им блогов, но я хочу сделать как можно лучше.

Каким должен быть лучший подход? Ищите теги, у которых атрибут id равен «post», «content»? Ищите теги p? и т. д. и т. д. и т. д.

Заранее благодарю за любую помощь!


person Bruno    schedule 15.04.2011    source источник


Ответы (4)


«Наилучший из возможных» оказывается «наиболее разумным», и вы должны определить, что является разумным. Вы можете получить очень большое количество блогов, посмотрев, как распространенные инструменты для ведения блогов (WordPress, LiveJournal и т. д.) генерируют свои страницы и код специально для каждой из них.

Общий случай оказывается очень сложной задачей, потому что каждый инструмент для ведения блога имеет свой собственный формат. Возможно, вы сможете сделать вывод, используя «стандартные» идентификаторы, такие как «публикация», «контент» и т. д., но это сомнительно.

У вас также будут трудности с рекламой. Многие объявления создаются с помощью JavaScript. Таким образом, загрузка страницы даст вам только код JavaScript, а не сгенерированный HTML. Если вы действительно хотите идентифицировать рекламные объявления, вам необходимо определить код JavaScript, который их генерирует. Или ваша программа должна будет выполнить JavaScript для создания окончательного DOM. И тогда вы сталкиваетесь с проблемой, похожей на вышеописанную: выяснить, является ли какой-то конкретный фрагмент HTML рекламой.

Есть эвристические методы, которые несколько успешны. Ознакомьтесь с разделом Идентификация основного контента страницы, чтобы получить ответы на аналогичный вопрос.

person Jim Mischel    schedule 15.04.2011

Я не думаю, что вы добьетесь успеха в этом. Возможно, вы сможете разобрать один блог, но если движок блога изменит материал, он больше не будет работать. Я также не думаю, что вы сможете написать универсальный парсер. Возможно, вы даже добьетесь частичного успеха, но это будет невероятный успех, потому что в этом контексте все так подвержено ошибкам. Если вам нужен контент, вы должны использовать RSS. Если вам нужно сохранить (просто сохранить), как это выглядит, вы также можете это сделать. Но разбор по тому, как это выглядит? Я не вижу конкретных успехов в этом.

person Adriano Carneiro    schedule 15.04.2011

Используйте пакет гибкости HTML. Это парсер HTML, созданный для этого.

person Francis Gilbert    schedule 15.04.2011
comment
Пакет HTML Agility анализирует только HTML. Это не помогает определить, какие части являются основным контентом, а какие — рекламой или типичным шаблоном. - person Jim Mischel; 16.04.2011
comment
Я использую его с текущим парсером =) - person Bruno; 16.04.2011

Я только что сделал что-то подобное для блога нашей компании, который использует WordPress. Это хорошо для нас, потому что наш блог wordress не менялся годами, но другие правы в том, что если ваш html сильно меняется, синтаксический анализ становится громоздким решением.

Вот что я рекомендую:

С помощью Nuget установите RestSharp и HtmlAgilityPack. Затем загрузите fizzler и включите эти ссылки в свой проект (http://code.google.com/p/fizzler/downloads/list).

Вот пример кода, который я использовал для реализации поиска по блогу на своем сайте.

using System;
using System.Collections.Generic;
using Fizzler.Systems.HtmlAgilityPack;
using RestSharp;
using RestSharp.Contrib;

namespace BlogSearch
{
    public class BlogSearcher
    {
        const string Site = "http://yourblog.com";

        public static List<SearchResult> Get(string searchTerms, int count=10)
        {            
            var searchResults = new List<SearchResult>();

            var client = new RestSharp.RestClient(Site);
            //note 10 is the page size for the search results
            var pages = (int)Math.Ceiling((double)count/10);

            for (int page = 1; page <= pages; page++)
            {
                var request = new RestSharp.RestRequest
                                  {
                                      Method = Method.GET,
                                      //the part after .com/
                                      Resource = "page/" + page
                                  };

                //Your search params here
                request.AddParameter("s", HttpUtility.UrlEncode(searchTerms));

                var res = client.Execute(request);

                searchResults.AddRange(ParseHtml(res.Content));
            }

            return searchResults;
        }

        public static List<SearchResult> ParseHtml(string html)
        {            
            var doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);
            var results = doc.DocumentNode.QuerySelectorAll("#content-main > div");

            var searchResults = new List<SearchResult>();
            foreach(var node in results)
            {
                bool add = false;
                var sr = new SearchResult();

                var a = node.QuerySelector(".posttitle > h2 > a");
                if (a != null)
                {
                    add = true;
                    sr.Title = a.InnerText;
                    sr.Link = a.Attributes["href"].Value;
                }

                var p = node.QuerySelector(".entry > p");
                if (p != null)
                {
                    add = true;
                    sr.Exceprt = p.InnerText;
                }

                if(add)
                    searchResults.Add(sr);
            }

            return searchResults;
        }


    }

    public class SearchResult
    {
        public string Title { get; set; }
        public string Link { get; set; }
        public string Exceprt { get; set; }
    }
}

Удачи, Эрик

person Eric    schedule 16.06.2011