2014-11-05 59 views
0

尝试使用WebBrowser组件自动导航通过代码它不起作用。导航包括登录页面以及之后的一些其他页面。首页按钮登录正常工作。在第二页上,下一个按钮在执行之前需要一个application.processmessages以使其工作。在下一页/第三页上,我无法自动使下一个按钮工作。通过多个页面的WebBrowser组件导航不起作用

CODE:

//CLICK BUTTON 
function clickForm1(WebBrowser: TWebBrowser; FieldName: string): Boolean; 
var 
    i, j: Integer; 
    FormItem: Variant; 
begin 
    Result := False; 
    //no form on document 
    if WebBrowser.OleObject.Document.all.tags('FORM').Length = 0 then 
    begin 
    Exit; 
    end; 
    //count forms on document 
    for I := 0 to WebBrowser.OleObject.Document.forms.Length - 1 do 
    begin 
    FormItem := WebBrowser.OleObject.Document.forms.Item(I); 
    for j := 0 to FormItem.Length - 1 do 
    begin 
    try 
    //when the fieldname is found, try to fill out 
    if FormItem.Item(j).Name = FieldName then 
    begin 
     FormItem.Item(j).click; 
     Result := True; 
    end; 
    except 
    Exit; 
    end; 
end; 
    end; 
end; 

//SEARCH INSIDE THE MEMO 
procedure TForm2.Button7Click(Sender: TObject); 
var 
    i: Integer; 
    a: string; 
begin 
    Memo1.Lines.Add(''); 
    Memo1.Lines.Text := ' ' + Memo1.Lines.Text; 
    for i := 0 to Length(Memo1.Lines.Text) - Length(edit7.Text) do 
    begin 
    a := Copy(Memo1.Lines.Text, i, Length(edit7.Text)); 
    if CheckBox1.Checked = True then //FIND CASE Sensitive 
    begin 
     if a = edit7.Text then 
     begin 
     find := True; 
     x := 2; 
     Memo1.Lines.Text := Copy(Memo1.Lines.Text, 2,    Length(Memo1.Lines.Text) - 1); 
    Memo1.SetFocus; 
    Memo1.SelStart := i - 2; 
    Memo1.SelLength := Length(edit7.Text); 
    break; 
    end; 
end 
    else        
    begin 
     if lowercase(a) = lowercase(edit7.Text) then 
     begin 
     Memo1.Lines.Text := Copy(Memo1.Lines.Text, 2,  Length(Memo1.Lines.Text) - 1); 
     find := True; 
     x := 2; 
     Memo1.SetFocus; 
     Memo1.SelStart := i - 2; 
     Memo1.SelLength := Length(edit7.Text); 
     break; 
     end; 
    end; 
    end; 
end; 


//HTML TO MEMO 
procedure TForm2.Button6Click(Sender: TObject); 
var 
    iall : IHTMLElement; 
begin 
    if Assigned(WebBrowser1.Document) then 
    begin 
    iall := (WebBrowser1.Document AS IHTMLDocument2).body; 

    while iall.parentElement <> nil do 
    begin 
     iall := iall.parentElement; 
    end; 
    memo1.Text := iall.outerHTML; 
    end; 
end; 


procedure TForm2.WebBrowser1DocumentComplete(ASender: TObject; 
    const pDisp: IDispatch; var URL: OleVariant); 
var 
Document: IHtmlDocument2; 
CurWebrowser : IWebBrowser; 
TopWebBrowser: IWebBrowser; 
WindowName : string; 

ovElements: OleVariant; 
i: Integer; 
begin 

CurWebrowser := pDisp as IWebBrowser; 
TopWebBrowser := (ASender as TWebBrowser).DefaultInterface; 
if CurWebrowser=TopWebBrowser then 
begin 

button6.Click;    // HTML TO MEMO 

TRY 
button7.Click;      //SEARCH LOGIN FORM 
if find=true then Begin 
    clickForm1(WebBrowser1, 'move'); //CLICK LOGIN BUTTON 
End Else begin Null; End; 
FINALLY find:=false; END; 

TRY 
button8.Click;   //SEARCH HOME (AFTER LOGIN) FORM 
if find1=true then Begin 
Application.ProcessMessages;//NEEDED IN ORDER THE BUTTON TO BE PRESSED. 
clickForm1(WebBrowser1, 'refresh'); //CLICK NEXT PAGE BUTTON 
End; 
FINALLY find1:=false;END; 

TRY 
button9.Click;    //SEARCH WORKLIST FORM 
if find2=true then Begin 
clickForm1(WebBrowser1, 'next'); //CLICK NEW FORM BUTTON 
End; 
FINALLY find2:=false;END; 

    end; 
end; 
+3

如果页面被回发到服务器(例如“移动”),则需要再次处理DocumentComplete上的下一页/步骤,因为webbrowser将加载新文档。所以每个步骤都应该在每个DocumentComplete事件上分开处理。如果动作是在客户端使用javascript完成的,则需要给DOM一些时间来处理空闲的动作,或者直接挂钩到脚本事件中。 – kobik 2014-11-05 08:00:15

+0

谢谢你的回答。我怎样才能再次使用onDocumentComplete方法?在上面的例子中,我插入了一个Try/Except方法,以便每次搜索加载的网页的标题并按相应的按钮。 – VaVel 2014-11-05 08:24:17

+0

例如,您可以检查URL或每次启动onDocumentComplet时检查DOM,以确定接下来要处理的步骤/页面。 – kobik 2014-11-05 08:30:18

回答

1

我不知道你了解一下代码的事件处理程序的工作有多大。

像Forms和WebBrowsers这样的对象通常具有一个或多个事件属性,用于定义事件发生时会发生什么。因此,事件属性是一个对象的属性,它可以保存调用(调用)同一个对象或另一个对象的过程(或函数,但通常不是)所需的信息。要调用的过程必须具有正确的“签名”以用于事件的类型定义。如果确实如此,则可以在代码中将事件处理程序分配给事件属性,如下所示。

只需转到Object Inspector的Events选项卡,然后双击其中一个事件名称,就可以在Delphi中以一种简单的方式使用事件属性和事件处理代码,而无需了解任何这些信息。实际上做的是创建一个新的处理程序并将其分配给对象的相应事件属性(当然,实际上该分配是在主机窗体加载时在运行时完成的)。

我的意思是“签名”是其定义中的例程类型(过程或函数)及其参数列表及其类型。

因此,对于web浏览器,该OnDocumentComplete事件的签名是

procedure (Sender: TObject; const pDisp: IDispatch; var URL: OLEVariant); 

聪明的事情是,你可以在OnDocumentComplete 财产分配给 具有完全相同的签名对象的任何程序。对于世行OnDocumentComplete事件类型是在进口单位SHDOCVW定义,顺便说一句

所以,让我们假设你分别编写包含的代码要运行 世行完成加载网址A,B和C时三种方法, :

procedure TForm1.DocCompleteA(Sender: TObject; const 
    pDisp: IDispatch; var URL: OLEVariant); 
begin 
    // Do your stuff for arrival at site/page A here 
    // Then update NavigationOK flag to reflect if you succeeded or failed 

    if NavigationOK then begin 
    WebBrowser1.OnDocumentComplete := DocCompleteB; 
    // Now navigate to site/page B 
    end 
    else 
    WebBrowser1.OnDocumentComplete := Nil; 
end; 

procedure TForm1.DocCompleteB(Sender: TObject; const 
    pDisp: IDispatch; var URL: OLEVariant); 
begin 

end; 

procedure TForm1.DocCompleteC(Sender: TObject; const 
    pDisp: IDispatch; var URL: OLEVariant); 
begin 

end; 

然后,您可以在WB的OnDocumentComplete属性又与像在DocCompleteA结束其更新WB的OnDocumentComplete所需对于B代码的代码分配给每个人, ,等等, 反过来。 NavigationOK变量只是一个标志,表示我们的导航在进展中保持“正常”。如果它因为出错而被设置为false,我们将WB的OnDocumentComplete设置为Nil,以便下次事件不发生时不做任何事情。

然后,你可以揭开序幕网站的整个“组团”像这样的东西:

procedure TForm1.NavigateSites; 
begin 
    NavigationOK := True; 
    WebBrowser1.OnDocumentComplete := DocCompleteA; 
    WebBrowser1.Navigate(...); // Navigate to site A 

end; 

当然,你不做WB的OnDocumentComplete财产和导航的更新到当前DocCompleteX中的下一个URL。事实上,如果你像NavigateSites这样的更高层次的程序,并且更容易维护,那么这可能会更清楚一些,如果你在浏览他人的网站时很重要,这些网站在没有任何预先警告的情况下容易被改变。

+0

非常感谢你的时间。我马上试试 – VaVel 2014-11-06 12:45:00

+0

@MarcielFonseca:IIrc,我用D7的代码编写了这个答案,它使用了一个相当古老的MSHTML.Pas导入单元。如果您遇到此错误,可能是因为您使用的是MSHTML.Pas的不同版本(以后版本)。但是我不明白为什么你会用DocCompleteB得到这个错误,但是没有,因为你没有提到DocCompleteA。在任何情况下,您只需使用IDE为您的TWebBrowser版本创建一个OnDocumentComplete事件,并从中复制参数列表。 – MartynA 2016-11-07 13:21:08