Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: 6310
Последний выпуск: 19.06.2015

HTML Parser

5.7K
28 июля 2011 года
Lindemann66
193 / / 21.07.2011
Всем привет!

Необходимо написать parser содержимого html - в частности, тэгов

Лично я в основу положил обычный проход по html, с поиском начального символа тэга <, определения типа тэга и считывания его содержимого до следующего открывающего, либо закрывающего тэга

Плюс, необходимо учитывать вложенность тэгов
То есть, если ситуация
[HTML]<div>текст1 <a>текст2</a> текст3</div>[/HTML]
то в результате должно получиться
div : текст 1 текст2 текст3
div, a : текст 2
a сохраняется, так как у него тип - inside (сам придумал), тк, если не приписывать содержимое тэга а в тэг div, может потеряться смысл содержимого тэга div

Вобщем-то, алгоритм почти реализован, но ситуация с вложенностью в нём обрабатывается плохо...

Может, у кого-то будут какие-то свежие идеи на счёт такого parser'а html?
Буду благодарен за любой ответ!
278
28 июля 2011 года
Alexander92
1.1K / / 04.08.2008
А что, стандартный XMLDocument и иже с ним не оно? На чем вообще пишете?

Ежели не пользуетесь .NET'ом - почему не регулярки? Последовательно ищете в документе все конструкции вида <tag>bla-bla-bla</tag>, потом проходитесь рекурсивно по bla-bla-bla и строите дерево.
5.7K
28 июля 2011 года
Lindemann66
193 / / 21.07.2011
Цитата: Alexander92
А что, стандартный XMLDocument и иже с ним не оно? На чем вообще пишете?

Ежели не пользуетесь .NET'ом - почему не регулярки? Последовательно ищете в документе все конструкции вида <tag>bla-bla-bla</tag>, потом проходитесь рекурсивно по bla-bla-bla и строите дерево.




пишу на MFC
думал по поводу рекурсии, но это ведь, по идее, медленнее, чем однопроходный алгоритм
но по факту вышло, что однопроходный не даёт достоверного хотя бы 90% результата

по поводу XMLDocument...если честно, в C++ ни разу не использовал, а там есть возможности для такого парсинга?

регулярки в C++ тоже не использовал, мне писали сюда код...
Вообще, регулярки в MFC, C++ через #include <atlrx.h> использовать надо?
Я вот пробовал, у меня этот заголовок не находился

Можешь примерно описать, в какую сторону можно копнуть?

278
28 июля 2011 года
Alexander92
1.1K / / 04.08.2008
Да можно и однопроходным, в общем-то; может, оно и проще получится, прикинуть надо. Только тогда тебе надо конечный автомат построить.

XMLDocument - это из .NET, в MFC ты этим не воспользуешься. Только если полезешь в управляемый код.

По поводу "куда копнуть" - либо строй конечный автомат и делай однопроходный алгоритм, либо рекурсивно. А потом можно будет сравнить, что быстрее и эффективнее. Подобные конечные автоматы почти в любой соответствующей литературе описаны, посмотри.
10
28 июля 2011 года
Freeman
3.2K / / 06.03.2004
Цитата: Alexander92
Да можно и однопроходным, в общем-то;


Порты SAX-а вроде и на C/C++ есть.

5.7K
28 июля 2011 года
Lindemann66
193 / / 21.07.2011
Цитата: Freeman
Порты SAX-а



а что это такое?

260
28 июля 2011 года
Ramon
1.1K / / 16.08.2003
Юзаем MSXML и не занимаемся ерундой.
5.7K
28 июля 2011 года
Lindemann66
193 / / 21.07.2011
Цитата: Ramon
Юзаем MSXML и не занимаемся ерундой.



Спасибо за совет!
Но можешь хотя бы вкратце натолкнуть на то, октуда копать в этом направлении?
В гугле я разъясняющей информации не нашёл

5.7K
28 июля 2011 года
Lindemann66
193 / / 21.07.2011
а MS XML подойдёт для парсинга HTML (XHTML) файла?

потому что, например, для load метода сказано:

Цитата:
load Method
Loads an XML document from the specified location.

399
28 июля 2011 года
KIV
432 / / 20.01.2009
Рекурсия не так уж и отнимает скорость. Больше стековую память. То есть если уровень вложенности тэгов будет порядка нескольких сотен, то может переполнится стек. Однако на практике найти такие документы крайне сложно, да и в параметрах компиляции можно увеличить размер стека до большего.

Зато алгоритм сразу становится проще и нагляднее. Некоторые вещи весьма геморно реализовывать без рекурсии и если она нужна, то непременно надо её использовать. Тут как раз такой случай.
360
29 июля 2011 года
P*t*
474 / / 15.02.2007
Писать свой парсер html - очень муторное дело, поскольку регулярно встречаются ужасающие несоответствия стандартам.
Например может быть такое:
<a href=/dir/>ссылка</a> - это нужно понимать как href="/dir/", а не как <a href="/dir" />
Часто встречаются непарные теги, иногда попадаются спецсимволы "<" и ">", не являющиеся началом или концом тега.
Один раз я видел лишний тег <body> в середине страницы и без соответствующего закрывающего.
Браузеры это умеют распознавать и отображают страницы нормально, но самостоятельно перебрать все возможные извращения будет сложно.
5.7K
01 августа 2011 года
Lindemann66
193 / / 21.07.2011
Согласен, потому мной было принято решение использовать MSHTML для парсинга страницы.
Вобщем-то, это уже реализовано

Вот код:
Он выполняет сканирование содержимого тэгов, заданных в списке

Код:
void AddTextBlocks(int page_id, CString html) {
    //Объявляем MSHTML переменные и создаём документ
    MSHTML::IHTMLDocument2Ptr pDoc;
    MSHTML::IHTMLDocument3Ptr pDoc3;
    MSHTML::IHTMLElementCollectionPtr pCollection;
    MSHTML::IHTMLElementPtr pElement;

    HRESULT hr = CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER,
        IID_IHTMLDocument2, (void**)&pDoc);
       
    //заносим код в SAFEARRAY и записываем его в документ
    SAFEARRAY* psa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
    VARIANT *param;
    bstr_t bsData = (LPCTSTR)html;
    hr = SafeArrayAccessData(psa, (LPVOID*)&param);
    param->vt = VT_BSTR;
    param->bstrVal = (BSTR)bsData;
       
    hr = pDoc->write(psa);
    hr = pDoc->close();
       
    bsData.Detach();
    SafeArrayDestroy(psa);

    //использую IHTMLDocument3 для получения тегов.
    //эта функция доступна только в IE5 +
    //есть вариант без использования IHTMLDocument3 - можно просто запустить через все теги HTML
    // (IHTMLDocument2->all)
    pDoc3 = pDoc;  

           //список тэгов для обработки
    vector<CString> tags_names = GetListsOfContentTag();
    for (int i = 0; i < tags_names.size(); i++) {
        pCollection = pDoc3->getElementsByTagName(bstr_t(tags_names));
        for(long j = 0; j < pCollection->length; j++){
            pElement = pCollection->item(j, (long)0);
           
            if(pElement != NULL){
                //второй параметр означает, что необходимо получить текст внутри атрибута
                //CString str = pElement->getAttribute("href", 2);
                //получаем содержимое тэга
                CString text = (LPCTSTR)pElement->GetinnerText();
            }
        }
    }

    //добавляем информацию о текстовых блоках в БД
    AddTextBlocksToDb(blocks);
}


Всем спасибо за советы :)

Знаете кого-то, кто может ответить? Поделитесь с ним ссылкой.

Ваш ответ

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог