Re: [Library] Chrome.ahk - Automate Google Chrome using native AutoHotkey. No Selenium!
Posted: 25 Jun 2018, 10:47
Deleted.
Let's help each other out
https://www.autohotkey.com/boards/
I'm sorry but I can't help with this without a much more thorough understanding of your situation and your goals. I don't have the time to dive that deeply into it right now.Manuf wrote:Hi sirs. Can you help me with this simple task
i want to write a script to detect
- can check if webpage full loaded
- can check if webpage loaded error
- can check if an element display after an action. Ie: after upload a file, a button will turn from gray to yellow. i want to check that state of the button.
Thanks you
I don't think you can do that directly, but a viable alternative may be to generate a google search url and navigate to that. For example,bmilcs wrote:I have a few questions for you regarding this script:
#1) PageInst.Call("Page.navigate", {"url": address})
I am trying to pass text that isn't a specific URL, but text that I would normally type to search google for. However, I'm receiving errors from Chrome.AHK. Is there a section of the Chrome.ahk script I can edit to allow for non-url text to be passed as valid?
Code: Select all
PageInst.Call("Page.navigate", {"url": "https://google.com/search?q=" UriEncode("Search Terms")})
; Modified by GeekDude from http://goo.gl/0a0iJq
UriEncode(Uri, RE="[0-9A-Za-z]") {
VarSetCapacity(Var, StrPut(Uri, "UTF-8"), 0), StrPut(Uri, &Var, "UTF-8")
While Code := NumGet(Var, A_Index - 1, "UChar")
Res .= (Chr:=Chr(Code)) ~= RE ? Chr : Format("%{:02X}", Code)
Return, Res
}
Try PageInst.Evaluate("window.location.href")bmilcs wrote:#2) How do I retrieve the current URL of the active PageInst?
As mentioned at the top of the original post, the Chrome DevTools Protocol's documentation lists a lot of endpoints that you can use from PageInst.Call: https://chromedevtools.github.io/devtools-protocol/bmilcs wrote:#3) I am a dummy, but are there commands that work with Chrome.ahk that aren't mentioned as examples?
I have zero experience with this, and am wondering if there is another resource detailing the COMS available to us via Chrome.ahk?
In other words, does this just unlock the ability to use Chrome and not give you a full scope of possibilities?
No need to apologize. I love when people are eager to learn . Good luck with your code!bmilcs wrote:I'm dying to learn more but feel like I'm missing something. Thanks!
Edit: Apologies if I misused vocab or sound like a moron. I've been able to successfully scrape metadata off of websites which is quite exciting! Thank you again for posting such a tremendously useful script!
Code: Select all
037: if i := InStr("{[", ch)
047: if InStr("}]", ch)
049: ObjRemoveAt(stack, 1)
050: next := stack[1]==tree ? "" : is_arr[stack[1]] ? ",]" : ",}"
051: }
134: }
010: While,( (ch := SubStr(src, ++pos, 1)) != "" )
136: Return,tree[1]
---- E:\autohotkey\Infraware\Chrome\Chrome.ahk
316: fnCallback := this.fnCallback
317: if (newData := %fnCallback%(data))
320: if this.responses.HasKey(data.ID)
322: }
329: } (0.91)
Code: Select all
PageInst.Disconnect()
Code: Select all
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
#Include C:\Program Files\AutoHotkey\Chrome.ahk
ChromeInst := new Chrome()
PageInst := ChromeInst.GetPage()
PageInst.Call("Page.navigate", {"url": "http://google.com"})
PageInst.WaitForLoad()
sleep 10000
PageInst.Evaluate("setInterval(function(){var div = document.getElementsByName('btnK')[0];var rect = div.getBoundingClientRect();x = rect.left;alert("("x")");});")
x = PageInst.Evaluate("rect.left")
msgbox, %x%
Code: Select all
#SingleInstance, Force
#NoEnv
OnExit, BeforeExit
#Include <Chrome>
; >>--++--<< >>--++--<<
ProfilePath := "Chrome_Profile"
; >>--++--<< >>--++--<<
if (!FileExist(ProfilePath))
FileCreateDir,% ProfilePath
; >>--++--<< >>--++--<<
ChromeInst := new Chrome(ProfilePath,"about:blank","--no-first-run")
if !(PageInst := ChromeInst.GetPage())
{
MsgBox, Could not retrieve page!
ChromeInst.Kill()
ExitApp
}
PageInst.Call("Page.navigate", {"url": "https://p.ahkscript.org/"})
PageInst.WaitForLoad()
MsgBox,,Title,Exit from app
ExitApp
BeforeExit:
OutputDebug,Exit now
try
PageInst.Call("Browser.close") ; Fails when running headless
catch
ChromeInst.Kill()
; |=> Next code is unreachable
OutputDebug,Close Browser
PageInst.Disconnect()
OutputDebug,Disconnect
ExitApp
Code: Select all
#SingleInstance, Force
#NoEnv
;OnExit, BeforeExit
#Include <Chrome>
; >>--++--<< >>--++--<<
ProfilePath := "Chrome_Profile"
; >>--++--<< >>--++--<<
if (!FileExist(ProfilePath))
FileCreateDir,% ProfilePath
; >>--++--<< >>--++--<<
pageSettings := {"ahkscript": {"funcName": "MsgFunc"}}
page := new PageClass(ProfilePath, pageSettings)
; >>--++--<< >>--++--<<
page.PageNavigate("https://p.ahkscript.org/")
MsgBox,,Title,Exit from app
;ExitApp
BeforeExit:
page.Quit()
ExitApp
MsgFunc(data) {
if (data.method == "Console.messageAdded") {
msg := data.params.message
MsgBox,,Message from browser,% msg.text
} else
OutputDebug,% Format("data.method = {}", data.method)
}
Class PageClass
{
__New(ProfilePath, pageSettings, URLs := "about:blank", ar := "") {
this.tabs := {}, this.page := "", this.ProfilePath := ProfilePath
this.pageSettings := pageSettings
if (Chrome.FindInstances()) {
this.ChromeInst := {"base": Chrome, "DebugPort": 9222}
} else {
this.ChromeInst := new Chrome(ProfilePath,URLs,Format("--no-first-run{}",ar ? (" " . ar) : ar))
}
this.GetTabs()
}
GetTabs() {
pageIndex := 1, this_page := ""
for i, obj in this.ChromeInst.GetPageList() {
if ( obj.type == "page" ) {
if ( !this.tabs.HasKey(page := this.GetDomainName(obj.url)) ) {
bindFunc := this.pageSettings.HasKey(page)
this.tabs[page] := { "pInst": New this.ChromeInst.Page(obj.webSocketDebuggerUrl
, bindFunc ? Func(this.pageSettings[page].funcName) : ""
, ObjBindMethod(this,"FreeConnection")) ; Delete this parameter for work
, "title": obj.title, "id": obj.id }
(bindFunc && this.tabs[page].pInst.Call("Console.enable"))
this.SetRootPage(page)
} (pageIndex++ == 1 && this_page := page)
}
} this.page := this_page
}
FreeConnection() {
this.GetTabs()
if (!this.page) {
ExitApp
} for k, t in this.tabs {
if (!t.pInst.Connected) {
OutputDebug,% Format("Closed tab '{}'", k)
this.tabs.Delete(k)
}
}
}
GetDomainName(d) {
return RegExReplace(d, "https?://([w|p|info|forum]+\.)?([\w-]*)\..*", "$2")
}
PageNavigate(address, page := "") {
this.page := page ? page : this.page
this.tabs[this.page].pInst.WaitForLoad()
this.tabs[this.page].pInst.Call("Page.navigate", {"url": address})
this.tabs[this.page].pInst.WaitForLoad()
if (this.page != this.GetDomainName(address)) {
this.tabs[this.page].pInst.Disconnect()
this.tabs.Delete(this.page)
this.GetTabs()
}
}
Quit(isDone := true, recycleProfile := false) {
OutputDebug,Quit: Close the Browser
if (isDone) {
try
this.tabs[this.page].pInst.Call("Browser.close")
catch
this.ChromeInst.Kill()
}
; |=> Next code is unreachable
OutputDebug,Disconnect
for k, t in this.tabs
t.pInst.Disconnect()
OutputDebug,Delete_Profile
if (recycleProfile) {
fPath := Format("{1}\{2}",A_ScriptDir,this.ProfilePath)
FileRemoveDir,% fPath, 1
i := 0
while (i < 10, i++) {
Sleep, 1000
if (FileExist(fPath))
FileRemoveDir,% fPath, 1
else
break
}
}
OutputDebug,Finish
}
}
App Pahs — App PathsGeekDude wrote:Code: Select all
if (ChromePath == "") RegRead, ChromePath, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Pahs\chrome.exe
I have the same issue on my Win 7 64 AHK 64.KusochekDobra wrote:I tried to add to my code processing event "OnExit" ... it turned out that exit from program is unreachable.
Code: Select all
#include Chrome.ahk
; Create an instance of the Chrome class using
; the folder ChromeProfile to store the user profile
FileCreateDir, ChromeProfile
ChromeInst := new Chrome("ChromeProfile")
; Connect to the newly opened tab and navigate to another website
; Note: If your first action is to navigate away, it may be just as
; effective to provide the target URL when instantiating the Chrome class
PageInst := ChromeInst.GetPage()
PageInst.Call("Page.navigate", {"url": "https://autohotkey.com/"})
PageInst.WaitForLoad()
; Execute some JavaScript
PageInst.Evaluate("alert('Hello World!');")
; Close the browser (note: this closes *all* pages/tabs)
PageInst.Call("Browser.close")
PageInst.Disconnect()
ExitApp
return
Make sure you're downloading the release file "Chrome.ahk_vX.Y.zip" from the releases page, not the source code. As you have noticed, GitHub does not include submodules (i.e. AutoHotkey-JSON and WebSocket.ahk) in its source downloads. The release has all the #Include's built in.mgroen wrote:Hi, I'm new to automating Chrome with Autohotkey. If I run this script (see below), I get the error "Websocket.ahk cannot be opened"
Anybody able to assist me?
No, that's what Selenium is. There are other tutorials on this forum for using Selenium with AHK as the 3rd party software, but you can use it with any programming language.ocnuybear wrote:Can Chrome.ahk be compiled into a stand alone DLL & called from 3rd party software?
I'm not sure what the exact rules chrome uses are for showing the button in a loading state, but typically the approach you want to take in this situation is to wait for the elements you want to interact to have finished loading. Depending on how the page is built the way to do this can very a lot.Koiu wrote:How to wait until all elements visible?
I try everything but i dont know how to make my script wait until all elements visible
- I try "PageInst.Evaluate("document.readyState")" to make sure the state page is " Complete" but the button still loading
- i try " PageInst.WaitForLoad()" and the button still loading
i really appreciate if anyone can help me. Thanks
Hi, you can add --remote-debugging-port=9222 on a shortcut properties after "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" or wherever you chrome path is for you.euras wrote:It may sound stupid, but I'm not a Chrome user and I dont have a clue how do I need to start Chrome in Debug mode? Can someone tell me or give a link where it's showed up?
I actually delt with this a while back and after talking to GeekDude about it, I realized, I was calling a new version of the class every time, so it would fail after about 5 versions of the class were created.bmilcs wrote:And as I wear out my welcome here, I think I've found a bug of some type. After I make a dozen or so DOM JS calls, AHK locks up and this is what I'm seeing for output:
Those are the last lines every single time it locks up. I've tried running the same getelementby syntax, which I know works for a fact, several times and it locks up at the same point every time.Code: Select all
037: if i := InStr("{[", ch) 047: if InStr("}]", ch) 049: ObjRemoveAt(stack, 1) 050: next := stack[1]==tree ? "" : is_arr[stack[1]] ? ",]" : ",}" 051: } 134: } 010: While,( (ch := SubStr(src, ++pos, 1)) != "" ) 136: Return,tree[1] ---- E:\autohotkey\Infraware\Chrome\Chrome.ahk 316: fnCallback := this.fnCallback 317: if (newData := %fnCallback%(data)) 320: if this.responses.HasKey(data.ID) 322: } 329: } (0.91)
;-----------------------------------------------------------------------------------------------------------------------------
EDIT: SOLVED.
After hours of tinkering with the code and browsing the Chrome DevTools page, I stumbled upon Page.Disconnect(). Apparently, the connection with Chrome was hitting the max allotment of time or only allows for X amount of actions per connection.Code: Select all
PageInst.Disconnect()
I added this to the end of the cycle of actions that I perform. This has completely fixed all issues I was having in regards to AHK freezing up after X amount of lines or time passed.
Hopefully this helps someone <3
The syntax