Как Вы понимаете, этот пост никак не связан с домушничеством и воровством :). Сегодня я поделюсь с Вами ещё одним простым способом получения необходимой информации из Web-документов.
Однако, прежде, чем начинать программировать, я настоятельно рекомендую Вам ознакомиться со статьей Wiki о DOM, т.к. без понимания всей сути вопроса будет очень трудно понять как всё работает.
Теперь давайте разберемся, что нам необходимо получить из документа, чтобы провести его анализ на предмет поисковой оптимизации (SEO)? Самое основное, на мой взгляд, при анализе любой страницы это:
- Заголовок страницы (Title).
- Количество ссылок и их тип (внутренние/внешние ссылки).
- Содержимое мета-тегов keywords и description.
- Содержимое всех заголовков H1-H5 (ну, или H10 — кому какая глубина анализа нужна)
- Подписи к рисункам, если таковые имеются на странице.
- Длину текста страницы и сам текст.
Имея в своем распоряжении перечисленные выше данные, мы сможем провести простейший анализ HTML-документа, а именно:
- Определить список ключевых слов.
- Определить плотность каждого ключевого слова/фразы на странице.
- Определить расположение ключевых слов на странице.
- При необходимости предложить пользователю список. предположительных ключевых слов/фраз.
- Выявить недочеты и ошибки 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;
Теперь у Вас будут в руках все необходимые данные для анализа страницы. Анализируйте, ищите ошибки и недочеты, улучшайте свои сайты.
В javascript на странице используется переменная с нужным мне значением, можно ли средствами delphi как-то получить её значение?
Самому как-то такие действия не приходилось выполнять, но, думаю, что в принципе возможно. Нужен пример html-странички и этой переменной.
Для себя программу пишу, подгружаю в webbrowser страничку http://old.station.ru/player.aspx?radio_id=5404 например, и хочу вытянуть программно название песни и артиста….
Просто так загрузить страничку и получить песню — не получится однозначно, т.к. название песни и автор передаются по запросу GET на адрес http://old.station.ru/getsong.aspx?id=station01. В исходном тексте этой страницы содержится, интересующая вас информация. Достаточно просто немного проанализировать http-заголовки ;)
Vlad, Спасибо большое! Теперь все намного проще :-) Как с сессией разделаюсь то по вашим статьям думаю без проблем выдеру из кода эту информацию, хоть и не пробовал еще ни разу :-)
Не за что :) Главное держите на такой случай всегда под рукой какой-нибудь инструмент для просмотра HTTP-заголовков. Думаю, что статья про каптчи должна пригодиться — там как раз работа со скриптами рассматривалась
Так-то всё бы оно ничего, только вот нет самого главного: поиск по DOM-дереву. Если мне нужно добраться до отдельных тегов без классов и id в разных местах кода, то вот тут и начинается настоящий геморрой.
Извените за тупой вопрос IHTMLDocument2 что это такое как подключить ?
У меня делфи7 подскажите, пожалуйста, Doc.Write(PSafeArray(TVarData(v).VArray)); у меня выдает UndeclaredIdentifier PSafeArray. Хотя и в подсказке все верно, но упорно пишет неопределен. :(
Все спс не надо, забыл просто в uses добавить Activex ))
[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(‘какойтоЮрл’,?); выдает ошибку соккет еррор. Что с этим делать ? я прально передаю параметры ?
Что-то пока до компа добрался, а уже и вопросов не осталось :) Рад, что сами разобрались. Компонент Indy idHTTP на форме лежит? В параметрах GetDom его передаете?
ЕДИНСТВЕННЫЙ НОРМАЛЬНЫЙ БЛОГ
2. Получение всех ссылок на странице
Links.Add(Doc.links.item(i));
[Error] Not enough actual parameters
Здравствуйте. Я не очень опытный программист, но мне нужно вытащить DOM с сайта. Можно вас попросить выложить элементарный код как это сделать. Адрес вводится через Edit, DOM выводится в поле MEMO. Или хотя бы объясните подробнее код представленный в самом начале. Очень нужно.
Так не проще тогда взять Indy и скачать сразу исходник страницы, чтоб TWebBrowser по форме не возить? Компонент idHTTP вроде бы там был. Делаете запрос GET и выгружаете исходник к себе в Memo
мне без разницы куда выводить, главное получить DOM в виде текста. мне получается нужно создать переменную, потом переменной придуть значение
IdHTTP.Get(url); и дальше просто в блокнот скинуть значение переменной?
ну да. Я Indy не пользую, но по-моему есть перегруженные метод GET где можно после урла вторым параметром воткнуть TStrings куда сохранять текст
я не могу понять что такое IHTMLDocument2, где это взять? где смотреть?
uses MSHTML;
У меня всё получилось но при запуске вылетает табличка — типа
«во время выполнения произошла ошибка, запустить отладку?
Строка1. Синтаксическая ошибка»
Как исправить.
Программа работает но это окошко задолбало.
Doc.Write(PSafeArray(TVarData(v).VArray)); — убираю и ошибки нет, но и толку от проги нет тоже.
Первую проблему решил. Теперь вторая
Links.Add(Doc.links.item(i)); — пишет not enough actual parameter
Решил проблему так
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;
Правильно ли?
Ну, если работает правильно — значит правильно.
IdHTTP.Get(url); и дальше просто в блокнот скинуть значение переменной?
var list:Tstringlist;
begin
list:=Tstringlist.Create;
list:=IdHTTP.Get(url);
list.SaveToFile(‘имя_файла’);
list.Destroy;
end;
поправка
list.text:=IdHTTP.Get(url);
[…] delphi html getAttribute […]
[…] статье «Что можно «вытащить» из DOMа» мы немного касались таких свойств объекта Document как […]
Влад, приветствую, повторял твой пример, но споткнулся на пункте 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 — как с этим работать? )) Я просто с интерфейсами… Подробнее »
В общем, разобрался, но все равно спасибо за внимание.
ребята подскажите, столкнулся с проблемой..пробую парсить страницы своего сайта, все здорово получается до тех пор, пока в коде странице прога не нарывается на элементы HTML 5 и сразу же информирует об этом и если взять для примера details то исходный текст через инди показывается норм…как побороть эту беду с обходом для игнорирования скриптов и дальше так сказать по тексту бежать далее..такой параметр как silent — true из веббраузера не работает, да и не интересует веббраузер, только парсинг через документ..знающие откликнитесь и укажите путь побороть отключения скриптов в доке, всем спс за внимание