Application locks while trying to access TWebbrows

2019-01-20 12:09发布

Edit Narrowed it down to this 1 line,

HTML := wb.OleObject.Document.documentElement.innerHTML;

which consumes the time... how can that be speed up?

Using the following code my application can hang for 1-2 seconds while it tries to access the HTML of a page (Delphi XE).

function Button1Click(Sender : TObject);
begin
   wb.navigate('http://10.0.0.154/stats');
   // Use a timer to poll the page - dont wait and process app messages
   timer1.enabled := true;
end;

procedure Timer1Timer(Sender : TObject);
var
  HTML : WideString;
begin
   If GetHTML(HTML) = true then
   begin
      Timer1.enabled := false;
      { do something }
   end;
end;


function GetHTML(var HTML : WideString) : boolean;
var
  Document : IHTMLDocument2;
begin
  HTML := '';
  Result := false;

  Document := wb.DOcument as IHTMLDocument2;
  If Assigned(Document) then
  begin
    try
      HTML := wb.OleObject.Document.documentElement.innerHTML;
      Result := true;
    except
      Result := false;
    end;
  end;
end;

However I notice in my GetHTML method can take 1-2 seconds to return something and it locks UI. Looking at the AQTime with Delphi XE it says that method call is slow (1-2 seconds). It's sporatic and I wonder if it fails when the page is still mid load.

The page I am loading is an inhouse page, full of javascript and 500k big, I can't use the OnDocumentComplete because it fires before the page is even ready, even if I do a check on the ReadyState it still fires to early.

Anyone able to shed some light, if their a faster way I can access the HTML of TWebbrowser?

3条回答
别忘想泡老子
2楼-- · 2019-01-20 12:48

Your problem appears to be that you are not allowing TWebBrowser to complete the loading of the page before you try to get the HTML. This is only a guess because you do not show how the code where you call wb.Navigate and you are having to deal with exceptions getting the InnerHTML.

You should try the following:

procedure TForm1.GetHTML(URL: string; var HTML: string);
begin
  wb.Navigate(URL);
  Application.ProcessMessages;
  while wb.Busy do
    Application.ProcessMessages;
  HTML := wb.OleObject.Document.documentElement.innerHTML;
end;
查看更多
虎瘦雄心在
3楼-- · 2019-01-20 12:56

As with @crefird's answer, I suspect you are attempting to access the InnerHTML before the browser has completed its work...

If ReadState/Busy are not returning accurate representations of the TWebBrowser's busy state, you can do this:

1) Create either a global variable, or a private member of your form... such as "FBrowserBusy: Boolean" (DON'T FORGET TO INITIALIZE IT TO TRUE JUST PRIOR TO CALLING ".Navigate") 2) As @crefird demonstrated in his answer, use a "while" loop, only substitute "wb.Busy" for "FBrowserBusy". 3) Add an OnDocumentComplete event to your TWebBrowser instance, and have this set FBusy := False;

This will eliminate any collision, and ensure that the TWebBrowser object has completed loading the document before your outer routine proceeds to interrogate it.

Hope you find this helpful!

查看更多
Ridiculous、
4楼-- · 2019-01-20 13:08

Please remember that OnDocumentComplete can fire multiple times (frames) when navigating a page.

How to properly implement OnDocumentComplete:

procedure YourForm.OnDocumentComplete(
  Sender: TObject;
  const pDisp: IDispatch;
  var URL: OleVariant);
var
  currentBrowser: IWebBrowser;
  topBrowser: IWebBrowser;
  document: OleVariant;
  windowName: string;
begin
  currentBrowser := pDisp as IWebBrowser;
  topBrowser := (Sender as TWebBrowser).DefaultInterface;
  if currentBrowser = topBrowser then
    ShowMessage('Complete document was loaded')
  else
  begin
    document := currentBrowser.Document;
    windowName := document.ParentWindow.Name;
    ShowMessage(Format('Frame "%s" was loaded', [windowName]));
  end;
end;

source:

http://www.cryer.co.uk/brian/delphi/twebbrowser/twebbrowser_events.htm#OnDocumentComplete

查看更多
登录 后发表回答