2014-11-05 57 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