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

суббота, 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.

понедельник, 25 августа 2008 г.

Создание собственного редактора для проверки составляемых регулярных выражений

Как я уже писала, после составления регулярных выражений "по теории", их необходимо проверить с использованием того инструмента, которым они потом будут использоваться. Мы работаем с объектом RegExp в Delphi (надеюсь, все уже познакомились с библиотекой хотя бы просто прочитав статью, ссылку на которую я привела в предыдущем посте). Перейдем от теории к практике. Создадим простенький инструмент, позволяющий искать выражения, удовлетворяющие паттерну. На форме будет memo для исходного текста, memo для вывода результатов, edit для ввода регулярного выражения и кнопка "Find".


В этом простеньком проекте необходим только код для обработки нажатия кнопки Find. Он будет следующим:

procedure TForm1.Button2Click(Sender: TObject);
var
R: TRegExp;
mc: MatchCollection;
m: Match;
sm: SubMatches;
i, j: Integer;
begin
memOutput.Clear;
R := TRegExp.Create(Self);
try
R.Pattern := edtRegExpFind.Text;
R.IgnoreCase := cbIGNCASE.Checked;
R.Global := cbGLOBAL.Checked;
R.Multiline:=CBMULTILINE.Checked;
mc := R.Execute(memInput.Lines.Text) as MatchCollection;
if mc.Count > 0 then begin
for i := 0 to mc.Count - 1 do begin
m := mc[i] as Match;
memOutput.lines.Add(intToStr(i)+'.');
MemOutput.Lines.Add(Format('Match[%d] = "%s"', [i, m.Value]));
sm := m.SubMatches as SubMatches;
for j := 0 to sm.Count - 1 do
memOutput.Lines.Add(Format(' SubMatch[%d] = "%s"', [j, VarToStr(sm[j])]));
end;
end;
finally
m := nil;
sm := nil;
mc := nil;
R.Free;
end;
end;


cbIGNCASE, cbGLOBAL, CBMULTILINE — чекбоксы соответственно определяющие свойства IgnoreCase, Global и Multiline для регулярного выражения.

Думаю, что выкладывать исходник — нет смысла. Кому что непонятно — спрашивайте в комментариях.

пятница, 22 августа 2008 г.

Работа с регулярными выражениями в Delphi

Самый простой способ работы с регулярными выражениями — это работа с использованием библиотеки Microsoft VBScript Regular Expressions 5.5.


Библиотеку надо добавить в проект, создать модуль, подключить в uses:
VBScript_RegExp_55_TLB

С этого момента становятся доступными объекты RegExp, MatchCollection, Match, SubMatches. Используя их, вы можете искать группы соответствий, заданных в паттерне поиска. Не знаю, надо ли здесь помещать описание свойств и методов объектов. Если вы впервые сталкиваетесь с ними, то почитайте подробное описание в статье "Использование VBScript RegExp в Delphi" на delphikingdom.com. После знакомства с компонентами пойдем дальше.

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

Регулярные выражения или Без чего не начать

Для того, чтобы парсить, как рыба в воде (плавает), надо на "отлично" уметь владеть главным инструментом парсера — регулярными выражениями.

Когда-то с сайта (который сейчас не открывается) скачивала шпаргалку по регулярным выражениям. Кто в свое время не скачал — выкладываю, берите:

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

Для проверки регулярных выражений, написанных для использования на php или perl, существуют online-сервисы. Так что можете проверить свои выражения там.

Например, сервис RegexPal.com.

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

Парсинг. А.

Начнем с самого простого и главного — с определения.

Обратимся к Wiki.

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

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

Меня больше интересует практическое применение парсинга. А именно — автоматический анализ данных, получаемых через Интернет. В настоящее время создано очень много продуктов, реализующих парсинг. В основном продукты заточены под узкую задачу. Например — парсинг выдачи поисковиков. По своему опыту знаю, что сложно найти какой-либо продукт, удовлетворяющий всем твоим запросам. Поэтому, целью — моей и, надеюсь, читателей, — будет научиться писать парсеры самостоятельно.

Скорее всего, большая часть материала будет посвящена созданию десктопных парсеров (с использованием среды разработки Borland Delphi и стандартного набора компонент; там, где набор будет отличаться от стандартного, я скажу), т.к. программирование приложений под винду мне гораздо ближе, нежели под инет. Но так как в последнее время стало появляться достаточно много серверных парсеров, то некоторое внимание планируется уделить и серверным технологиям.

Поделиться