Статьи Королевства Дельфи


Использование функциональности IE или заметки о WebBrowser - часть 9


Простой парсинг

А теперь пожалуй пришло время очень сильно подружится с интерфейсами, ибо вся работа с основными вкусностями WebBrowser возможна только через них. Декларации основных интерфейсов Вы найдете в модулях mshtml и SHDocVw.
Перед тем, как организовать взаимодействие с составляющими документа, естественно что нужно этот документ разобрать на составляющие, то есть провести парсинг. Это довольно просто можно сделать при помощи интерфейса IHtmlDocument2, который предоставляет средства по доступу к документу, который загружен в соответствующий броузер. Сам же IHtmlDocument2 можно получить, имея "в руках" интерфейс IWebBrowser2 на броузер, в котором этот документ содержится.

Как уже отмечалось, для документа самого верхнего уровня это сделать довольно просто:

var doc:IHtmlDocument2; ..... if assigned(WebBrowser1.ControlInterface.Document) then WebBrowser1.ControlInterface.Document.QueryInterface(IHtmlDocument2,doc); Хотел бы обратить Ваше внимание на условие "if" - это связано с тем, что если броузер еще не делал навигации, то свойство Document не будет проинициализировано. Также я надеюсь, Вы помните, почему используется конструкция WebBrowser1.ControlInterface.Document а не WebBrowser1.Document

А как же получить доступ к вложенным фреймам?

Это можно сделать как минимум двумя способами Первый: Использовать OnDocumentComplete для получения интерфейса к броузеру каждого фрейма, примерно так, как приводилось выше в примере Второй: Использовать свойства самого IHtmlDocument2 для получения доступа к фреймам. Понятно, что нужно иметь доступ к IHtmlDocument2 самого верхнего уровня. Пример реализации этого подхода:

type TDoerOneDoc = procedure (iDoc:IHtmlDocument2); procedure DoWithFrames(iDoc:IHtmlDocument2; aDoer:TDoerOneDoc); { процедура aDoer будет вызвана для каждого IHtmlDocument2, начиная с главного и для каждого IHtmlDocument2 с любого уровня вложенности фреймов} var frames:IHTMLFramesCollection2; i:integer; ov1:OleVariant; iDisp:IDispatch; IWindow2:IHTMLWindow2; begin if not assigned(aDoer) then Exit; aDoer(iDoc); frames:=iDoc.frames; if not assigned(frames) then exit; if frames.length=0 then exit; for i:=1 to frames.length do begin ov1:=i-1; try iDisp:=frames.item(ov1); iDisp.QueryInterface(IHTMLWindow2,IWindow2); if assigned(IWindow2) then DoWithFrames(IWindow2.document,aDoer); except { ShowMessage('Find error !!!');} end; end; end; Итак, имея в руках IHtmlDocument2 можно приступить и к парсингу ...
Наиболее простой способ для этого - использование метода All интерфейса IHtmlDocument2, который позволяет получить список или всех тегов или только тегов определенного вида. Посмотрим пример для получения списка всех тегов:

procedure TFormSimpleWB.WebBrowser1DocumentComplete(Sender: TObject; const pDisp: IDispatch; var URL: OleVariant); var i : integer; iDoc : IHtmlDocument2; iDisp : IDispatch; iElement : IHTMLElement; iInputElement : IHTMLInputElement; S : string; begin Memo1.Clear; iDoc:=(pDisp as IWebBrowser).Document as IHtmlDocument2; for i:=1 to iDoc.All.Get_length do begin iDisp:=iDoc.Get_all.item(pred(i),0); iDisp.QueryInterface(IHTMLElement, iElement); Str(pred(i),S); S:= S+''; if assigned(iElement) then begin S:=S+'tag='+iElement.Get_tagName+' '; iElement.QueryInterface(IHtmlInputElement,iInputElement); if assigned(iInputElement) then begin S:=S+'name='+iInputElement.Get_name; end; Memo1.Lines.Add(S); end; end; end; Как Вы догадались, здесь тип каждого тега заносится в компонент TMemo. Также делается попытка определить, есть ли очередной тег элементом ввода (поддерживает ли он соответствующий интерфейс), и если это так, то делается попытка получить значение специфического для элементов ввода свойства.

Далее посмотрим пример получения списка тегов определенного типа:

procedure TFormSimpleWB.btPutDataClick(Sender: TObject); var iDoc:IHtmlDocument2; i:integer; ov:OleVariant; iDisp: IDispatch; iColl:IHTMLElementCollection; iInputElement:IHTMLInputElement; begin // WebBrowser1.ControlInterface.Document.QueryInterface(IHtmlDocument2,iDoc); if not assigned(iDoc) then begin ShowMessage(' !!!??? Nothing dowloaded ... '); Exit; end; ov:='INPUT'; IDisp:=iDoc.all.tags(ov); if assigned(IDisp) then begin IDisp.QueryInterface(IHTMLElementCollection,iColl); if assigned(iColl) then begin for i:=1 to iColl.Get_length do begin iDisp:=iColl.item(pred(i),0); iDisp.QueryInterface(IHTMLInputElement,iInputElement); if assigned(iInputElement) then begin if iInputElement.Get_name='mn' then iInputElement.Set_value('Ihor'); if iInputElement.Get_name='pw' then iInputElement.Set_value('PASSWORD'); end; end; end; end; end;

В этом примере получаем список тегов типа "INPUT", а потом для некоторых тегов (которые отбираем по имени) делается попытка сделать "ввод данных". Полностью этих два примера (как проект) можно взять (4k).

Ну, для начала пожалуй и хватит. Если у Вас есть вопросы к является рь Осов'як





Начало  Назад  Вперед



Книжный магазин