Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.14.250.196] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Написала программу для открытия страниц браузера. В боковой панели сделала вывод информации о dom-элементах. Чтобы открыть ссылку нужно по ней щелкнуть. Если навести мышкой и посмотреть в панели то атрибут id равняется test. Gif пример работы программы ниже.
Подскажите можно как-нибудь по id найти в документе html и заставить нажать по ссылке автоматически. В своей программе я подключаю дополнительные файлы. Цитата WBFuncs – для процедуры WB_Navigate. MSHTML – для интерфейса IHTMLElement. Для работы использую компонент WebBrowser. Код полностью (исходники: Прикреплённый файлExampleSource.zip (70,61 Кбайт, скачиваний: 13) ) unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, OleCtrls, SHDocVw, ComCtrls, ExtCtrls, WBFuncs; type TForm1 = class(TForm) WebBrowser1: TWebBrowser; Button1: TButton; PageControl: TPageControl; Panel1: TPanel; TabSheet1: TTabSheet; TabSheet2: TTabSheet; PageControl1: TPageControl; TabSheet3: TTabSheet; TabSheet4: TTabSheet; TabSheet5: TTabSheet; GroupBox1: TGroupBox; edSearchAndHighlight: TEdit; Button2: TButton; PnlElementInfo1: TPanel; PnlHandle: TPanel; edElementTag: TEdit; Label1: TLabel; Panel3: TPanel; edElementId: TEdit; Label2: TLabel; Panel4: TPanel; edElementinnerHTML: TEdit; Label3: TLabel; Timer1: TTimer; Panel5: TPanel; edElementclassName: TEdit; Label4: TLabel; Panel6: TPanel; edElementinnerText: TEdit; Label5: TLabel; Panel7: TPanel; edElementhref: TEdit; Label6: TLabel; procedure Button1Click(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } FPrevBrowser: TWebbrowser; public { Public declarations } function GetCurrentWB: TWebbrowser; end; var Form1: TForm1; implementation uses MSHTML; {$R *.dfm} function TForm1.GetCurrentWB: TWebbrowser; begin Result := nil; with PageControl do if ActivePage.ControlCount > 0 then begin if ActivePage.Controls[0] is TWebbrowser then begin Result := (TWebbrowser(ActivePage.Controls[0])); end else Result := FPrevBrowser; end; end; procedure TForm1.Button1Click(Sender: TObject); begin WB_Navigate(GetCurrentWB, 'http://mysite1.su'); WB_SetFocus(GetCurrentWB); end; procedure TForm1.Timer1Timer(Sender: TObject); var MausPos: TPoint; Element: IHTMLElement; imgElement: IHTMLIMGElement; scrElement: IHTMLLinkElement; x, y: Integer; Doc: IHTMLDocument2; CurrentWB: TWebbrowser; begin CurrentWB := GetCurrentWB; if Assigned(CurrentWB) then begin Doc := CurrentWB.Document as IHTMLDocument2; if Assigned(doc) then begin GetCursorPos(MausPos); mauspos := CurrentWB.ScreenToClient(mauspos); x := MausPos.x; y := MausPos.y; Element := GetElementAtPos(doc, x, y); if Assigned(Element) then begin edElementTag.Text := Element.tagName; edElementId.Text := Element.id; edElementinnerHTML.Text := Element.innerHTML; edElementclassName.Text := Element.className; edElementinnerText.Text := Element.innerText; Element.QueryInterface(IHTMLIMGElement, imgElement); if assigned(imgElement) then edElementhref.Text := imgElement.href; Element.QueryInterface(IHTMLLinkElement, scrElement); if assigned(scrElement) then edElementhref.Text := scrElement.href; end; end; end; end; end. Исходники приложила. Там сама программа и сайт который я использую для тестирования. |
Сообщ.
#2
,
|
|
|
Вам это нужно?
const constInvalidHTML = 'Invalid HTML document'; constInvalidHTMLStructure = constInvalidHTML + ' structure'; // aDocument = WebBrowser.Document, ID = строка ID, iNum = номер вхождения элемента в документ с таким ID (начинаются с 1) function GetElementById(const aDocument: IDispatch; const ID: String; iNum: LongInt): IDispatch; var Doc: IHTMLDocument2; Body: IHTMLElement2; Tags: IHTMLElementCollection; Tag: IHTMLElement; i, c, Count: LongInt; begin Result := nil; if iNum < 1 then Exit; if Supports(aDocument, IHTMLDocument2, Doc) then begin if Supports(Doc.body, IHTMLElement2, Body) then begin Tags := Body.getElementsByTagName('*'); Count := Tags.length; c := 0; for i := 0 to Count - 1 do begin Tag := Tags.item(i, EmptyParam) as IHTMLElement; if AnsiSameText(Tag.id, ID) then inc(c); if c = iNum then begin Result := Tag; break; end; end; end else raise Exception.Create(constInvalidHTMLStructure + '!'); end else raise Exception.Create(constInvalidHTML + '!'); end; procedure TForm1.Button3Click(Sender: TObject); var Elem: IHTMLElement; begin try Elem := GetElementById(WebBrowser1.Document, 'myid', 1) as IHTMLElement; if Assigned(Elem) then begin // Делаем с элементом что хотим end; except // Ошибки поиска элементов end; end; |
Сообщ.
#3
,
|
|
|
А вот здесь, что указываем. Вместо звездочки.
Tags := Body.getElementsByTagName('*'); |
Сообщ.
#4
,
|
|
|
Цитата Katerina1993 @ А вот здесь, что указываем. Вместо звездочки. Ничего. Используйте как есть. '*' получает все тэги из body в document. Или можете передать её через параметры и тогда можно будет искать не просто по id но еще и конкретный тэг (например, только ссылки, указав там 'a' или только блочные тэги, указав 'div'). |
Сообщ.
#5
,
|
|
|
Просто у меня появляется ошибка, когда я открываю веб-страницу и при нажатии кнопки, где активируется элемент в dom. Пример:
Цитата Access violation at adress 43CFCDAA in module 'mshtml.dll' Вот скриншот ошибки. Прикреплённый файлScreenshot_1.jpg (112,74 Кбайт, скачиваний: 30) Когда я нажимаю OK выделяется эта строка, я решила что с ней что-то не так и нужно в скобках изменить параметр. Прикреплённый файлScreenshot_2.jpg (99,61 Кбайт, скачиваний: 31) |
Сообщ.
#6
,
|
|
|
Вот так всегда, когда набираешь код в браузере по памяти и не проверяешь.
const constInvalidHTML = 'Invalid HTML document'; constInvalidHTMLStructure = constInvalidHTML + ' structure'; // aDocument = WebBrowser.Document, ID = строка ID, iNum = номер вхождения элемента в документ с таким ID (начинаются с 1) function GetElementById(const aDocument: IDispatch; const ID: String; iNum: LongInt = 1; const tagName: WideString = '*'): IDispatch; var Doc: IHTMLDocument2; Body: IHTMLElement2; Tags: IHTMLElementCollection; Tag: IHTMLElement; i, c, Count: LongInt; begin Result := nil; if iNum < 1 then Exit; if Supports(aDocument, IHTMLDocument2, Doc) then begin if Supports(Doc.body, IHTMLElement2, Body) then begin Tags := Body.getElementsByTagName(tagName); Count := Tags.length; c := 0; for i := 0 to Count - 1 do begin Tag := Tags.item(i, EmptyParam) as IHTMLElement; if AnsiSameText(Tag.id, ID) then inc(c); if c = iNum then begin Result := Tag; break; end; end; end else raise Exception.Create(constInvalidHTMLStructure + '!'); end else raise Exception.Create(constInvalidHTML + '!'); end; procedure TForm1.Button3Click(Sender: TObject); var Elem: IHTMLElement; begin try Elem := GetElementById(WebBrowser1.Document, 'element_id', 1, 'a') as IHTMLElement; // Поиск только среди ссылок if Assigned(Elem) then begin // Делаем с элементом что хотим end; except // Ошибки поиска элементов end; end; |
Сообщ.
#7
,
|
|
|
Вот в этой строке:
Elem := GetElementById(WebBrowser1.Document, 'element_id', 1, 'a') as IHTMLElement; Вместо element_id нужно использовать значения атрибута ссылки? У меня например test. |
Сообщ.
#8
,
|
|
|
Да. У вас в примере туда надо передать 'test'. Можно так же модифицировать код для поиска элементов без атрибута id.
const constInvalidHTML = 'Invalid HTML document'; constInvalidHTMLStructure = constInvalidHTML + ' structure'; // aDocument = WebBrowser.Document, ID = строка ID, iNum = номер вхождения элемента в документ с таким ID (начинаются с 1) function GetElementByIndexIdAndTagName(const aDocument: IDispatch; iNum: LongInt = 1; const sID: String = '*'; const sTagName: WideString = '*'): IDispatch; function AnyID(const s1: String; const s2: String): Boolean; begin Result := True; end; var Doc: IHTMLDocument2; Body: IHTMLElement2; Tags: IHTMLElementCollection; Tag: IHTMLElement; i, c, Count: LongInt; comp: function (const s1: String; const s2: String): Boolean; begin Result := nil; if iNum < 1 then Exit; if (sID <> '*') and (sID <> '') then comp := @AnsiSameText else comp := @AnyID; if Supports(aDocument, IHTMLDocument2, Doc) then begin if Supports(Doc.body, IHTMLElement2, Body) then begin Tags := Body.getElementsByTagName(sTagName); Count := Tags.length; c := 0; for i := 0 to Count - 1 do begin Tag := Tags.item(i, EmptyParam) as IHTMLElement; if comp(Tag.id, sID) then inc(c); if c = iNum then begin Result := Tag; break; end; end; end else raise Exception.Create(constInvalidHTMLStructure + '!'); end else raise Exception.Create(constInvalidHTML + '!'); end; procedure TForm1.Button3Click(Sender: TObject); var Elem: IHTMLElement; begin try Elem := GetElementByIndexIdAndTagName(WebBrowser1.Document, 1, 'test', 'a') as IHTMLElement; // Поиск первой только среди ссылок с id="test" (по тэгу и id) if Assigned(Elem) then begin // Делаем с элементом что хотим end; except // Ошибки поиска элементов end; try Elem := GetElementByIndexIdAndTagName(WebBrowser1.Document, 10) as IHTMLElement; // Поиск по индексу десятого элемента в документе (только по индексу) if Assigned(Elem) then begin // Делаем с элементом что хотим end; except // Ошибки поиска элементов end; try Elem := GetElementByIndexIdAndTagName(WebBrowser1.Document, 2, 'myid') as IHTMLElement; // Поиск второго элемента с id="myid" (по индексу и id) if Assigned(Elem) then begin // Делаем с элементом что хотим end; except // Ошибки поиска элементов end; try Elem := GetElementByIndexIdAndTagName(WebBrowser1.Document, 3, '', 'div') as IHTMLElement; // Поиск третьего блочного элемента (<div>...</div>) (по индексу и тэге) if Assigned(Elem) then begin // Делаем с элементом что хотим end; except // Ошибки поиска элементов end; end; |
Сообщ.
#9
,
|
|
|
Комментарий в условие
Цитата // Делаем с элементом что хотим Все таки, что нужно сделать, чтобы был переход по ссылке и открылась форма? |
Сообщ.
#10
,
|
|
|
Например
procedure TForm1.Button3Click(Sender: TObject); var Elem: IHTMLElement; begin try Elem := GetElementByIndexIdAndTagName(WebBrowser1.Document, 1, 'test', 'a') as IHTMLElement; // Поиск первой только среди ссылок с id="test" (по тэгу и id) if Assigned(Elem) then begin // Делаем с элементом что хотим Elem.click; // Кликнуть по ссылке (выполнить OnClick или переход по href) end; except // Ошибки поиска элементов end; end; |
Сообщ.
#11
,
|
|
|
macomics, в 8 посту несколько примеров, как искать по блоку, id и по индексу, а как по классу.
Сделала заполнение полей. procedure TForm1.Button4Click(Sender: TObject); var Elem: IHTMLElement; begin try Elem := GetElementById(WebBrowser1.Document, 'title', 1, 'input') as IHTMLElement; // Поиск только среди ссылок if Assigned(Elem) then begin Elem.innerText:='Название'; end; Elem := GetElementById(WebBrowser1.Document, 'message', 1, 'textarea') as IHTMLElement; // Поиск только среди ссылок if Assigned(Elem) then begin Elem.innerHTML:='Тестовое описание' end; except end; end; А вот в кнопке у меня только класс прописан, пример на картинке. Прикреплённый файлimg1.jpg (34,51 Кбайт, скачиваний: 30) Еще интерсно как можно на одну кнопку button4 повесить и заполнение полей и отправку? |
Сообщ.
#12
,
|
|
|
Цитата Katerina1993 @ Еще интерсно как можно на одну кнопку button4 повесить и заполнение полей и отправку? Смотря какую кнопку вы имеете ввиду. Если кнопку на странице, тогда просто измените её тип с submit на button и добавьте обработчик onClick. На JavaScript в обработчике нажатия добавляете заполнение полей формы, а в конце вызываете submit для формы function clickOnButton(e) { const f = e.target.form; // Получаем форму, на которой находится кнопка e.preventDefault(); // Прерываем цепочку передачи сообщений к нижерасположенным элементам f.title.value = "Hello world"; // Заполняем поля формы (заголовок) f.textbox.innerText = "Autofilled by click!"; // и текстовое поле тоже (не забудьте у textarea добавить name="textbox") f.submit(); // Отправка формы } const formButton = document.querySelector(".submitButton"); if (formButton) { formButton.addEventListener("click", clickOnButton); } Если надо заполнить поля формы перед отправкой при нажатии на кнопке Delphi, тогда придется найти каждое поле формы отдельно и установить его соответствующие атрибуты. Если вы хотите, чтобы я вам заполнил поля на форме Delphi для найденного элемента, тогда это будет так (не забудьте выключить таймер) procedure TForm1.Button3Click(Sender: TObject); var Elem: IHTMLElement; begin try Elem := GetElementByIndexIdAndTagName(WebBrowser1.Document, 1, 'test', 'a') as IHTMLElement; // Поиск первой только среди ссылок с id="test" (по тэгу и id) if Assigned(Elem) then begin // Делаем с элементом что хотим edElementTag.Text := WideCharToString(@Elem.tagName[1]); edElementId.Text := WideCharToString(@Elem.id[1]); edElementinnerHTML.Text := WideCharToString(@Elem.innerHTML[1]); edElementclassName.Text := WideCharToString(@Elem.className[1]); edElementinnerText.Text := WideCharToString(@Elem.innerText[1]); Elem.click; // Кликнуть по ссылке (выполнить OnClick или переход по href) end; except // Ошибки поиска элементов end; end; const constInvalidHTML = 'Invalid HTML document'; constInvalidHTMLStructure = constInvalidHTML + ' structure'; // aDocument = WebBrowser.Document, iNum = номер вхождения элемента в документ с таким ID (начинаются с 1), sClassName = строка ID, sTagName = имя тэга у элемента function GetElementByIndexClassNameAndTagName(const aDocument: IDispatch; iNum: LongInt = 1; const sClassName: String = '*'; const sTagName: WideString = '*'): IDispatch; function AnyID(const s1: String; const s2: String): Boolean; begin Result := True; end; var Doc: IHTMLDocument2; Body: IHTMLElement2; Tags: IHTMLElementCollection; Tag: IHTMLElement; i, c, Count: LongInt; comp: function (const s1: String; const s2: String): Boolean; begin Result := nil; if iNum < 1 then Exit; if (sClassName <> '*') and (sClassName <> '') then comp := @AnsiSameText else comp := @AnyID; if Supports(aDocument, IHTMLDocument2, Doc) then begin if Supports(Doc.body, IHTMLElement2, Body) then begin Tags := Body.getElementsByTagName(sTagName); Count := Tags.length; c := 0; for i := 0 to Count - 1 do begin Tag := Tags.item(i, EmptyParam) as IHTMLElement; if comp(Tag.className, sClassName) then inc(c); if c = iNum then begin Result := Tag; break; end; end; end else raise Exception.Create(constInvalidHTMLStructure + '!'); end else raise Exception.Create(constInvalidHTML + '!'); end; Добавлено И еще Цитата Katerina1993 @ Сделала заполнение полей. procedure TForm1.Button4Click(Sender: TObject); var Elem: IHTMLElement; begin try Elem := GetElementById(WebBrowser1.Document, 'title', 1, 'input') as IHTMLElement; // Поиск только среди ссылок if Assigned(Elem) then begin Elem.innerText:='Название'; end; Elem := GetElementById(WebBrowser1.Document, 'message', 1, 'textarea') as IHTMLElement; // Поиск только среди ссылок if Assigned(Elem) then begin Elem.innerHTML:='Тестовое описание' end; except end; end; А вот в кнопке у меня только класс прописан, пример на картинке. Текст для input задается не как innerText или innerHTML, а в поле value! Elem.value := 'Отправить сообщение'; |
Сообщ.
#13
,
|
|
|
Цитата Текст для input задается не как innerText или innerHTML, а в поле value! У меня почему-то выдает сообщение об ошибке. Прикреплённый файлErr1.png (23,56 Кбайт, скачиваний: 36) |
Сообщ.
#14
,
|
|
|
Значит оно доступно не напрямую, а через getAttribute/setAttribute
Text := Elem.getAttribute('value', 0); Caption := WideCharToString(@Text[1]); Elem.setAttribute('value', 'Send text!', 0); |
Сообщ.
#15
,
|
|
|
Работает, только первые две строчки не пойму для чего getAttribute и WideCharToString? Мне удалось запусить только через Elem.setAttribute.
|