WebView4Delphi等でソースの取得が遅い件です

解決


りん  2026-04-21 08:44:52  No: 152245

WebView4DelphiをMr.XRAY様に教えていただきD7で色々試してます。

そこで、疑問があるのですがWebView4DelphiでもCEF4DelphでもRetrieveHTMLCompletedでソースを取得しようとすると
なぜあんなに時間がかかるのでしょうか?embedwebだと即時で表示されるにもかかわらず前記の2つは30秒くらいかかります。

NavigationCompleted自体はすぐに来ており、画面の表示も完了しているんですが、ソースの取得がかなり遅いです。
これはレジストリの書き換えやNavigationCompletedやRetrieveHTML以外で高速に取得する技をお持ちの方はいないでしょうか?


mam  URL  2026-04-22 21:01:16  No: 152247

こんばんは。

TEdgeBrowserを使う場合は以下URLでサンプルソースを記述させていただいています。
https://mam-mam.net/delphi/tedgebrowser.html

WebView4Delphiの場合は上記を少し変更して以下のようにしてHTMLソースを取得しています。
(申し訳ありませんが、Delphi12の記述です。)
SSR(サーバーサイドレンダリング)のサイトであれば取得できるかと。
外していたらすいません。

uses System.NetEncoding;

procedure TForm1.WVBrowser1DOMContentLoaded(Sender: TObject;
  const aWebView: ICoreWebView2;
  const aArgs: ICoreWebView2DOMContentLoadedEventArgs);
var pUri:PChar;
begin
  WVBrowser1.ExecuteScript(
    'encodeURI(document.documentElement.outerHTML)',1
  );
end;

procedure TForm1.WVBrowser1ExecuteScriptCompleted(Sender: TObject;
  aErrorCode: HRESULT; const aResultObjectAsJson: wvstring;
  aExecutionID: Integer);
var st:string;
    i:integer;
begin
  if aExecutionID=1 then
  begin
    if aResultObjectAsJson<>'null' then
    begin
      st:=TNetEncoding.URL.Decode(AResultObjectAsJson);
      //前後の1文字を削除して表示する
      i:=Length(st);
      Memo1.Text:=st.Substring(1,i-2);
    end;
  end;
end;


mam  2026-04-22 21:02:49  No: 152248

先ほど投稿した上記ソースの

var pUri:PChar;

は不要です。すいません。


りん  2026-04-23 12:02:49  No: 152249

高速で取得できましたぁ。ありがとうございます。
JSでは表示できますがコントロールに結果を移行するとnullが返ってしまいます。

aResultObjectAsJson:がwvstringという事は文字列でかえるので確認だけなら
デコードしなくてもmemo1.Text:=aResultObjectAsJsonみれますよね?そうするとnullになってしまいます。

CEF4Delphiのときは、確かJSの返り値を受けるときはコンソールログに出しコントロールに転記していたような気がしたのでmam様のページの「コンソール」にメッセージが出力されたイベントが発生という部分をみて色々試しているのですが、JSとの関連づけがリファレンスがみあたらなく、理解できないでいます。

多分、下記は結果を絞る関数で、*になっているところは全許可という意味ですよね?
今回は関係しませんが絞る場合はどうするのかのリファレンスが見っけられませんでした。

//  WVBrowser1.OnWebResourceRequestedイベントが発火するようになる
  WVBrowser1.AddWebResourceRequestedFilter(
    '*',COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL);

下記が関連付ける部分だと思うのですが、Console.enableは定数のようなもので
  '{}', 0の2つの引数のリファレンスが得られませんでした。

 //コンソールの使用を申請する
  WVBrowser1.CallDevToolsProtocolMethod(
    'Console.enable',
    '{}', 0
  );

下記のConsole.messageAddedもていすうのようなもので、1が関連付の番号だと思い
ますが

 //コンソールにメッセージが出力された時に
  WVBrowser1.SubscribeToDevToolsProtocolEvent('Console.messageAdded',1);

これは下記のようなJSの末尾の番号と関連付けるのですよね?もし下記の2つのけっかもログ経由で受ける場合はどのようになるのかが把握できない感じになっいます。


procedure TForm1.Button6Click(Sender: TObject);
begin
  WVBrowser1.ExecuteScript('alert("Hello");',2);
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
  WVBrowser1.ExecuteScript('alert("aaa");',3);
end;

すいませんが引き続き対応していただけますと助かります。


mam  2026-04-23 13:55:53  No: 152250

IDEからオブジェクトインスペクタで
WVBrowser1.OnDevToolsProtocolEventReceived に WVBrowser1DevToolsProtocolEventReceived
WVBrowser1.OnExecuteScriptCompleted に WVBrowser1ExecuteScriptCompleted を設定してください。

以下の3つのボタンでJavascriptを動かしてみると分かりやすいかもですね。


procedure TForm1.Button1Click(Sender: TObject);
begin
  //スクリプトの実行
  // ONExecuteScriptCompleted イベントのみが発火
  WVBrowser1.ExecuteScript('window.innerHeight',1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  // スクリプトの実行(コンソールに出力)
  // OnDevToolsProtocolEventReceived と ONExecuteScriptCompleted イベントが発火
  WVBrowser1.ExecuteScript('console.log(window.innerHeight);',2);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  // スクリプトの実行(コンソールに出力)
  // OnDevToolsProtocolEventReceived と ONExecuteScriptCompleted イベントが発火
  WVBrowser1.ExecuteScript('console.log("幅"+window.innerWidth);"高さ"+window.innerHeight',3);
end;

procedure TForm1.WVBrowser1DevToolsProtocolEventReceived(Sender: TObject;
  const aWebView: ICoreWebView2;
  const aArgs: ICoreWebView2DevToolsProtocolEventReceivedEventArgs;
  const aEventName: wvstring; aEventID: Integer);
var pwc:PChar;
begin
  Memo1.Lines.Add('OnDevToolsProtocolEventReceived');
  Memo1.Lines.Add(aEventName);//イベント名が出力
  aArgs.Get_ParameterObjectAsJson(pwc);//jsonの値をそのまま出力
  Memo1.Lines.Add(pwc);
  Memo1.Lines.Add('------------------');
end;

procedure TForm1.WVBrowser1ExecuteScriptCompleted(Sender: TObject;
  aErrorCode: HRESULT; const aResultObjectAsJson: wvstring;
  aExecutionID: Integer);
begin
  //スクリプト処理が完了
  Memo1.Lines.Add(
    'OnExecuteScriptCompleted:'+
    IntToStr(aExecutionID)+':'+
    aResultObjectAsJson
  );
  Memo1.Lines.Add('------------------');
end;


りん  2026-04-24 01:58:53  No: 152252

ありがとうございます。
だんだん理解してきました。

が、新たな謎が出てきました。
EventReceivedEventArgsのほうでButton2を実行すると下記のように表示されます。

OnDevToolsProtocolEventReceived
{"message":{"column":9,"level":"log","line":1,"source":"console-api","text":"幅342"}}

高さの値はなぜ表示されないのか?

ExecuteScriptCompletedのほうで  Memo2.Text:=aResultObjectAsJson;とすると

高さ96と表示されます。
なぜEventReceivedEventArgsの方の値にはないのに出てくるのかが謎になりました。
たぶん:が入っているので正規のJSONとして判断されていない気がするのですが、そこは、定数部分は全部置換で対処する感じになるのでしょうか?


mam  2026-04-24 08:59:39  No: 152253

Button1のjavascriptは以下を実行しています。
  window.innerHeight

Button2のjavascriptは以下を実行しています。
  console.log(window.innerHeight);

Button3のjavascriptは以下2行を実行しています。
  console.log("幅"+window.innerWidth);
  "高さ"+window.innerHeight


WVBrowser1.ExecuteScriptで実行が完了したら
  ONExecuteScriptCompleted イベントが発火
します。(console.logで出力した値は届きません)

Javascriptの console.log( 値 ) 命令でブラウザのコンソールに値を出力したら
  OnDevToolsProtocolEventReceived イベントが発火
して、値 が aArgs に届きます。

WebView2では、基本的にjavascriptでイベントの取得や値を出力させたりして、Delphi側はその値を取り出すだけになります。


りん  2026-04-26 13:34:42  No: 152256

ただいまやっと理解きました。

>Button3のjavascriptは以下2行を実行しています。

コンソールとScriptCompletedて同時に処理が得られるんですね。下記だと思い込んでいました(>_<)

//WVBrowser1.ExecuteScript('console.log("幅"+window.innerWidth);"高さ"+window.innerHeight',3);

//WVBrowser1.ExecuteScript('console.log("幅"+window.innerWidth+":高さ"+window.innerHeight);',3);



consollogの場合はScriptCompletedに結果がながれEventReceived'には流れないからnullになっていたんですね

で、色々調べているうちに文字で返るなら何故JSONと思い、しらべてみましたらオブジェクトも代入できるんですね。
そこで下記のようにしてみたところedgebrowserではJSONでかえるような記事をみかけたんですが

WVBrowser1.ExecuteScript('console.log("xxx", 28, {a: "x", b: 2})');

webviewだと下記のようになりました。

{"message":{"column":9,"level":"log","line":1,"source":"console-api","text":"xxx 28 [object Object]"}}

これはegebrowserだけで使える機能でwebviewには関係ないものだったんでしょうかね。

>WebView2では、基本的にjavascriptでイベントの取得や値を出力させたりして、Delphi側はその値を取り出すだけになります。

その方がSIMPLEでいいですね。
と思いましたが、エラーのハンドリングでつまりました。

JSONに行番号とかでるので、console.error()とかやってみましたが、表示されないだけでした。
この後ろの方は表示の見出しを変えるためで処理を変えるものではなかったのかな・・・。

そこでエラーのハンドリングもJSで行うことになるとfirefoxのレガシーとかはXPCOMがあったのでできましたが
chromeとかedge系はないですよね?そうなると&レガシー以外のハンドリングを見たことがありません。

EMBEDWBだとプロパティーにスクリプトエラーがありがwebviewではみあたりませんでした。

題材の内容は理解できて来たみたいなので、今回はどうもありがとうございました。

もし、お時間のある時にでもサイトの方で上記の2つおわかりでしたら、解説があるとうれしく思います。


※作成する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。







   このエントリーをはてなブックマークに追加