Поиск по блогу

суббота, 30 августа 2008 г.

Объектная модель браузера (DOM в веб-браузерах)

Немного об объектной модели браузера. Почему немного? Потому что этот блог посвящен все-таки созданию парсеров, а не изучению отдельных вопросов программирования.

В Википедии:
DOM (от англ. Document Object Model — «объектная модель документа») — это не зависящий от платформы и языка программный интерфейс, позволяющий программам и скриптам получить доступ к содержимому документов, а также изменять содержимое, структуру и оформление документов.

Суть объектной модели браузера в том, что мы через простой интерфейс можем получить доступ к любым элементам страницы. Например, к любой ссылке (или ко всему массиву ссылок), к любой форме, к любому элементу ввода, к любой кнопке и так далее. К объектам и их свойствам и методам, естественно. Нас больше всего будут интересовать объекты, связанные с тегами HTML. Они соответствуют тегам, которые формируют текущий документ, и включают такие элементы как гиперсвязи и формы.

К объектам можно обращаться по id, по номеру в массиве (например, если надо перебрать все элементы одинакового типа).

Я бы посоветовала взять в руки какой-нибудь толстенный спровочник по JavaScript, например. И просмотреть раздел, посвященный объектной модели браузера. В свое время я так и делала. Необязательно знать и помнить все объекты, свойства и методы — важно оценить возможности и прикинуть, для чего все это может пригодиться. Тем, кто уже изучал JavaScript, будет немного легче.

Так, сейчас немного о том, как работать с объектной моделью в Delphi, используя рассмотренный в предыдущем посте компонент TWebBrowser.

Существует интерфейс IHTMLDocument2, который позволяет с легкостью это делать. А можно напрямую через OleObject. Например, если в html-документе, заруженном в WebBrowser, есть, допустим, инпут с id='message', то код:
WebBrowser.OleObject.document.getElementById('message').Value := 'Привет!';
запишет в этот инпут строку "Привет!".

А код:
  ovElements := WebBrowser1.OleObject.Document.Forms.Item(0).Elements;
for i := 0 to (ovElements.Length-1) do
if (AnsiUpperCase(ovElements.Item(i).tagName) = 'INPUT') then
if (AnsiUpperCase(ovElements.Item(i).type) = 'SUBMIT') or
(AnsiUpperCase(ovElements.Item(i).type) = 'BUTTON') then
if (ovElements.item(i).Value = 'Send') then
ovElements.Item(i).Click;
переберет все элементы первой по счету формы страницы, найдет в ней кнопку, на которой будет написано "Send" и сымитирует ее нажатие.

Как видите, объектная модель — очень полезная и удобная штука. Хотя основное ее применение — не парсинг, а автоматизация регистраций, заполнения форм и так далее. Чтобы показать, насколько она может быть полезна, в следующих постах приведу пример разработки и создания небольшой утилиты для автоматизации добавления вашей RSS-ленты в RSS-агрегаторы.

четверг, 28 августа 2008 г.

Получение содержимого web-страниц в Delphi. Вариант первый, самый простой

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

Сегодня опишу самый простой способ получить содержимое web-страницы. Для этого будем использовать стандартный Active-X компонент TWebBrowser. Этот же компонент использует Windows в своем IE. В некоторых случаях это даже удобно, так как созданный на основе этого компонента объект будет "видеть" все ваши IE-кукисы и прочие настройки (если, конечно, вы пользуетесь IE).

Итак, создадим форму, на нее поместим TEdit (подобие адресной строки), кнопку и компонент TWebBrowser (вкладка Internet).


В обработчике нажатия кнопки пишем:
WebBrowser1.Navigate(Edit1.Text);

Вот и все!

Simple Browser
Этот компонент удобен в случаях, когда HTML-код страницы нельзя получить другим простым способом (например, некоторые сайты отказываются работать, когда браузер не поддерживает flash, поэтому получить код страницы в обход применения этого компонента — возможности нет). Также TWebBrowser удобен для автоматизации работы с формами на сайтах.

Иногда требуется, чтобы страница полностью отобразилась в контейнере, прежде чем продолжится работа с ней. В этом случае я обычно в проекте создаю глобальную переменную, на событие OnDocumentComplete вешаю обработчик:
procedure TFMain.WebBrowser1DocumentComplete(Sender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
begin
DocLoaded := true;
end;

А в теле основного модуля работа продолжается только тогда, когда эта глобальная переменная станет равна true:
procedure TFMain.PostMessageOnBoard(Mess: string);
var
Doc : IHTMLDocument2;
S : string;
begin
DocLoaded := false;
WebBrowser1.Navigate(Edit1.Text);
while DocLoaded = false do
Application.ProcessMessages;

Doc := WebBrowser1.Document as IHTMLDocument2;
WebBrowser1.OleObject.document.getElementById('shform').ClassName := '';

S := Doc.body.innerHTML;

//...
end;

Кстати, в приведенном выше отрезке кода содержится пример использования объектной модели браузера. (Что это — я расскажу позже.) А в переменной S в результате окажется весь HTML-код страницы.

В ближайших постах я планирую рассказать:
  • Что такое объектная модель браузера и с чем ее едят?
  • Как еще можно получить содержимое страницы?
  • Написание простенького парсера (Пример №1 - Парсинг ключевых слов).
Так что подписывайтесь на RSS :)

среда, 27 августа 2008 г.

Парсинг XML на Delphi

Начнем с самого простого — с синтаксического анализа документа формата XML. Этот документ имеет четкую структуру и как нельзя лучше подходит для начала изучения парсинга. Еще один приятный момент — для парсинга XML нам пока даже не пригодится умение составлять регулярные выражения (это не значит, что их не надо знать :) ).

XML — формат для хранения структурированных данных. Если вы лишь краем уха слышали про этот формат, но близко не сталкивались, прочитайте скучную, но полезную статью об XML на Wiki.

Итак, прочитали? Проверим, понимаем ли мы друг друга. Вот скрин ссылки http://newyorg.myminicity.com/xml, как ее видит Firefox (вставляю рисунком, так как блоггер что-то не очень любит подобного рода код).


City — корневой элемент. Элементы: host, name, region, ranking и т.д.. Атрибуты: code (у элемента region, значение атрибута — "RU"), com, env, ind, sec, tra (атрибуты элемента bases, каждый атрибут имеет числовое значение). Обратите внимание, что bases — пустой элемент. Сходится с теорией?

Рассмотрим стандартный компонент Delphi, позволяющий работать с XML. Это TXMLDocument с вкладки Internet, с которой нам в будущем придется еще поработать.



Компонент можно положить на форму, а можно создавать динамически по мере надобности.

Итак, создаем форму, помещаем на нее компонент и 5 компонентов TEdit. В первый мы запишем содержимое элемента population, в 4 остальных — значения атрибутов ind, tra, sec, env. Все это делается чрезвычайно просто. В обработчике нажатия кнопки, например, пишем:


XMLDocument1.LoadFromFile('http://newyorg.myminicity.com/xml');
XMLDocument1.Active := true;
Edit1.Text := XMLDocument1.DocumentElement.ChildNodes['population'].Text;
Edit2.Text := VarToStr(XMLDocument1.DocumentElement.ChildNodes['bases'].Attributes['ind']);
Edit3.Text := VarToStr(XMLDocument1.DocumentElement.ChildNodes['bases'].Attributes['tra']);
Edit4.Text := VarToStr(XMLDocument1.DocumentElement.ChildNodes['bases'].Attributes['sec']);
Edit5.Text := VarToStr(XMLDocument1.DocumentElement.ChildNodes['bases'].Attributes['env']);
XMLDocument1.Active := false;

Подведем итоги.

Чтение атрибута узла можно произвести так:
Root.GetAttribute(WideString('NodeName'));
(где Root — элемент)

Так работать можно, естественно, не только с корневым элементом, но и с его дочерними узлами:
Root.ChildNodes.Nodes[i].GetAttribute(WideString('NodeName'));

Запись атрибута:
Root.SetAttribute(WideString('NodeName'),'NodeValue');

Количество дочерних узлов определяем:
Root.ChildNodes.Count;

Вот и все. Мы получили все, что хотели, плюс начальные навыки работы с компонентом TXMLDocument.

Поделиться