[Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post a reply

Confirmation code
Enter the code exactly as it appears. All letters are case insensitive.
Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :| :mrgreen: :geek: :ugeek: :arrow: :angel: :clap: :crazy: :eh: :lolno: :problem: :shh: :shifty: :sick: :silent: :think: :thumbup: :thumbdown: :salute: :wave: :wtf: :yawn: :facepalm: :bravo: :dance: :beard: :morebeard: :xmas: :HeHe: :trollface: :cookie: :rainbow: :monkeysee: :monkeysay: :happybday: :headwall: :offtopic: :superhappy: :terms: :beer:
View more smilies

BBCode is ON
[img] is OFF
[flash] is OFF
[url] is ON
Smilies are ON

Topic review
   

Expand view Topic review: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by malcev » Today, 19:21

In selenium You can post in facebook like this:

Code: [Select all]GeSHi © Codebox Plus

driver:= ComObjCreate("Selenium.ChromeDriver")
driver.Get("https://www.facebook.com/")
element := driver.findElementByCss("textarea[name=""xhpc_message""]")
element.Click()
element.sendKeys("test")
element := driver.findElementByCss("button[data-testid=""react-composer-post-button""]")
element.Click()

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by GeekDude » Today, 17:27

The syntax to set the value of a control is (IIRC) document.querySelector('abc').value = 'This is some text', but many websites don't like it when you set the value directly.

In that case, you would want to make a bunch of calls to the dispatchKeyEvent endpoint documented here: https://chromedevtools.github.io/devtoo ... /tot/Input

I don't have any examples of using it though, sorry!

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by taapo » Today, 14:18

How do you "type" text?

I'm trying to create a status update for a Facebook page using your script, and I'm almost there, but I'm running into problems.

So'm I'm unsure if I should do this:

Code: [Select all]GeSHi © Codebox Plus

PageInst.Evaluate("document.querySelector('div._1mf._1mj span').click();")
Send This is a status update
PageInst.Evaluate("document.querySelector('._1mf7._69g1._4jy0._4jy3._4jy1._51sy.selected._42ft').click();")

... which doesn't seem to work properly half of the time (not sure why).

or more something like this (which gives a script error):

Code: [Select all]GeSHi © Codebox Plus

PageInst.Evaluate("document.querySelector('div._1mf._1mj span span').value('This is a status update');")
PageInst.Evaluate("document.querySelector('._1mf7._69g1._4jy0._4jy3._4jy1._51sy.selected._42ft').click();")


Any pointers?

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by Xtra » 14 Jun 2018, 17:26

Guest wrote:how do I extract the URL from the Address Bar?

PageInstance.Evaluate("document.URL;").Value
or
PageInstance.Evaluate("window.location.href;").Value

HTH

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by Guest » 14 Jun 2018, 15:53

After spending the last 2 hours trying to figure out GetElement and GetTab, I finally realized GetTab doesn't exist lol.

Anyways, thank you SO MUCH for adding this!

I have one really dumb question - how do I extract the URL from the Address Bar?

Also, is there documentation on what functions are available with Chrome? I'm very, very new to programming and don't know any COM syntax. But I'm eager to learn!

Thanks,
Bryan

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by GeekDude » 13 Jun 2018, 12:28

KusochekDobra wrote:Help me please.
I do not understand, how to use Chrome browser with "Chrome.ahk" in "Headless" mod.
Can you give an example?


Check out the ExportPDF.ahk example

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by KusochekDobra » 13 Jun 2018, 12:12

Help me please.
I do not understand, how to use Chrome browser with "Chrome.ahk" in "Headless" mod.
Can you give an example?

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by Xtra » 24 May 2018, 12:58

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by GeekDude » 24 May 2018, 09:25

PoorInRichfield wrote:Not an earth-shattering change, but I added the -incognito flag to the Run command in attempt to get Chrome to stop showing all sorts of annoying alerts and pop-ups...


Some other good flags I've seen around the net are --no-first-run and --disable-extensions. You don't necessarily have to modify the Chrome class to add flags, since there's a parameter in the constructor you can pass them to.

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by PoorInRichfield » 24 May 2018, 09:19

Not an earth-shattering change, but I added the -incognito flag to the Run command in attempt to get Chrome to stop showing all sorts of annoying alerts and pop-ups...

Code: [Select all]GeSHi © Codebox Plus

	Run, % this.CliEscape(ChromePath)
. " -incognito --remote-debugging-port=" this.DebugPort
. (ProfilePath ? " --user-data-dir=" this.CliEscape(ProfilePath) : "")
. (Flags ? " " Flags : "")
. URLString
,,, OutputVarPID
this.PID := OutputVarPID

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by KusochekDobra » 18 May 2018, 14:01

GeekDude wrote:
KusochekDobra wrote:Is it possible to connect to events such as Target.targetCreated? This feature would reduce the possibility of errors, telling the ahk-code what him need to create a new connection.

I haven't tested it, but I think if use the Target.setDiscoverTargets method that you can receive those events using the new callback system.

Thank you very much! Indeed, it works! And I did not think about this possibility. :thumbup:

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by Stavencross » 18 May 2018, 12:59

To start chrome without all the UI buttons, instantiate the class like this
ChromeInst := new Chrome("ChromeProfile", "--app=https://autohotkey.com/")

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by GeekDude » 18 May 2018, 11:48

The delay is caused by decoding chrome's response from a JSON message into an AHK object. Like with IE, the browser responds with the source immediately. However, IE responds with the text directly, and Chrome responds with a JSON blob that contains the text but must be decoded into a useful form. Because AutoHotkey does not support JSON encode/decode natively, this conversion must be done with a user-made script. That page's source is roughly 200kb, so the decoding process takes a while.

One alternative may be to use the file api to make chrome download the source as a file, then use AHK to read in that file. This takes about ~700ms on my system.

Code: [Select all] [Expand]GeSHi © Codebox Plus



Some other options could be to find a more performant way of reading JSON and extend/modify the class to use that instead. You could look for another way of doing interprocess communication with chrome, such as fiddling with the clipboard (I tried this with little to no success) or saving to the browser's local storage and reading that with an sqlitedb script.

Another potential option is to try to avoid transferring so much data across. If there's some kind of processing that needs to be done to the page, could that processing be done in JavaScript and only the results be returned to AHK?

Finally, you could use something other than this library, like the Selenium example you used to demonstrate.

Good luck!

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by malcev » 18 May 2018, 10:31

Why does it take a lot of time to get page source?
For example if I use IE or Selenium it takes about 100ms.
IE:

Code: [Select all]GeSHi © Codebox Plus

oIE := ComObjCreate("InternetExplorer.Application")
oIE.visible := True
oIE.navigate("http://delfi.lv")
While oIE.readyState != 4 || oIE.document.readyState != "complete" || oIE.busy
sleep 10
a := a_tickcount
OuterHTML := oIE.Document.documentElement.OuterHtml
msgbox % a_tickcount - a

Selenium:

Code: [Select all]GeSHi © Codebox Plus

driver:= ComObjCreate("Selenium.ChromeDriver")
driver.Get("http://delfi.lv")
a := A_TickCount
OuterHtml := driver.PageSource()
msgbox % A_TickCount - a

But with Chrome DevTools Protocol about 3500ms.
I tried with CHROME DOM API and with JavaScript injection - the time is the same.
Chrome DevTools Protocol:

Code: [Select all] [Expand]GeSHi © Codebox Plus

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by GeekDude » 18 May 2018, 07:33

KusochekDobra wrote:It will be very powerful instrument! :)

In "Source code (zip)" - link => in "Chrome.ahk" file => in 72 code-line have a one missing letter "t" (...\App Pahs\chrome.exe).

My bad, I'll fix it in the next release. Thanks for pointing it out!



KusochekDobra wrote:Can I ask you to add the name of the function to the constructor of class Page by the third parameter, which will be called when the connection is broken?
For example:

*snip*

I make a simple wrapper for use in the program and concluded that it would be convenient to remove data about an unused connection from the object of this wrapper because of a disconnection that may occur if the user closes the tab.
Example:

*snip*

I hope this request does not look like impudence.
And thank you very much for your hard work!
Beautiful code and maximum efficiency! :bravo:

Good idea, I'll try to add it to the next release. Thanks!


KusochekDobra wrote:And another question. Is it possible to replace this exception:

Code: [Select all]GeSHi © Codebox Plus

Call(DomainAndMethod, Params:="", WaitForResponse:=True)
{
if !this.Connected
throw Exception("Not connected to tab")

; ... other code
}

To return a connection to the state "disabled"?

I think that this is logical, if all the tabs are closed, then you need to create a new connection, reinitializing the instance of the class Chrome. Instead, there is a constant call "Runtime.evaluate" without parameters, and the program terminates its work after the exception message.

Because it throws an exception you can put multiple calls into a single try-catch block, and use the catch to define something to happen instead of the script terminating. If Call returned a value to indicate an error instead, you would have to check the result of every Call individually, and it would make error propagation through wrappers like Evaluate much more difficult.


KusochekDobra wrote:Sometimes, when creating an instance of a class Chrome, passing an address to the constructor, the method WaitForLoad() returns flow control before the page loads:

*snip*

This can be circumvented by creating an instance of the class without an address, followed by a transition PageInst.Call("Page.navigate", {"url": address}) and PageInst.WaitForLoad(), but is there any way to do without it?

Creating an instance without an address (or with an address like about:blank then later using Page.navigate is the recommended way right now. It's likely that, in the future, the library will use this method internally instead of passing in the URLs directly.


KusochekDobra wrote:Is it possible to connect to events such as Target.targetCreated? This feature would reduce the possibility of errors, telling the ahk-code what him need to create a new connection.

I haven't tested it, but I think if use the Target.setDiscoverTargets method that you can receive those events using the new callback system.



Stavencross wrote:I really love this library! Just a couple questions as I'd like to work it in deeper into my webapp.

One of the things I have to do is navigate to a url, and which triggers a pdf download. Is there a way for the lib to know when the download is complete? Right now I use a function called watch folder to loop through my downloads folder until a new file is present and grab it.

https://developer.chrome.com/extensions ... -onCreated

Something like this here would be perfect, but it's part of the extensions Api so I don't know that you have access to it.

Secondly, is it possible to launch chrome without the ui buttons, or similar to how in IE we can launch a shell as a gui browser?

I don't think there's a way to do that directly, but there may be a somewhat indirect way to go about it. When using Chrome.ahk you can connect to regular tabs, but also to the pages that make up extensions. If there's an extension with the proper permissions already in place, or if you can get an extension of your own creation installed, you should be able to connect to the extension and manipulate things from there.

Another possibility would be using one of the more hidden targets/pages that you can connect to. There's one listed on this page http://localhost:9222/json/version separate from all the others (which are listed on just http://localhost:9222/json) which has some slightly different functionality to it. What that functionality is, though, I'm not sure.

One method you may be interested in, although it's not what your'e asking for, is Page.setDownloadBehavior which lets you change the folder that the files are saved to.

Final thing on this question. Your method of watching the folder sounds pretty robust, given how chrome downloads as a separate file then renames it to be the final downloaded file once it's complete. There are very efficient methods of watching folders demonstrated elsewhere on the forum. For example, https://autohotkey.com/boards/viewtopic.php?t=8384 . On the other hand, you may find that complex functions for such a simple problem are unnecessary :lol:. I'm all about informing people of their options, but you're more than free to make your own opinion.

For your second question, I'm pretty sure the answer is not with this library. You could look into something like the Chrome Embedded Framework for Python and try to copy what it does, but it will be a lot of work.

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by Stavencross » 16 May 2018, 05:28

Geek Dude wrote:
Stavencross

Stavencross wrote:Really been digging in to this Lib, its so helpful! Just want to see if ya'll have a better way on how to scrape the JSON I've been grabbing from these pages. Here is my code:

*snip*

If you check jsonGrabber(), you'll see I'm grabbing the JSON from the page DOM. I grab the innerHTML of the page, and run strReplace to get rid of the <pre> tags. I thought I'd see if ya'll had a better way to accomplish this as it feels dirty. I'm also open to any other code optimizations you could throw my way. I've been working on my coding skills a lot in the last 6 months and I know I really need to start pushing myself to write better & more modular code

It's hard to say without access to the actual page, but I would bet that grabbing from document.body.innerText would work better for you than document.body.innerHTML



I really love this library! Just a couple questions as I'd like to work it in deeper into my webapp.

One of the things I have to do is navigate to a url, and which triggers a pdf download. Is there a way for the lib to know when the download is complete? Right now I use a function called watch folder to loop through my downloads folder until a new file is present and grab it.

https://developer.chrome.com/extensions ... -onCreated

Something like this here would be perfect, but it's part of the extensions Api so I don't know that you have access to it.

Secondly, is it possible to launch chrome without the ui buttons, or similar to how in IE we can launch a shell as a gui browser?

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by KusochekDobra » 15 May 2018, 12:24

Is it possible to connect to events such as Target.targetCreated? This feature would reduce the possibility of errors, telling the ahk-code what him need to create a new connection.

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by KusochekDobra » 14 May 2018, 10:35

And another question. Is it possible to replace this exception:

Code: [Select all]GeSHi © Codebox Plus

Call(DomainAndMethod, Params:="", WaitForResponse:=True)
{
if !this.Connected
throw Exception("Not connected to tab")

; ... other code
}

To return a connection to the state "disabled"?

I think that this is logical, if all the tabs are closed, then you need to create a new connection, reinitializing the instance of the class Chrome. Instead, there is a constant call "Runtime.evaluate" without parameters, and the program terminates its work after the exception message.

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by KusochekDobra » 14 May 2018, 08:51

Sometimes, when creating an instance of a class Chrome, passing an address to the constructor, the method WaitForLoad() returns flow control before the page loads:

Code: [Select all] [Expand]GeSHi © Codebox Plus


This can be circumvented by creating an instance of the class without an address, followed by a transition PageInst.Call("Page.navigate", {"url": address}) and PageInst.WaitForLoad(), but is there any way to do without it?

Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!

Post by KusochekDobra » 12 May 2018, 19:50

Can I ask you to add the name of the function to the constructor of class Page by the third parameter, which will be called when the connection is broken?
For example:

Code: [Select all] [Expand]GeSHi © Codebox Plus


I make a simple wrapper for use in the program and concluded that it would be convenient to remove data about an unused connection from the object of this wrapper because of a disconnection that may occur if the user closes the tab.
Example:

Code: [Select all] [Expand]GeSHi © Codebox Plus


I hope this request does not look like impudence.
And thank you very much for your hard work!
Beautiful code and maximum efficiency! :bravo:

Top