how to use DomVisitor

aneal
Posts: 5
Joined: Tue Jun 16, 2020 6:30 am

how to use DomVisitor

Post by aneal » Tue Jun 16, 2020 6:35 am

I am not an experienced Delphi developer but I am trying to use the CEF4Delphi library in the hope that I can modify the pascal code after I get it to work. I am trying to do document automation a bit like that described in
https://www.briskbard.com/forum/viewtopic.php?f=8&t=314&sid=8dfe6f20e3ced118788c8c87d8a80e9b
I have had some success so far and have working Delphi 10.3 and 10.4 code that automates simulated key presses and button clicks, a bit like how I understand Selenium might work.

Now I would like to access/extract various elements of the DOM like https://www.briskbard.com/forum/viewtopic.php?f=8&t=905&p=4023#p4023

....so I can provide more control over entering/extract data, executing JS, etc. From reading the Briskboard it seems that your DomVisitor is the best starting point to use as an example for stepping through the code and understanding how to access the ICefDomDocument. From your DomVisitor code it seems to be that you either right-click on the browser to produce a context menu or click the "Visit DOM" button to invoke procedures. However, I can't find a way to make the appropriate code execute. In other words: how do you invoke the SimpleNodeSearch procedure? Pardon my ignorance but I have spent a long time searching through the forum without any progress. Can you suggest what I might be doing wrong please?

Thanks
Aneal

User avatar
salvadordf
Posts: 2412
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: how to use DomVisitor

Post by salvadordf » Tue Jun 16, 2020 9:58 am

Hi,

The DomVisitor demo sends a process message to visit the DOM and you can send that message wherever you like :
https://github.com/salvadordf/CEF4Delphi/blob/ea447c74d5073d0f5035f99ee24807ed36d8d2cc/demos/Delphi_VCL/DOMVisitor/uDOMVisitor.pas#L516

The DOM functions in CEF are not as powerful as the DOM functions in JavaScript.

If you can't find an easy way to do what you need remember that you can execute your custom JavaScript code with TChromium.ExecuteJavaScript to visit the DOM and then use the "console trick" to send the results back to Delphi with a "console.log" call. Then you can receive the console messages in the TChromium.OnConsoleMessage event.

aneal
Posts: 5
Joined: Tue Jun 16, 2020 6:30 am

Re: how to use DomVisitor

Post by aneal » Wed Jun 17, 2020 6:09 am

Hi
Thanks for your message but I still do not understand.

To clarify my requirement in the simplest possible terms:
"I want to iterate over a selected web page elements (by using something similar to the procedure 'SimpleNodeSearch' found in the DomVisitor example) so that I can extract an element node by its Id and view it's value"

When I click the 'visit dom' button with the code running in debug and some breakpoints, I agree the code at L516 does get executed via a message and this in turn sends another message which invokes the procedure Chromium1ProcessMessageReceived at L432. However, at no stage is the procedure GlobalCEFApp_OnProcessMessageReceived ever called and this procedure is the only one that ever calls the 'SimpleNodeSearch' procedure. What steps (e.g. mouse clicks and/or keyboard presses) do I have to do to force the 'SimpleNodeSearch' procedure to run inside the DomVisitor example?

I guess my problem would be solved if you had a section describing how to use the code for newbies like myself!
TIA
Aneal

User avatar
salvadordf
Posts: 2412
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: how to use DomVisitor

Post by salvadordf » Wed Jun 17, 2020 7:36 am

Chromium uses several processes and threads to render web pages, handle the network tasks, etc.

The DOM is available in the "Renderer" process while your application lives in the "Browser" process. We send process messages between those processes to execute our code, send information and results, etc.

The problem is that Delphi will only debug one process at a time. By default it will debug the browser process and the breakpoints will only work for code sections executed inside the browser process.

GlobalCEFApp_OnProcessMessageReceived is executed in the rederer process and by default you will not be able to debug its code.

However, there are some ways to debug that code. Read this for all the details :
https://www.briskbard.com/index.php?lang=en&pageid=cef#debugging

User avatar
salvadordf
Posts: 2412
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: how to use DomVisitor

Post by salvadordf » Wed Jun 17, 2020 7:53 am

Further reading about the processes in Chromium :
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-processes

aneal
Posts: 5
Joined: Tue Jun 16, 2020 6:30 am

Re: how to use DomVisitor

Post by aneal » Thu Jun 18, 2020 10:58 am

Thanks - that certainly helped.

I can confirm that I can now step through the code in SimpleNodeSearch after setting GlobalCEFApp.SingleProcess to true as you said.

Now I would like to get and/or set the value of a html textbox element. Because I do not know how to view the log that is written by calls to CefLog I hoped that adding at L209
ShowMessage(TempNode.GetValue);
I would be able to see the user entered value but it only shows an empty string.

Is there any example that defines how to get and set the value of a textbox? Alternatively can you walk me through an example in simple terms?

User avatar
salvadordf
Posts: 2412
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: how to use DomVisitor

Post by salvadordf » Sat Jun 20, 2020 10:17 am

Sorry for the delay but I'm busy these days. :oops:

The use of several processes and threads by Chromium makes everything more complicated and this is one of the things that it's not easy to give an simple explanation.

I just uploaded a new version of the DOMVisitor demo to GitHub with the "console trick" used to send information from the render process to the browser process more easily. Please, download CEF4Delphi again and read the new code comments in the DOMVisitor demo.

As you can see, SimpleNodeSearch now sends the name and the value of the DOM node inside a console message that will be received in the TChromium.OnConsoleMessage event. That message has a preamble used to identify our message from all the other console messages.

The code in this demo can be used to get the node value but if you need to set a different value you would only have to execute some custom JavaScript code to find the node and set its value :
https://www.w3schools.com/jsref/prop_node_nodevalue.asp

Use TChromium.ExecuteJavaScript for that.

aneal
Posts: 5
Joined: Tue Jun 16, 2020 6:30 am

Re: how to use DomVisitor

Post by aneal » Sun Jun 28, 2020 7:58 am

Hello again
Today I downloaded the new domvisitor example and read through the code/comments which seem clear - thanks. Note I didn't download and reinstall the CEF4Delphi library and am unsure how often this is necessary.

On running I note it now starts up at the root of this forum's website. Hitting the 'Visit DOM' button shows a message "name:'INPUT' - value:''" indicative of a blank value for the forum's search text box. Given your previous email I expected that entering some text (e.g. "help") into the searchbox and hitting the 'Visit DOM' button would have shown a message "name:'INPUT' - value:'help'", yes? But sadly this is not the case for me as the value remained empty. Am I doing something wrong?

Also if you could extend the domvisitor example to change the value of the searchbox or modify one of JS examples to do this then I think I will be able to rework this in C++, further validating this library as a viable alternative to Delphi's built in IE-based components for website automation.

Many thanks for your continued support
Aneal

User avatar
salvadordf
Posts: 2412
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: how to use DomVisitor

Post by salvadordf » Sun Jun 28, 2020 10:11 am

I'm sorry. There seems to be an old bug in the CEF functions ICefDomNode.GetValue and ICefDomNode.SetValue
https://bitbucket.org/chromiumembedded/cef/issues/832/cefdomnode-getvalue-doesnt-return-for

The CEF project maintainer often recommends to use JavaScript to visit the DOM.

Use TChromium.ExecuteJavascript to execute this Javascript code :
console.log("DOMVISITOR" + document.getElementById("keywords").value);
As you can see the code uses the "console trick" to send information to the browser process without registering a JavaScript extension.

The information is received in TDOMVisitorFrm.Chromium1ConsoleMessage, the "DOMVISITOR" preamble is recognized and removed, and the input value is shown to the user.

I'll update that demo with this information.

aneal
Posts: 5
Joined: Tue Jun 16, 2020 6:30 am

Re: how to use DomVisitor

Post by aneal » Mon Jun 29, 2020 11:06 pm

It is good news that this code now enables me to GET the value of an input box - thanks!

However when it comes to the SET part of my requirements, the news is not so good. Neither of these work:
aDocument.GetElementById('keywords').SetValue("why is this function here if it is broken?");
document.getElementById("keywords").value = "this works in chrome developer console but not in CEF";

When looking into this a bit more it appears that this is because the CEF DOM is read-only https://magpcss.org/ceforum/viewtopic.php?f=10&t=634
Is that correct? The last post on the thread linked above suggested modifying the CEF library to access private WebKit::WebNode member named node_ for the purpose of doing this? Have you any experience of doing this or other (easier?) suggestions on how to set a input box value through JS?

The final part of my demo is to automate a button click. Can you walk me through an example of executing JS to achieve this please?

All the best from Australia

Post Reply