Пишу сейчас небольшое дополнение к «Блевантону» — включение в анализ страницы meta-тегов, заголовка, подписей к рисункам и т.д. в общем всего того текста, который учитывается поисковиками при индексации страницы.
Решил, не изобретая велосипед, воспользоваться уже готовыми решениями — форумов-то по Delphi в Рунете пруд пруди. Перерыл добрый полтинник сайтов и форумов в поисках подходящих процедур и функций — все не то. Может к концу первой сотни я бы и нашел чего-то стоящего, но терпения не хватило. Как обычно везде всё практически одно и то же с теми же недочетами в работе.
Больше всего улыбнула одна функция по разбору тегов страницы. Вот её код:
function GetNextTag(var Src:PChar; const Tag:string): string; var PStart,PEnd: PChar; begin Result := ''; PStart := AnsiStrPos(Src,PChar('<'+Tag+#0)); if PStart = nil then begin Src := StrEnd(Src); Exit; end; PStart := AnsiStrPos(PStart,PChar('>'+#0))+1; Src := PStart; PEnd := AnsiStrPos(Src,PChar('<!--'+Tag+'-->'+#0)); if PEnd = nil then begin Src := StrEnd(Src); Exit; end; Src := PEnd + Length(Tag) + 3; if PEnd = PStart then exit; SetLength(Result,PEnd - PStart); StrLCopy(@Result[1],PStart, Length(Result)); end;
Спору нет, функция написана по всем правилам и она корректно работает, но возникает одно «но» — но какое время займет чистка html-документа от тегов и при том чтение определенного набора атрибутов из этих тегов? Тем более, что функция не предусматривает чтения атрибутов, кстати сказать.
Остальные методы работы с html-документами, в принципе тоже недостаточно корректно работали с теми документами, которые я им давал на разбор. В числе прочих недостатков можно выделить следующие:
- невозможность чтения данных из meta-тегов
- игнорирование комментариев на странице
- игнорирование конструкций вида
//<![CDATA[
addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
var userSettings = {'url':'/','uid':'1','time':'1250247607'};
var ajaxurl = 'http://webdelphi.ru/wp-admin/admin-ajax.php', pagenow = 'post-new', adminpage = 'post-new-php';
//]]>
и ещё много разного рода недостатков. Вот я и решился на «изобретение». Представленный ниже способ очистки HTML-документа от служебной информации и html-тегов также не является панацеей от всех проблем, однако для меня он показал вполне удовлетворительные результаты.
Для работы нам понадобятся следующие компоненты: Edit, Button, Memo и idHTTP. Размещаете их на форме и подключаем дополнительно в uses два модуля: MSHTML и activex
Теперь на событие onClick у кнопки пишем следующий код:
procedure TForm1.Button1Click(Sender: TObject); var Cache: string; Doc: IHTMLDocument2; V: OleVariant; DocA: IHTMLElementCollection; DocElement: IHtmlElement; i:integer; begin Memo1.Clear; Cache:=IdHTTP1.Get(Edit1.Text); Doc := coHTMLDocument.Create as IHTMLDocument2; V := VarArrayCreate([0, 0], varVariant); V[0]:=Cache; Doc.Write(PSafeArray(TVarData(v).VArray)); DocA:=Doc.all.tags('meta')as IHTMLElementCollection; Memo1.Lines.Add(Doc.title); for i:=0 to DocA.length-1 do begin DocElement:=DocA.Item(i, 0) as IHtmlElement; Cache:=DocElement.getAttribute('name',0); if (LowerCase(Cache)='description')or(LowerCase(Cache)='keywords') then Memo1.Lines.Add(DocElement.getAttribute('content',0)) end; Memo1.Lines.Add(Doc.body.innerText); end;
Вот так в несколько строк мы получаем в Memo заголовок страницы, содержание мета-тегов keywords и description и основной текст со страницы.
Разберемся немного с тем, что написано в процедуре.
вначале загружаем весь документ в переменную Cache:
Cache:=IdHTTP1.Get(Edit1.Text);
теперь создаем новый экземпляр DOM страницы:
V := VarArrayCreate([0, 0], varVariant); V[0]:=Cache; Doc.Write(PSafeArray(TVarData(v).VArray)); Doc := coHTMLDocument.Create as IHTMLDocument2;
и применяем капельку знаний по работе с IHTMLDocument2 — создаем коллекцию всех meta-тегов страницы:
DocA:=Doc.all.tags('meta')as IHTMLElementCollection;
В цикле читаем атрибуты каждого элемента коллекции и, если аттрибут name удовлетворяет заданому условию — выписываем content мета-тега в Memo:
for i:=0 to DocA.length-1 do begin DocElement:=DocA.Item(i, 0) as IHtmlElement; Cache:=DocElement.getAttribute('name',0); if (LowerCase(Cache)='description')or(LowerCase(Cache)='keywords') then Memo1.Lines.Add(DocElement.getAttribute('content',0)) end;
ну и в конце — вытаскиваем чистый текст из тела страницы (текст между тегами body):
Memo1.Lines.Add(Doc.body.innerText);
Это, можно сказать, даже не процедура, а заготовка для процедуры. Сейчас буду дорабатывать её в плане чтения атрибутов рисунков и прикручивать к «Блевантону«. Если у кого-нибудь есть более оригинальная идея по очистки html-документов — буду благодарен за идею.

Привет, работает то оно конечно хорошо но вот если сайт в виндовой колировке то получим не то что надо, как поправить?
Так для таких случаев всегда под рукой две замечательные функции в Delphi есть: UTF8ToAnsi и AnsiToUTF8 — используй в зависимости от кодировки страницы и все. А в 2010 целый отдельный класс для кодировок выдуман, вроде бы TEncoding назывался
[…] вопрос я рассматривал в статье про очистку HTML-документа от тегов. Единственная «сложноть» при работе с […]