Recent

Author Topic: how to use fpCEF3 webbrowser with getElementByXxxx methods?  (Read 13067 times)

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
how to use fpCEF3 webbrowser with getElementByXxxx methods?
« on: October 22, 2016, 10:42:58 am »
how to use fpCEF3 webbrowser with getElementByXxxx  methods?
i only see Chromium.Browser.MainFrame.ExecuteJavaScript not see getElementByXxxx methods.

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #1 on: October 22, 2016, 05:32:10 pm »
now use Chromium1.Browser.MainFrame.GetSource can get the source code of html,
but how to use it?i do not know how to pass a param to the GetSource method
param is delcare like this
procedure GetSource(const visitor: ICefStringVisitor);

  ICefStringVisitor = interface(ICefBase) ['{63ED4D6C-2FC8-4537-964B-B84C008F6158}']
    procedure Visit(const str: ustring);
  end;
,need your help.thank u.
« Last Edit: October 22, 2016, 05:55:56 pm by greenzyzyzy »

Michl

  • Full Member
  • ***
  • Posts: 226
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #2 on: October 22, 2016, 11:33:29 pm »
To look into the DOM structure, you can do something like this (just tested):
Code: Pascal  [Select][+][-]
  1. uses
  2.   cef3own, cef3intf, cef3types, cef3ref, cef3lib, gettext,
  3.   sysutils, cef3lcl, Forms, StdCtrls, EditBtn, ExtCtrls;  
  4.  
  5. type
  6.  
  7.   TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn)
  8.   protected
  9.     function OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId;
  10.       const message: ICefProcessMessage): Boolean; override;
  11.   end;
  12. ...
  13.  
  14. procedure VisitNode(Node: ICefDomNode; Depth: Integer);
  15. var
  16.   i: Integer;
  17. begin
  18.   if not Assigned(Node) then Exit;
  19.   if not Node.IsText then begin
  20.     for i := 1 to Depth do Write(' ');
  21.     WriteLn(Node.ElementTagName);
  22.   end;
  23.   VisitNode(Node.FirstChild, Depth + 2);
  24.   VisitNode(Node.NextSibling, Depth);
  25. end;
  26.  
  27. procedure VisitDOM(const Document: ICefDomDocument);
  28. begin
  29. //  VisitNode(Document.Document, 0);
  30.   VisitNode(Document.Body, 0);
  31. end;
  32.  
  33. function TCustomRenderProcessHandler.OnProcessMessageReceived
  34.   (const browser: ICefBrowser; sourceProcess: TCefProcessId;
  35.   const message: ICefProcessMessage): Boolean;
  36. begin
  37.   case message.Name of
  38.     'visitdom':
  39.       begin
  40.         browser.MainFrame.VisitDomProc(@VisitDOM);
  41.         Result := True;
  42.       end;
  43.     else
  44.       Result := inherited;
  45.   end;
  46. end;
  47.  
  48.  
  49. procedure TForm1.Button1Click(Sender: TObject);
  50. begin
  51.   if Chromium.Browser.SendProcessMessage(PID_RENDERER, TCefProcessMessageRef.New('visitdom')) then
  52.     WriteLn('Triggered DOM visit.')
  53.   else
  54.     WriteLn('Failed to start DOM visit.');
  55. end;
  56.  
  57. procedure TForm1.FormCreate(Sender: TObject);
  58. var
  59.   PrjPath: ustring;
  60.   Lang, FallbackLang: string;
  61. begin
  62.   CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
  63.   PrjPath := UTF8Decode(GetCurrentDir + PathDelim);
  64.   CefLocalesDirPath := PrjPath + 'locales';
  65.   GetLanguageIDs(Lang, FallbackLang);
  66.   CefLocale := UTF8Decode(FallbackLang);
  67.   edtURL.Text := 'http://forum.lazarus.freepascal.org/index.php/board,21.0.html/';
  68. end;
The same job iterativ (just show Form Control Elements):
Code: Pascal  [Select][+][-]
  1. procedure VisitDOM(const Document: ICefDomDocument);
  2. var
  3.   Node: ICefDomNode;
  4.   Depth, i: Integer;
  5. begin
  6.   Depth := 0;
  7.   Node := Document.Document;
  8.   while Assigned(Node) do
  9.   begin
  10.     if Node.IsFormControlElement then
  11.       WriteLn(Node.Name, ' - ', Node.AsMarkup);
  12. {    if not Node.IsText then begin
  13.       for i := 1 to Depth do Write(' ');
  14.       WriteLn(Node.ElementTagName);
  15.     end;}
  16.     if Node.HasChildren then begin
  17.       Node := Node.FirstChild;
  18. //      Inc(Depth, 2);
  19.       Continue;
  20.     end;
  21.     while not Assigned(Node.NextSibling) do begin
  22.       Node := Node.Parent;
  23. //      Dec(Depth, 2);
  24.       if not Assigned(Node) then Exit;
  25.     end;
  26.     Node := Node.NextSibling
  27.   end;
  28. end;
And if you just want to look for the current topics in forum.lazarus.freepascal.org/general, you can do it so:
Code: Pascal  [Select][+][-]
  1. procedure VisitNode(Node: ICefDomNode; IsTopic: Boolean);
  2. begin
  3.   if not Assigned(Node) then Exit;
  4.   if Node.Name = 'SPAN' then begin
  5.     VisitNode(Node.FirstChild, True);
  6.     Exit;
  7.   end;
  8.   if IsTopic then begin
  9.     WriteLn(Node.ElementInnerText);
  10.     Exit;
  11.   end;
  12.   VisitNode(Node.FirstChild, False);
  13.   VisitNode(Node.NextSibling, False);
  14. end;
  15.  
  16. procedure VisitDOM(const Document: ICefDomDocument);
  17. var
  18.   Node: ICefDomNode;
  19. begin
  20.   if not (Pos('http://forum.lazarus.freepascal.org/index.php/board,21.0.html/', Document.GetBaseUrl) = 1) then
  21.     Exit;
  22.   Node := Document.GetElementById('messageindex');
  23.   VisitNode(Node, False);
  24. end;
A simple test app added. Even done. Hope it gives you inspirations.
Code: [Select]
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #3 on: October 23, 2016, 02:59:08 am »
thanks for reply.but is it all ways need to use Chromium.Browser.SendProcessMessage
and browser.MainFrame.VisitDomProc(@VisitDOM) to get it?
is there not a easy way to use VisitDom( ) function directly?
and how about how to use GetSource method?thank you.
and it seems your code test is no effect in gui mode.my lazarus ver is 1.6
and some sites is error,just like the picture as below.
« Last Edit: October 23, 2016, 11:23:13 am by greenzyzyzy »

Michl

  • Full Member
  • ***
  • Posts: 226
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #4 on: October 23, 2016, 08:55:13 pm »
thanks for reply.but is it all ways need to use Chromium.Browser.SendProcessMessage
and browser.MainFrame.VisitDomProc(@VisitDOM) to get it?
AFAIK yes.

and how about how to use GetSource method?
Do something like this (tested in your app "dom"):
Code: Pascal  [Select][+][-]
  1. uses ..., cef3own;
  2.  
  3. procedure StringVisitor(const str: ustring);
  4. begin
  5.   Mainform.Log.Text := UTF8Encode(str); // UTF8Encode hide the conversion warning
  6. end;
  7.  
  8. procedure TMainform.ChromiumLoadEnd(Sender : TObject; const Browser : ICefBrowser; const Frame : ICefFrame;
  9.   httpStatusCode : Integer);
  10. var
  11.   CefStringVisitor: ICefStringVisitor;
  12. begin
  13.   EUrl.Text := UTF8Encode(Browser.MainFrame.Url);
  14.  
  15. {  If Browser.SendProcessMessage(PID_RENDERER, TCefProcessMessageRef.New('addListener')) then
  16.     Log.Append('Listener registered.')
  17.   Else
  18.     Log.Append('Failed to register listener.');
  19. }
  20.   CefStringVisitor := TCefFastStringVisitor.Create(@StringVisitor);
  21.   Chromium.Browser.MainFrame.GetSource(CefStringVisitor);
  22. end;

and it seems your code test is no effect in gui mode.my lazarus ver is 1.6
I don't understand. Can you explain more, what you want and doesn't work?

and some sites is error,just like the picture as below.
Can you tell me, which webpage show such a error? Maybe there is a bug in the logic of my short written test, so I can check.
Code: [Select]
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #5 on: October 24, 2016, 03:24:05 am »
thank you for the GetSource method code.runing well.
the error site is a chinese site. http://www.163.com   .not your code error. only  load url method
error too.
« Last Edit: October 24, 2016, 03:27:39 am by greenzyzyzy »

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #6 on: October 26, 2016, 09:44:24 am »
excuse me .why i do it like this  visit dom does not work?

procedure TForm1.Button1Click(Sender: TObject);
begin
  Chromium1.Load(Edit1.Text);
end;
procedure VisitDom(const visit: ICefDomDocument);
begin
  Form1.Memo1.Lines.Add(visit.GetTitle);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  //visit:ICefDomDocument;
  visit:ICefDomVisitor;
begin
visit:=TCefFastDomVisitor.Create(@VisitDom);
Chromium1.Browser.MainFrame.VisitDom(visit);
end;

Michl

  • Full Member
  • ***
  • Posts: 226
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #7 on: October 26, 2016, 11:16:07 am »
Please have a look at the example in FPCEF3 package directory /Examples/DOMAccess.

You have to do following:
Code: Pascal  [Select][+][-]
  1. var
  2.   ActiveBrowser: ICefBrowser;
  3.  
  4. procedure VisitDOM(const visit: ICefDomDocument);
  5. var
  6.   message: ICefProcessMessage;
  7. begin
  8.   message := TCefProcessMessageRef.New('titledata');
  9.   message.ArgumentList.SetString(0, visit.GetTitle);
  10.   ActiveBrowser.SendProcessMessage(PID_BROWSER, message);
  11. end;
  12.  
  13. function TCustomRenderProcessHandler.OnProcessMessageReceived
  14.   (const browser: ICefBrowser; sourceProcess: TCefProcessId;
  15.   const message: ICefProcessMessage): Boolean;
  16. begin
  17.   ActiveBrowser := browser;  // insert the current browser
  18.   case message.Name of
  19.     'visitdom':
  20.       begin
  21.         browser.MainFrame.VisitDomProc(@VisitDOM);
  22.         Result := True;
  23.       end;
  24.     else
  25.       Result := inherited;
  26.   end;
  27. end;
  28.  
  29. ...
  30.  
  31. procedure TForm1.ChromiumProcessMessageReceived(
  32.   Sender: TObject; const Browser: ICefBrowser;
  33.   sourceProcess: TCefProcessId;
  34.   const message: ICefProcessMessage; out Result: Boolean);
  35. begin
  36.   case message.Name of
  37.     'titledata':
  38.       Memo1.Lines.Add('Title: ' + message.ArgumentList.GetString(0));
  39.   else
  40.     Memo1.Lines.Add('Unhandled message: ' + message.Name);
  41.     inherited;
  42.   end;
  43. end;
Code: [Select]
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #8 on: October 26, 2016, 12:41:39 pm »
Please have a look at the example in FPCEF3 package directory /Examples/DOMAccess.

You have to do following:
Code: Pascal  [Select][+][-]
  1. var
  2.   ActiveBrowser: ICefBrowser;
  3.  
  4. procedure VisitDOM(const visit: ICefDomDocument);
  5. var
  6.   message: ICefProcessMessage;
  7. begin
  8.   message := TCefProcessMessageRef.New('titledata');
  9.   message.ArgumentList.SetString(0, visit.GetTitle);
  10.   ActiveBrowser.SendProcessMessage(PID_BROWSER, message);
  11. end;
  12.  
  13. function TCustomRenderProcessHandler.OnProcessMessageReceived
  14.   (const browser: ICefBrowser; sourceProcess: TCefProcessId;
  15.   const message: ICefProcessMessage): Boolean;
  16. begin
  17.   ActiveBrowser := browser;  // insert the current browser
  18.   case message.Name of
  19.     'visitdom':
  20.       begin
  21.         browser.MainFrame.VisitDomProc(@VisitDOM);
  22.         Result := True;
  23.       end;
  24.     else
  25.       Result := inherited;
  26.   end;
  27. end;
  28.  
  29. ...
  30.  
  31. procedure TForm1.ChromiumProcessMessageReceived(
  32.   Sender: TObject; const Browser: ICefBrowser;
  33.   sourceProcess: TCefProcessId;
  34.   const message: ICefProcessMessage; out Result: Boolean);
  35. begin
  36.   case message.Name of
  37.     'titledata':
  38.       Memo1.Lines.Add('Title: ' + message.ArgumentList.GetString(0));
  39.   else
  40.     Memo1.Lines.Add('Unhandled message: ' + message.Name);
  41.     inherited;
  42.   end;
  43. end;




thank you, and yes the example is ok.but i want to use it like the GetSource method.it is no need so much codes.

Michl

  • Full Member
  • ***
  • Posts: 226
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #9 on: October 26, 2016, 01:34:00 pm »
it is no need so much codes.
;) I'm on your side!

But Chromium isn't working in that way you (we) want. The created render process, isn't part of your app. AFAIK, the only way to communicate with it, is the described way.

Maybe you are simply looking for the event Chromium.OnTitleChange, there you can do something like:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ChromiumTitleChange(Sender: TObject;
  2.   const Browser: ICefBrowser; const title: ustring);
  3. begin
  4.   Memo1.Lines.Add(UTF8Encode(title));
  5. end
Code: [Select]
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #10 on: October 26, 2016, 02:01:34 pm »
it is no need so much codes.
;) I'm on your side!

But Chromium isn't working in that way you (we) want. The created render process, isn't part of your app. AFAIK, the only way to communicate with it, is the described way.

Maybe you are simply looking for the event Chromium.OnTitleChange, there you can do something like:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ChromiumTitleChange(Sender: TObject;
  2.   const Browser: ICefBrowser; const title: ustring);
  3. begin
  4.   Memo1.Lines.Add(UTF8Encode(title));
  5. end

ok.it is does not matter.thank you very much.
and the last two question.
how about GetBody method?the same as the GetTitle?
and how to use a proxy with fpcef3?
thank you.
« Last Edit: October 26, 2016, 02:05:55 pm by greenzyzyzy »

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #11 on: October 27, 2016, 04:26:33 am »
it is no need so much codes.
;) I'm on your side!

But Chromium isn't working in that way you (we) want. The created render process, isn't part of your app. AFAIK, the only way to communicate with it, is the described way.

Maybe you are simply looking for the event Chromium.OnTitleChange, there you can do something like:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ChromiumTitleChange(Sender: TObject;
  2.   const Browser: ICefBrowser; const title: ustring);
  3. begin
  4.   Memo1.Lines.Add(UTF8Encode(title));
  5. end



would you like to help me again?thank you very much.

Michl

  • Full Member
  • ***
  • Posts: 226
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #12 on: October 27, 2016, 09:33:27 pm »
how about GetBody method?the same as the GetTitle?
AFAIK, there is no other way, as the way above:
Code: Pascal  [Select][+][-]
  1. procedure VisitDOM(const Document: ICefDomDocument);
  2. var
  3.   message: ICefProcessMessage;
  4. begin
  5.   message := TCefProcessMessageRef.New('bodydata');
  6.   message.ArgumentList.SetString(0, document.Body.AsMarkup);
  7.   ActiveBrowser.SendProcessMessage(PID_BROWSER, message);
  8. end;
  9.  
  10. function TCustomRenderProcessHandler.OnProcessMessageReceived
  11.   (const browser: ICefBrowser; sourceProcess: TCefProcessId;
  12.   const message: ICefProcessMessage): Boolean;
  13. begin
  14.   ActiveBrowser := browser;
  15.   case message.Name of
  16.     'visitdom':
  17.       begin
  18.         browser.MainFrame.VisitDomProc(@VisitDOM);
  19.         Result := True;
  20.       end;
  21.     else
  22.       Result := inherited;
  23.   end;
  24. end;
  25.  
  26. ...
  27.  
  28. procedure TForm1.ChromiumProcessMessageReceived(
  29.   Sender: TObject; const Browser: ICefBrowser;
  30.   sourceProcess: TCefProcessId;
  31.   const message: ICefProcessMessage; out Result: Boolean);
  32. begin
  33.   case message.Name of
  34.     'bodydata':
  35.       Memo1.Lines.Add(UTF8Encode(message.ArgumentList.GetString(0)));
  36.   else
  37.     Memo1.Lines.Add('Unhandled message: ' + UTF8Encode(message.Name));
  38.     inherited;
  39.   end;
  40. end;

If you search for a special info, you can parse the DOM nodes easily (like in my first post):
Code: Pascal  [Select][+][-]
  1. procedure GetNodeInfo(Node: ICefDomNode; var Info: ustring);
  2. begin
  3.   if not Assigned(Node) then Exit;
  4.   Info := Info
  5.     + Node.Name + ';'
  6. //    + Node.ElementTagName + ';'
  7. //    + Node.ElementInnerText + ';'
  8. //    + Node.GetValue
  9.     + LineEnding;
  10.  
  11.   GetNodeInfo(Node.FirstChild, Info);
  12.   GetNodeInfo(Node.NextSibling, Info);
  13. end;
  14.  
  15. procedure VisitDOM(const Document: ICefDomDocument);
  16. var
  17.   message: ICefProcessMessage;
  18.   s: ustring;
  19. begin
  20.   SetLength(s, 0);
  21.   GetNodeInfo(document.Body, s);
  22.   message := TCefProcessMessageRef.New('bodydata');
  23.   message.ArgumentList.SetString(0, s);
  24.   ActiveBrowser.SendProcessMessage(PID_BROWSER, message);
  25. end;  

and how to use a proxy with fpcef3?
Sorry, I dont know. I never need it before. Just google "DCEF proxy". Maybe there is some info around, like (untested) http://stackoverflow.com/questions/13426649/proxy-settings-chromium-embedded
Code: [Select]
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;

greenzyzyzy

  • Full Member
  • ***
  • Posts: 249
Re: how to use fpCEF3 webbrowser with getElementByXxxx methods?
« Reply #13 on: October 28, 2016, 10:11:31 am »
ok,thank you very very much

 

TinyPortal © 2005-2018