уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Как Вы понимаете, этот пост никак не связан с домушничеством и воровством :). Сегодня я поделюсь с Вами ещё одним простым способом получения необходимой информации из Web-документов.

Однако, прежде, чем начинать программировать, я настоятельно рекомендую Вам ознакомиться со статьей Wiki о DOM, т.к. без понимания всей сути вопроса будет очень трудно понять как всё работает.

Теперь давайте разберемся, что нам необходимо получить из документа, чтобы провести его анализ на предмет поисковой оптимизации (SEO)? Самое основное, на мой взгляд, при анализе любой страницы это:

  1. Заголовок страницы (Title).
  2. Количество ссылок и их тип (внутренние/внешние ссылки).
  3. Содержимое мета-тегов keywords и description.
  4. Содержимое всех заголовков H1-H5 (ну, или H10 — кому какая глубина анализа нужна)
  5. Подписи к рисункам, если таковые имеются на странице.
  6. Длину текста страницы и сам текст.

Имея в своем распоряжении перечисленные выше данные, мы сможем провести простейший анализ HTML-документа, а именно:

  1. Определить список ключевых слов.
  2. Определить плотность каждого ключевого слова/фразы на странице.
  3. Определить расположение ключевых слов на странице.
  4. При необходимости предложить пользователю список. предположительных ключевых слов/фраз.
  5. Выявить недочеты и ошибки SEO на странице.

Теперь давайте попробуем вытащить все необходимые данные.  Сегодня я не буду Вам советовать какие компоненты использовать, какой интерфейс придумать для программы, т.к. это все субъективные детали, а сосредоточусь именно на программном коде. Единственное, что следует сказать — это то, что для получения содержимого HTML-страницы я использую компонент Indy — idHTTP.

Итак, первое, что нам необходимо — это получить экземпляр DOM в свое распоряжении. Сделать это можно следующим образом:

var Doc: IHTMLDocument2; //экземпляр документа
procedure GetDom(const URL: string; idHTTP: TIdHTTP);
var Cache: string;
    V: OleVariant;
begin
  Cache:=IdHTTP.Get(url);
  Doc:=coHTMLDocument.Create as IHTMLDocument2; //создали экземпляр документа
  V:=VarArrayCreate([0,0], varVariant);
  V[0]:=Cache;
  Doc.Write(PSafeArray(TVarData(v).VArray)); //записали полученные данные
end;

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

1. Получение заголовка страницы (Title)

var Str: string;
begin
...
  Str:=Doc.title;
...
end;

2. Получение всех ссылок на странице

var Links: TStringList;
begin
...
  Links:=TStringList.Create;
  for i:=0 to Doc.links.length-1 do
    Links.Add(Doc.links.item(i));
...
end;

Если Вам необходимо получить анкоры ссылок, например, чтобы определить, что контекстная реклама, которую Вы заказывали у веб-мастера правильно проставлена на странице, то это делается следующим образом:

var DocA: IHTMLElementCollection; //коллекция элементов
    DocElement: IHtmlElement; //один элемент
    i: integer;
begin
...
  Links:=TStringList.Create;
  DocA:=Doc.all.tags('A') as IHTMLElementCollection;
  for i:=0 to DocA.length-1 do
    begin
      DocElement:=DocA.item(i,0)as IHTMLElement;
      Links.Add(DocElement.innerText) //читаем текст внутри тега
    end;
...
end;

3.  Получение содержимого мета-тегов keywords и description

Этот вопрос я рассматривал в статье про очистку HTML-документа от тегов. Единственная «сложноть» при работе с мета-тегами заключается в чтении не текста внутри тега, а атрибута content.

4. Получение содержимого всех заголовков H1-H5

Здесь всё аналогично работе с анкорами ссылок:

var DocA: IHTMLElementCollection; //коллекция элементов
    DocElement: IHtmlElement; //один элемент
    i: integer;
begin
...
  Links:=TStringList.Create;
  DocA:=Doc.all.tags('H1') as IHTMLElementCollection;
  for i:=0 to DocA.length-1 do
    begin
      DocElement:=DocA.item(i,0)as IHTMLElement;
      Links.Add(DocElement.innerText) //читаем текст внутри тега
    end;
...
end;

Аналогично, изменяя имя тега на Н2, Н3 и т.д. получаем содержимое всех тегов заголовков.

5.  Получение подписей к рисункам.

Немного посмотрев на исходные коды различных html-документов можно выделить следующие атрибуты тега IMG:

  • alt — короткое описание
  • title — заголовок для рисунка (такой атрибут используется, например, при вставке рисунка в пост WordPress)
  • longdesc — подробное описание рисунка (такой атрибут использует, например, редактор Front Page)

Таким образом, при чтении подписи к рисункам нам необходимо проверить наличие всех трех атрибутов и прочитать их:

var  img_alt : TStringList;
     DocA: IHTMLElementCollection; //коллекция элементов
     DocElement: IHtmlElement; //один элемент
     i: integer;
...
begin
...
  img_alt:=TStringList.Create;
  DocA:=Doc.all.tags('img')as IHTMLElementCollection;
  for i:=0 to DocA.length-1 do
    begin
      DocElement:=DocA.Item(i, 0) as IHtmlElement;//получили элемент коллекции
      //проверяем тег на наличие атрибута
      if length(DocElement.getAttribute('alt',0))>0 then
         img_alt.Add(DocElement.getAttribute('alt',0));
      else
        if length(DocElement.getAttribute('title',0))>0 then
          img_alt.Add(DocElement.getAttribute('title',0));
        else
          if length(DocElement.getAttribute('longdesc',0))>0 then
            img_alt.Add(DocElement.getAttribute('longdesc',0));
    end;
...
end;

6. Получение текста страницы

Здесь опять же все просто и понятно:

var body_html: string;
...
begin
...
  body_html:=Doc.Body.innerText;
...
end;

Теперь у Вас будут в руках все необходимые данные для анализа страницы. Анализируйте, ищите ошибки и недочеты, улучшайте свои сайты.

5 1 голос
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
31 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Курский бомж
11/12/2009 22:33

В javascript на странице используется переменная с нужным мне значением, можно ли средствами delphi как-то получить её значение?

Курский бомж
13/12/2009 13:23

Для себя программу пишу, подгружаю в webbrowser страничку http://old.station.ru/player.aspx?radio_id=5404 например, и хочу вытянуть программно название песни и артиста….

Курский бомж
13/12/2009 22:00

Vlad, Спасибо большое! Теперь все намного проще :-) Как с сессией разделаюсь то по вашим статьям думаю без проблем выдеру из кода эту информацию, хоть и не пробовал еще ни разу :-)

Андрей
Андрей
01/03/2010 05:19

Так-то всё бы оно ничего, только вот нет самого главного: поиск по DOM-дереву. Если мне нужно добраться до отдельных тегов без классов и id в разных местах кода, то вот тут и начинается настоящий геморрой.

sever
sever
17/03/2010 22:51

Извените за тупой вопрос IHTMLDocument2 что это такое как подключить ?

sever
sever
17/03/2010 23:11

У меня делфи7 подскажите, пожалуйста, Doc.Write(PSafeArray(TVarData(v).VArray)); у меня выдает UndeclaredIdentifier PSafeArray. Хотя и в подсказке все верно, но упорно пишет неопределен. :(

sever
sever
17/03/2010 23:31

Все спс не надо, забыл просто в uses добавить Activex ))

sever
sever
18/03/2010 00:14

[code]var Doc: IHTMLDocument2; //экземпляр документа
procedure GetDom(const URL: string; idHTTP: TIdHTTP);
var Cache: string;
V: OleVariant;
begin
Cache:=IdHTTP.Get(url);
Doc:=coHTMLDocument.Create as IHTMLDocument2; //создали экземпляр документа
V:=VarArrayCreate([0,0], varVariant);
V[0]:=Cache;
Doc.Write(PSafeArray(TVarData(v).VArray)); //записали полученные данные
end;[/code].

Как обратиться к этой процедуре ? GetDom(‘какойтоЮрл’,?); выдает ошибку соккет еррор. Что с этим делать ? я прально передаю параметры ?

Александр
11/12/2010 00:27

ЕДИНСТВЕННЫЙ НОРМАЛЬНЫЙ БЛОГ

Надежда
Надежда
11/03/2011 00:22

2. Получение всех ссылок на странице
Links.Add(Doc.links.item(i));

[Error] Not enough actual parameters

damir
damir
26/04/2011 15:44

Здравствуйте. Я не очень опытный программист, но мне нужно вытащить DOM с сайта. Можно вас попросить выложить элементарный код как это сделать. Адрес вводится через Edit, DOM выводится в поле MEMO. Или хотя бы объясните подробнее код представленный в самом начале. Очень нужно.

damir
damir
26/04/2011 17:20

мне без разницы куда выводить, главное получить DOM в виде текста. мне получается нужно создать переменную, потом переменной придуть значение IdHTTP.Get(url); и дальше просто в блокнот скинуть значение переменной?

damir
damir
26/04/2011 23:01

я не могу понять что такое IHTMLDocument2, где это взять? где смотреть?

Alexo
Alexo
28/04/2011 16:09

uses MSHTML;

Андрей
30/05/2011 18:41

У меня всё получилось но при запуске вылетает табличка — типа
«во время выполнения произошла ошибка, запустить отладку?
Строка1. Синтаксическая ошибка»
 
Как исправить.
Программа работает но это окошко задолбало.
Doc.Write(PSafeArray(TVarData(v).VArray));  — убираю и ошибки нет, но и толку от проги нет тоже.

Андрей
30/05/2011 20:36

Первую проблему решил. Теперь вторая
 
Links.Add(Doc.links.item(i));  — пишет not enough actual parameter

Андрей
30/05/2011 21:26

Решил проблему так
 
for i:=0 to Doc.links.length-1 do
begin
firstLink:=Doc.links.item(i,») as IHTMLElement;
mmo2.Lines.Add(firstLink.toString) ;
end; a:=a+1;
until a=mmo1.lines.count-1;
 
Правильно ли?

viRUS
viRUS
12/08/2011 20:57

IdHTTP.Get(url); и дальше просто в блокнот скинуть значение переменной?

var list:Tstringlist;
begin
list:=Tstringlist.Create;
list:=IdHTTP.Get(url);
list.SaveToFile(‘имя_файла’);
list.Destroy;
end;

viRUS
viRUS
18/08/2011 00:05

поправка
list.text:=IdHTTP.Get(url);

trackback

[…] delphi html getAttribute […]

trackback

[…] статье «Что можно «вытащить» из DOMа» мы немного касались таких свойств объекта Document как […]

Stas Panteleyev
29/11/2015 17:31

Влад, приветствую, повторял твой пример, но споткнулся на пункте 2, где собираются ссылки. Ругается на этой строке Links.Add(Doc.links.item(i)) — мало ему видите ли аргументов))) Я полез во внутренности MSHTML, IHTMLElementCollection = interface(IDispatch) [‘{3050F21F-98B5-11CF-BB82-00AA00BDCE0B}’] function toString: WideString; safecall; procedure Set_length(p: Integer); safecall; function Get_length: Integer; safecall; function Get__newEnum: IUnknown; safecall; function item(name: OleVariant; index: OleVariant): IDispatch; safecall; function tags(tagName: OleVariant): IDispatch; safecall; property length: Integer read Get_length write Set_length; property _newEnum: IUnknown read Get__newEnum; end; И что мы видим? function item(name: OleVariant; index: OleVariant): IDispatch; safecall; 2 аргумента, тип функции IDispatch — как с этим работать? )) Я просто с интерфейсами… Подробнее »

Stas Panteleyev
03/12/2015 05:23

В общем, разобрался, но все равно спасибо за внимание.

Вячеслав
Вячеслав
20/02/2018 06:37

ребята подскажите, столкнулся с проблемой..пробую парсить страницы своего сайта, все здорово получается до тех пор, пока в коде странице прога не нарывается на элементы HTML 5 и сразу же информирует об этом и если взять для примера details то исходный текст через инди показывается норм…как побороть эту беду с обходом для игнорирования скриптов и дальше так сказать по тексту бежать далее..такой параметр как silent — true из веббраузера не работает, да и не интересует веббраузер, только парсинг через документ..знающие откликнитесь и укажите путь побороть отключения скриптов в доке, всем спс за внимание