Rufaydium WebDriver 1.7.2 (no selenium/websocket)

Post your working scripts, libraries and tools for AHK v1.1 and older
wineguy
Posts: 9
Joined: 03 Dec 2019, 16:26

Re: Rufaydium WebDriver (no selenium/websocket)

Post by wineguy » 06 May 2022, 16:19

Nixcalo wrote:
02 May 2022, 07:46
It may be a stupid question, but how do I get Rufaydium to open an Edge session instead of a Chrome one?
Untested, but presumably to need the EdgeWebDriver instead of ChromeWebDriver, which I think is available here...
https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Whether or not that is a like-for-like drop in replacement for Chrome with Rufaydium is not tested yet.

User avatar
Xeo786
Posts: 759
Joined: 09 Nov 2015, 02:43
Location: Karachi, Pakistan

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Xeo786 » 07 May 2022, 02:01

AHK_user wrote:
06 May 2022, 13:49
Great work!

May I propose to include this usefull piece of code of mine that downloads the driver automatically if the driver is not found or if the version is wrong. Why bothering figuring out if what the version of chrome is and where to download the driver? :lol: :lol: :lol:

It does some assumptions about the location of the ChromeDriver.exe and Chrome.exe, but I think they are acceptable.
EDITED POST: It looks in the registry for the location of Chrome.exe

I would include it in the driver definition, if the first parameter of RunDriver is empty, just apply this...

Code: Select all

#SingleInstance force
ChromeDriver_Update()

return

ChromeDriver_Update(Dir_Chromedriver:=""){
	; Function Updates the Chromedriver by checking the versions and downloading the latest chromedriver.
	; Written by AHK_User
	; Thanks to tmplinshi

	Dir_Chromedriver := Dir_Chromedriver="" ? (FileExist(A_ScriptDir "\chromedriver.exe") ? A_ScriptDir "\chromedriver.exe" : "")
	Dir_Chromedriver := Dir_Chromedriver="" ? RegexReplace(A_MyDocuments,"^(.*)\\.*","$1") "\AppData\Local\Google\Chrome\chromedriver.exe" : Dir_Chromedriver
	SplitPath, Dir_Chromedriver, , Folder_Chromedriver
	
	if FileExist(Dir_Chromedriver){
		; Get Chromedriver version
		Version_ChromeDriver := RunHide("""" Dir_Chromedriver """ --version")
		Version_ChromeDriver := RegexReplace(Version_ChromeDriver, "[^\d]*([\.\d]*).*", "$1")
	} else{
		Version_ChromeDriver := "Error"
	}
	
	RegRead, File_ChromeExe, % "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Chrome.exe"
	if (File_ChromeExe=""){
		MsgBox, Failed to find the chrome.exe directory`nCurrent thread will exit.
		Exit
	}

	FileGetVersion, Version_Chrome, % File_ChromeExe
	Version_Chrome_ := RegexReplace(Version_Chrome, "\.\d+$")
	Version_Chromedriver_ := RegexReplace(Version_Chromedriver, "\.\d+$")
	; Check if versions are equal
	if (Version_Chrome_=Version_Chromedriver_){
		; Versions are the same
		Return true
		MsgBox,68,ChromeDriver,Current Chromedriver is same as Chromeversion.`nDo you still want to download?
		IfMsgBox, No 
		{
			exit
		}
	}

; Find the matching Chromedriver
	oHTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	oHTTP.Open("GET", "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_"  Version_Chrome_, true)
	oHTTP.Send()
	oHTTP.WaitForResponse()
	Version_Chromedriver := oHTTP.ResponseText
	
	if InStr(Version_Chromedriver, "NoSuchKey"){
		MsgBox,16,Testing,Error`nVersion_Chromedriver
		return
	}
	
; Download the Chromedriver
	Url_ChromeDriver := "https://chromedriver.storage.googleapis.com/" Version_Chromedriver "/chromedriver_win32.zip"
	URLDownloadToFile, %Url_ChromeDriver%,  %A_ScriptDir%/chromedriver_win32.zip
	
; Unzip Chromedriver_win32.zip
	fso := ComObjCreate("Scripting.FileSystemObject")
	AppObj := ComObjCreate("Shell.Application")
	FolderObj := AppObj.Namespace(A_ScriptDir "\chromedriver_win32.zip")

	FileCreateDir, Folder_Chromedriver "\Backup"
	FileMoveDir, Dir_Chromedriver, Folder_Chromedriver "\Backup\", 1
	FileObj := FolderObj.ParseName("chromedriver.exe")
	AppObj.Namespace(Folder_Chromedriver "\").CopyHere(FileObj, 4|16)
	; Clean up the zipfile
	FileDelete, % A_ScriptDir "\chromedriver_win32.zip"
	return true
}

RunHide(Command) {
	dhw := A_DetectHiddenWindows
	DetectHiddenWindows, On
	Run, %ComSpec%,, Hide, cPid
	WinWait, ahk_pid %cPid%
	DetectHiddenWindows, %dhw%
	DllCall("AttachConsole", "uint", cPid)

	Shell := ComObjCreate("WScript.Shell")
	Exec := Shell.Exec(Command)
	Result := Exec.StdOut.ReadAll()

	DllCall("FreeConsole")
	Process, Close, %cPid%
	Return Result
}
I would have written something like this but Rufaydium supports multiple drives,
Rufaydium fully supports ChromeDriver and EdgeDriver, there are few non W3C commands which are not supported for drives like Firefox's geckodriver, causing methods (based on getSessions() like getSessionByUrl() getSessionByTitle()) not work, I need to add auto-download driver supports for multiple driver from different websites and this would complicate stuff for newbies.
btw your work is awesome, Thank you :D
"When there is no gravity, there is absolute vacuum and light travel with no time" -Game changer theory

AHK_user
Posts: 515
Joined: 04 Dec 2015, 14:52
Location: Belgium

Re: Rufaydium WebDriver (no selenium/websocket)

Post by AHK_user » 07 May 2022, 02:52

Xeo786 wrote:
07 May 2022, 02:01
AHK_user wrote:
06 May 2022, 13:49
Great work!

May I propose to include this usefull piece of code of mine that downloads the driver automatically if the driver is not found or if the version is wrong. Why bothering figuring out if what the version of chrome is and where to download the driver? :lol: :lol: :lol:

It does some assumptions about the location of the ChromeDriver.exe and Chrome.exe, but I think they are acceptable.
EDITED POST: It looks in the registry for the location of Chrome.exe

I would include it in the driver definition, if the first parameter of RunDriver is empty, just apply this...
I would have written something like this but Rufaydium supports multiple drives,
Rufaydium fully supports ChromeDriver and EdgeDriver, there are few non W3C commands which are not supported for drives like Firefox's geckodriver, causing methods (based on getSessions() like getSessionByUrl() getSessionByTitle()) not work, I need to add auto-download driver supports for multiple driver from different websites and this would complicate stuff for newbies.
btw your work is awesome, Thank you :D
@Xeo786:
I guess I could also make something similar for Edge, so we have the most popular browsers covered:

Driver := new RunDriver("ChromeDriver") ; check and update ChromeDriver
Driver := new RunDriver("EdgeDriver") ; check and update EdgeDriver
Driver := new RunDriver(A_Scriptdir "\EdgeDriver.exe") ; use specific file

The original function to use a specific file would still exist, but I auto-updating is usefull.

Alternative, I could return the path of the driver if successfull and write an alternative function to replace RunDriver() with RunAutoDriver().
My guess is that this would be more userfriendly, as the users do not need to download the driver manually anymore. It would be nice if it was included in the standard script.

Example of a working RunAutoDriver() that returns the Rufaydium driver (for now only Chrome)

Code: Select all

#SingleInstance force
Dir_Chromedriver :=  RegexReplace(A_MyDocuments,"^(.*)\\.*","$1") "\AppData\Local\Google\Chrome\chromedriver.exe"
FileGetVersion, Version_ChromeDriver, % Dir_Chromedriver
MsgBox, % Version_ChromeDriver
; ChromeDriver_Update()

return

ChromeDriver_Update(Dir_Chromedriver:=""){
	; Function Updates the Chromedriver by checking the versions and downloading the latest chromedriver.
	; Written by AHK_User
	; Thanks to tmplinshi

	Dir_Chromedriver := Dir_Chromedriver="" ? (FileExist(A_ScriptDir "\chromedriver.exe") ? A_ScriptDir "\chromedriver.exe" : "")
	Dir_Chromedriver := Dir_Chromedriver="" ? RegexReplace(A_MyDocuments,"^(.*)\\.*","$1") "\AppData\Local\Google\Chrome\chromedriver.exe" : Dir_Chromedriver
	SplitPath, Dir_Chromedriver, , Folder_Chromedriver
	
	if FileExist(Dir_Chromedriver){
		; Get Chromedriver version
		Version_ChromeDriver := RunHide("""" Dir_Chromedriver """ --version")
		Version_ChromeDriver := RegexReplace(Version_ChromeDriver, "[^\d]*([\.\d]*).*", "$1")
	} else{
		Version_ChromeDriver := "Error"
	}
	
	RegRead, File_ChromeExe, % "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Chrome.exe"
	if (File_ChromeExe=""){
		MsgBox, Failed to find the chrome.exe directory`nCurrent thread will exit.
		Exit
	}

	FileGetVersion, Version_Chrome, % File_ChromeExe
	Version_Chrome_ := RegexReplace(Version_Chrome, "\.\d+$")
	Version_Chromedriver_ := RegexReplace(Version_Chromedriver, "\.\d+$")
	; Check if versions are equal
	if (Version_Chrome_=Version_Chromedriver_){
		; Versions are the same
		Return Dir_Chromedriver
		MsgBox,68,ChromeDriver,Current Chromedriver is same as Chromeversion.`nDo you still want to download?
		IfMsgBox, No 
		{
			exit
		}
	}

; Find the matching Chromedriver
	oHTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	oHTTP.Open("GET", "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_"  Version_Chrome_, true)
	oHTTP.Send()
	oHTTP.WaitForResponse()
	Version_Chromedriver := oHTTP.ResponseText
	
	if InStr(Version_Chromedriver, "NoSuchKey"){
		MsgBox,16,Testing,Error`nVersion_Chromedriver
		Exit
	}
	
; Download the Chromedriver
	Url_ChromeDriver := "https://chromedriver.storage.googleapis.com/" Version_Chromedriver "/chromedriver_win32.zip"
	URLDownloadToFile, %Url_ChromeDriver%,  %A_ScriptDir%/chromedriver_win32.zip
	
; Unzip Chromedriver_win32.zip
	fso := ComObjCreate("Scripting.FileSystemObject")
	AppObj := ComObjCreate("Shell.Application")
	FolderObj := AppObj.Namespace(A_ScriptDir "\chromedriver_win32.zip")

	FileCreateDir, Folder_Chromedriver "\Backup"
	FileMoveDir, Dir_Chromedriver, Folder_Chromedriver "\Backup\", 1
	FileObj := FolderObj.ParseName("chromedriver.exe")
	AppObj.Namespace(Folder_Chromedriver "\").CopyHere(FileObj, 4|16)
	; Clean up the zipfile
	FileDelete, % A_ScriptDir "\chromedriver_win32.zip"
	return Dir_Chromedriver
}

RunHide(Command) {
	dhw := A_DetectHiddenWindows
	DetectHiddenWindows, On
	Run, %ComSpec%,, Hide, cPid
	WinWait, ahk_pid %cPid%
	DetectHiddenWindows, %dhw%
	DllCall("AttachConsole", "uint", cPid)

	Shell := ComObjCreate("WScript.Shell")
	Exec := Shell.Exec(Command)
	Result := Exec.StdOut.ReadAll()

	DllCall("FreeConsole")
	Process, Close, %cPid%
	Return Result
}

RunAutoDriver(Driver:=""){
	Driver := ChromeDriver_Update(Driver)
	Return new RunDriver(Driver)
}

User avatar
Xeo786
Posts: 759
Joined: 09 Nov 2015, 02:43
Location: Karachi, Pakistan

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Xeo786 » 07 May 2022, 03:56

AHK_user wrote:
07 May 2022, 02:52
@Xeo786:
I guess I could also make something similar for Edge, so we have the most popular browsers covered:

Driver := new RunDriver("ChromeDriver") ; check and update ChromeDriver
Driver := new RunDriver("EdgeDriver") ; check and update EdgeDriver
Driver := new RunDriver(A_Scriptdir "\EdgeDriver.exe") ; use specific file

The original function to use a specific file would still exist, but I auto-updating is usefull.

Alternative, I could return the path of the driver if successfull and write an alternative function to replace RunDriver() with RunAutoDriver().
My guess is that this would be more userfriendly, as the users do not need to download the driver manually anymore. It would be nice if it was included in the standard script.

Example of a working RunAutoDriver() that returns the Rufaydium driver (for now only Chrome)
Thanks for you code but we can get chrome latest version from driver therefore
I just Fixed NewSession() for error handling it will help script to to find out when to download driver

Code: Select all

	NewSession()
	{
		if !this.capabilities
			this.capabilities := capabilities.Simple
		
		k := this.Send( this.DriverUrl "/session","POST",this.capabilities,1)
		if k.error
		{
			msgbox, 48,Rufaydium WebDriver Support Error,% k.error "`n`n" k.message
			return k
		}
		window := []
		window.debuggerAddress := StrReplace(k.capabilities["goog:chromeOptions"].debuggerAddress,"localhost","http://127.0.0.1")
		window.address := this.DriverUrl "/session/" k.SessionId
		return new Session(window)
	}
This is how auto-download would be setup, Please download latest Rufaydium

Code: Select all

ChromeDriver := A_ScriptDir "\chromedriver.exe"
Driver := new RunDriver(ChromeDriver)
Chrome := new Rufaydium(Driver)
Page := Chrome.NewSession()
if(Page.error = "session not created")
{
	Driver.Exit()
	x := ChromeDriver_Update(ChromeDriver, page.message)
}
if x
	msgbox, Driver downloaded sucessfuly
return	

ChromeDriver_Update(DriverLocation, ErrorMessage)
{
	RegExMatch(ErrorMessage,"Chrome version ([\d.]+).*\n.*browser version is (\d+.\d+.\d+)",bver)
	
	; Find the matching Chromedriver
	oHTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
	oHTTP.Open("GET", "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_"  bver2, true)
	oHTTP.Send()
	oHTTP.WaitForResponse()
	Version_Chromedriver := oHTTP.ResponseText
	
	if InStr(Version_Chromedriver, "NoSuchKey"){
		MsgBox,16,Testing,Error`nVersion_Chromedriver
		return false
	}
	
	; Download the Chromedriver
	Url_ChromeDriver := "https://chromedriver.storage.googleapis.com/" Version_Chromedriver "/chromedriver_win32.zip"
	URLDownloadToFile, %Url_ChromeDriver%,  %A_ScriptDir%/chromedriver_win32.zip
	; Unzip Chromedriver_win32.zip
	fso := ComObjCreate("Scripting.FileSystemObject")
	AppObj := ComObjCreate("Shell.Application")
	FolderObj := AppObj.Namespace(A_ScriptDir "\chromedriver_win32.zip")
	if !FileExist(A_ScriptDir "\Backup")
		FileCreateDir, % A_ScriptDir "\Backup"
	
	while FileExist(DriverLocation)
	{
		FileMove, % DriverLocation, % A_ScriptDir "\Backup\Chromedriver Version " bver1 ".exe", 1
		msgbox, % DriverLocation "`n" A_ScriptDir "\Backup\Chromedriver Version " bver1 ".exe"
	}
	
	FileObj := FolderObj.ParseName("chromedriver.exe")
	AppObj.Namespace(A_ScriptDir "\").CopyHere(FileObj, 4|16)
	; Clean up the zipfile
	FileDelete, % A_ScriptDir "\chromedriver_win32.zip"
	return true
}
edited:
Above function can be put used inside WDM.ahk and can be used as you suggest, I am now thinking about your idea but idk where to start I try implementing above function but other drivers comes in 64bit, and we need to cover multiple version and complied types.

edited2:
Made few changes and you code have been auto-download chromedriver have been implemented, well I will make same thing for edge and firefox but I am busy with my job right now.
Thank you :D
"When there is no gravity, there is absolute vacuum and light travel with no time" -Game changer theory

User avatar
RaptorX
Posts: 372
Joined: 06 Dec 2014, 14:27
Contact:

Re: Rufaydium WebDriver (no selenium/websocket)

Post by RaptorX » 07 May 2022, 09:47

AHK_user wrote:
06 May 2022, 16:00
RaptorX wrote:
06 May 2022, 15:24
AHK_user wrote:
06 May 2022, 13:49
It does some assumptions about the location of the ChromeDriver.exe and Chrome.exe, but I think they are acceptable.
I think the exact location of browsers can be found on the registry. I had some code a while ago that retrieved the defaults browser location but it could be tweaked to find the exact location of any installed program.
@RaptorX: Thanks for the tip, I found the location and updated my previous post. :D

Code: Select all

RegRead, File_ChromeExe, % "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Chrome.exe"
glad to be of help, thats exactly the registry key i was referring to. :)
Projects:
AHK-ToolKit

tangshun
Posts: 1
Joined: 07 May 2022, 10:11

Re: Rufaydium WebDriver (no selenium/websocket)

Post by tangshun » 07 May 2022, 10:18

:D How to click the button by searching the text. In selenium, my code is driver.findElementByXpath("//*[contains(text(), 'hello')]") .click()

User avatar
RaptorX
Posts: 372
Joined: 06 Dec 2014, 14:27
Contact:

Re: Rufaydium WebDriver (no selenium/websocket)

Post by RaptorX » 07 May 2022, 10:39

tangshun wrote:
07 May 2022, 10:18
:D How to click the button by searching the text. In selenium, my code is driver.findElementByXpath("//*[contains(text(), 'hello')]") .click()
I use:

Code: Select all

driver.querySelector('.class.anotherclass').click()
Projects:
AHK-ToolKit

ahk7
Posts: 575
Joined: 06 Nov 2013, 16:35

Re: Rufaydium WebDriver (no selenium/websocket)

Post by ahk7 » 07 May 2022, 10:40

tangshun wrote:
07 May 2022, 10:18
:D How to click the button by searching the text. In selenium, my code is driver.findElementByXpath("//*[contains(text(), 'hello')]") .click()
Session.getElementsbyXpath("//*[contains(text(), 'hello')]")[1].click() :?:

jokerjy
Posts: 2
Joined: 30 Apr 2022, 04:31

Re: Rufaydium WebDriver (no selenium/websocket)

Post by jokerjy » 07 May 2022, 23:17

Hello
Is it possible to control the debug port in chrome that already exists?
I tried the selenium code below but it doesn't work
Is there any other way to debug it?

Code: Select all

run % "chrome.exe --start-maximized -incognito --remote-debugging-port=9222"
driver.SetCapability("debuggerAddress", "127.0.0.1:9222")
driver.Start()
Last edited by jokerjy on 08 May 2022, 07:44, edited 3 times in total.

User avatar
hotcheesesoup
Posts: 34
Joined: 08 May 2022, 01:41

Re: Rufaydium WebDriver (no selenium/websocket)

Post by hotcheesesoup » 08 May 2022, 01:59

Milchmann wrote:
02 May 2022, 06:05
But I still can't see which tab is the currently focused one.
Bert
Hope following code would resolve issue

Code: Select all

Driver := new RunDriver(ChromeDriver) ; running driver
Chrome := new Rufaydium(Driver) ; this will return control over Browser
Session := Chrome.getSession(1) ; getting session by number as we do not know page title or url 
; checking that session title and url
msgbox, % Session.title() "`n" Session.url() 
Hi Xeo786,

I found this post last night, and it is super impressive! I've used Chrome.ahk, and I feel this improves on a lot of it's shortcomings, especially in regards to that dang Security Error that would show up even after you thought it was resolved.

As for Milchmann's inquiry, I have the same question. How can we simply make the Session update to the current tab, regardless of URL, Title, or being opened manually? The solutions you provided don't really seem to help.

You mention getting the handles with TabsDetail := Session.GetTabs(). Is it possible to get the tab Titles or URLs in this fashion, and not just the handle, or at least a way to get the handle of your current tab even if not the active Session, maybe with something like Acc.ahk, to actually compare to the retrieved handles? Looping through each tab with Session.switch() to get the Title and URL doesn't really solve the problem.

With Internet Explorer, I use a function called WBGet() which, when paired with a SetTimer, will constantly poll IE for the current tab to interact with it. Chrome.ahk has something similar with GetPage().

Code: Select all

// From Chrome.ahk //
GetPage(Index:=1, Type:="page", fnCallback:="", fnClose:="")
	{
		return this.GetPageBy("type", Type, "exact", Index, fnCallback, fnClose)
	}
You can dig deeper into it if you think it is worthwhile, but this would be hugely helpful and seems like a no-brainer to implement to me.

Hope to hear back from you, and thanks for making this awesome new tool.
-HCS

Milchmann
Posts: 112
Joined: 05 Nov 2016, 08:50

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Milchmann » 08 May 2022, 03:30

Hi Xeo786,
As for Milchmann's inquiry, I have the same question. How can we simply make the Session update to the current tab, regardless of URL, Title, or being opened manually? The solutions you provided don't really seem to help.
An example to explain:
I have started a session with Rufandium.ahk. Now I open a page manually:
viewtopic.php?f=37&t=67213

And another one is started by me manually:
https://www.w3.org/TR/webdriver2/#commandsqid=1651997396&rnid=1040660&s=fashion-womens-intl-ship&sr=1-3
Now I want for this W3.org Link with your function

Code: Select all

f10:: ; save page to pdf
Driver := new RunDriver(ChromeDriver)
Chrome := new Rufaydium(Driver) ; Capabilities only affect new sessions 
Chrome.capabilities := Capabilities.headless ; added ChromeProfile in Capabilities and tested PDF print and tried all possible args all seems to fail idk its driver error 
msgbox " pdftest := currently activated tab"
pdftest.Print(a_desktop "/pdtest.pdf",PrintOptions.A4_Default)
save the page as pdf.
How can I make sure that this page is really saved with your function? This is the currently activated tab.

to viewtopic.php?p=460739#p460739:
I have packed the individual questions into examples. Maybe you try these and can confirm the errors?

Code: Select all

ChromeDriver := A_ScriptDir "\chromedriver.exe"
Driver := new RunDriver(ChromeDriver) ; running driver
Driver.visible := true ; make Driver CMD window visible 
Chrome := new Rufaydium(Driver) ; this will return control over Browser
Page := Chrome.getSessionByUrl("https://sketch.io/sketchpad/") ; try to get if already there
cc := Page.Detail()
msgbox % json.dump(cc)  ; does not work
if !IsObject(Page) ; checking if page found or not 
{
	Page := Chrome.NewSession() ; creating new session 
	Page.Navigate("https://sketch.io/sketchpad/")
	msgbox, close all messages on sketch.io and press f1 again
	return
}
Page.CDP.Document()
Element := Page.querySelectorAll("sketch-tool")[3]
msgbox, % "`nOuterhtml: `n" Page.CDP.querySelectorAll("sketch-tool")[3].outerhtml 
msgbox, % "dispayed not work, false results for enabled and displayed`n`n`ndisplayed: " Element.displayed() "`nEnabled: " Element.enabled() "`nName: " Element.Name()         ;    

Page.querySelectorAll("sketch-tool")[3].click() ; click on pencil icon
while !Page.QuerySelectorAll("sketch-gridviewtrigger")[1].displayed() ; wait for menu to get visible using dropdown element visibility 
	sleep, 200

Sleep, 1000
msgbox, % "dispayed not work, right results for enabled?`n`n`ndisplayed: " Element.displayed() "`nEnabled: " Element.enabled() "`nName: " Element.Name()  
And last but not least devicePixelRatio:

Code: Select all

Doesn't work correctly for example, rounding error?   console:	        Page.ExecuteSync("return window.devicePixelRatio"):

zoom 100%: 								1									1
							
zoom 90%:								0.8999999761581421					01
							
zoom 67%:								0.6666666865348816					01
zoom 150%:								1,5									02


thanks for your work
Last edited by Milchmann on 09 May 2022, 01:22, edited 1 time in total.

User avatar
hotcheesesoup
Posts: 34
Joined: 08 May 2022, 01:41

Re: Rufaydium WebDriver (no selenium/websocket)

Post by hotcheesesoup » 08 May 2022, 23:13

I took a crack at this using the Acc.ahk library to grab the current tab's URL whether it is the active Session or not. I'm pretty happy with the results, but I'm sure somebody else could do it better.

I'm not sure if GetElementByName(AccObj, name) is standard to the library. I might have found it somewhere else, so including below just in case.

Using a timer, I compare the current tab's URL against the Session URL (which could be a different tab or even in a different window).

Annoyingly, they both return different values for the current URL. Acc.ahk returns "example.com", but Session.URL() returns "http://www.example.com/". Acc.ahk returns what is actually showing in Chrome, and since it doesn't include the full URL by default, it doesn't perfectly match. Even selecting "Always show full URLs" doesn't give an exact match since it doesn't include the "/" on the end.

Therefore, I opted to simply check if the Session.URL() contains the Acc.ahk result. Does "http://www.example.com/" contain "example.com"? Sure, and that's close enough for me!

Code: Select all

ChromeDriver := A_ScriptDir "\chromedriver.exe"
Driver := new RunDriver(ChromeDriver) 
Chrome := new Rufaydium(Driver)
Chrome.capabilities := Capabilities.ChromeDefault 

; I'm not sure if I need global here, but doesn't seem to hurt anything.
global Session := Chrome.NewSession()
Session.Navigate("http://www.example.com/")
SetTimer, CheckCurrentTab, 16
return

CheckCurrentTab:
Session.GetCurrentTab(Session.URL())

; Turns the body of the current tab yellow so I know it is actually the current Session.
Session.CDP.Document()
Session.CDP.Evaluate("document.getElementsByTagName('body')[0].style.backgroundColor = 'lemonchiffon';")
return

GetElementByName(AccObj, name) {
	if (AccObj.accName(0) = name)
		return AccObj

	for k, v in Acc_Children(AccObj)
		if IsObject(obj := GetElementByName(v, name))
		return obj
}	

Code: Select all

GetCurrentTab(currentURL)
	{
        ; Grab handle of current Chrome window.
		hwndChrome := WinActive("ahk_class Chrome_WidgetWin_1")

		; Create Acc connection with Chrome handle.
		AccChrome := Acc_ObjectFromWindow(hwndChrome)

		; Grab the contents of the address bar in Chrome.
		AccAddressBar := GetElementByName(AccChrome, "Address and search bar")

		; This is the Chrome URL: "example.com"
		AccURL := AccAddressBar.accValue(0)

		; Does "http://www.example.com" contain "example.com"? Yes, so no need to update the Session.
		; If AccURL instead contains "google.com", then we switch the Session to our CURRENT Google tab.

		if !InStr(currentURL, AccURL) && InStr(AccURL, ".com")
			Session.SwitchbyURL(AccURL)
			
		; The InStr(AccURL, ".com") part is simply there to not trigger the evaluation while you're typing a URL in a new tab.
		; Otherwise, it triggers constantly and is annoying. I'm sure there's a better way to do this.			
	}
I'm sure there is room for improvement, especially since this won't work correctly with two identical tabs, but I thought I'd post my results since they seem like a good start to get what I'm looking for.

Thanks!
-HCS

User avatar
Xeo786
Posts: 759
Joined: 09 Nov 2015, 02:43
Location: Karachi, Pakistan

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Xeo786 » 09 May 2022, 03:06

Milchmann wrote:
08 May 2022, 03:30
How can I make sure that this page is really saved with your function? This is the currently activated tab.
hotcheesesoup wrote:
08 May 2022, 01:59
You mention getting the handles with TabsDetail := Session.GetTabs(). Is it possible to get the tab Titles or URLs in this fashion
Actually WebDriver written in such way you can use Session.url() and Session.Title() to get active title
but you cannot get all tabs detail using Webdriver Basic, you need to Switch evey tab one by one and getting active url and title
but there is Session.detail() it was not working and I just fixed it
jokerjy wrote:
07 May 2022, 23:17
Is it possible to control the debug port in chrome that already exists?
Unlike Selenium, Rufaydium has its own methods and are not hard you just need to figure out how to use them,
You just need to add chrome cmd parameter "arg" into are
Please look into capabilities-class https://github.com/Xeo786/Rufaydium-Webdriver#capabilities-class how to make profile and load that profile
arg should be

Code: Select all

"args": ["--remote-debugging-port=9222"]
Milchmann wrote:
08 May 2022, 03:30
An example to explain:
I have started a session with Rufandium.ahk. Now I open a page manually:
viewtopic.php?f=37&t=67213

And another one is started by me manually:
https://www.w3.org/TR/webdriver2/#commandsqid=1651997396&rnid=1040660&s=fashion-womens-intl-ship&sr=1-3
Now I want for this W3.org Link with your function
Webdriver can only access those Session/Pages created by Webdriver with a condition that driver kept running, if we close or restart driver we will lose the ability to control those webapge this is the reason I have commented out / disabled all __delete() methods in Rufaydium
I have also mentioned that in documents https://github.com/Xeo786/Rufaydium-Webdriver#script-reloading
Milchmann wrote:
08 May 2022, 03:30
And last but not least devicePixelRatio:

Code: Select all

Doesn't work correctly for example, rounding error?   console:	        Page.ExecuteSync("return window.devicePixelRatio"):
zoom 100%: 								1									1
zoom 90%:								0.8999999761581421					01
zoom 67%:								0.6666666865348816					01
zoom 150%:								1,5									02
have you tried following solution? which I suggested previously viewtopic.php?f=6&t=102616&start=60#p460741

Code: Select all

msgbox % round(Page.ExecuteSync("return window.devicePixelRatio") * 100,0) "%"
Milchmann wrote:
08 May 2022, 03:30
to viewtopic.php?p=460739#p460739:
I have packed the individual questions into examples. Maybe you try these and can confirm the errors?

Code: Select all

ChromeDriver := A_ScriptDir "\chromedriver.exe"
Driver := new RunDriver(ChromeDriver) ; running driver
Driver.visible := true ; make Driver CMD window visible 
Chrome := new Rufaydium(Driver) ; this will return control over Browser
Page := Chrome.getSessionByUrl("https://sketch.io/sketchpad/") ; try to get if already there
cc := Page.Detail()
msgbox % json.dump(cc)  ; does not work
if !IsObject(Page) ; checking if page found or not 
{
	Page := Chrome.NewSession() ; creating new session 
	Page.Navigate("https://sketch.io/sketchpad/")
	msgbox, close all messages on sketch.io and press f1 again
	return
}
Page.CDP.Document()
Element := Page.querySelectorAll("sketch-tool")[3]
msgbox, % "`nOuterhtml: `n" Page.CDP.querySelectorAll("sketch-tool")[3].outerhtml 
msgbox, % "dispayed not work, false results for enabled and displayed`n`n`ndisplayed: " Element.displayed() "`nEnabled: " Element.enabled() "`nName: " Element.Name()         ;    

Page.querySelectorAll("sketch-tool")[3].click() ; click on pencil icon
while !Page.QuerySelectorAll("sketch-gridviewtrigger")[1].displayed() ; wait for menu to get visible using dropdown element visibility 
	sleep, 200

Sleep, 1000
msgbox, % "dispayed not work, right results for enabled?`n`n`ndisplayed: " Element.displayed() "`nEnabled: " Element.enabled() "`nName: " Element.Name()  
as mentioned on top fixed Page.Detail() bug
just keep it at right place for safe side

Code: Select all

Page := Chrome.getSessionByUrl("https://sketch.io/sketchpad/") ; try to get if already there
if !IsObject(Page) ; checking if page found or not 
{
	Page := Chrome.NewSession() ; creating new session 
	Page.Navigate("https://sketch.io/sketchpad/")
	msgbox, close all messages on sketch.io and press f1 again
	return
}
cc := Page.Detail()
msgbox % json.dump(cc)  ; does not work
Dispayed is working just fine the page is written in such way that their displayed attribute returns false.

Code: Select all

msgbox, % "dispayed not work, false results for enabled and displayed`n`n`ndisplayed: " e := Element.displayed() "`nEnabled: " Element.enabled() "`nName: " Element.Name()
if E.error
	msgbox,  % E.error
"When there is no gravity, there is absolute vacuum and light travel with no time" -Game changer theory

Milchmann
Posts: 112
Joined: 05 Nov 2016, 08:50

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Milchmann » 09 May 2022, 08:47

Xeo786 wrote:
09 May 2022, 03:06
but you cannot get all tabs detail using Webdriver Basic, you need to Switch evey tab one by one and getting active url and title
Maybe there's a better way later. I currently have 9 TABS open and it takes a long time to switch to the right one. :D
Webdriver can only access those Session/Pages created by Webdriver with a condition that driver kept running, if we close or restart driver we will lose the ability to control those webapge this is the reason I have commented out
Web driver is active and so is the session. I only added 1 or more TABS manually. There was my wish to identify the active TAB without a switch and to continue working with active TAB.

Xeo786 wrote:
09 May 2022, 03:06
have you tried following solution? which I suggested previously viewtopic.php?f=6&t=102616&start=60#p460741
msgbox % round(Page.ExecuteSync("return window.devicePixelRatio") * 100,0) "%"
Have you tried this feature you suggested?
0,67,75,80,90, 100 and 125 = 100%
Zoom under 50 % = 0
zoom 125, 150, 200 = 200%
These are very roughly rounded values, which I needed more precisely. The console gives out the exact values.
Xeo786 wrote:
09 May 2022, 03:06
as mentioned on top fixed Page.Detail() bug
Thank You :bravo:
Dispayed is working just fine the page is written in such way that their displayed attribute returns false.
Thanks
Unfortunately, I've discovered another problem, or I'm not good enough.
No "value" values are output from "text areas" that are queried with Javascript.

Code: Select all

page.cdp.querySelectorAll("#ex123")[1].outerhtml
outputs:
<textarea class="text sr " wrap="off" id="ex123" cols="20" style="top:0px; left:55px; width:95px; height:21px;" rows="1" role="textbox"></textarea>
with $1.value in the console I get the correct value.

Code: Select all

page.cdp.querySelectorAll("#ex123")[1].value
returns 0.
Do you have an idea or do you need more information?

User avatar
Xeo786
Posts: 759
Joined: 09 Nov 2015, 02:43
Location: Karachi, Pakistan

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Xeo786 » 10 May 2022, 02:17

Milchmann wrote:
09 May 2022, 08:47
Maybe there's a better way later. I currently have 9 TABS open and it takes a long time to switch to the right one. :D
As far as I know Webdriver there is no way, you need to active that window in order to access window title and URL, but from CDP there might be some way, then you will not be able to access Webdriver Basic as I find no way to get Window ID from CDP, you can just use Session.CDP.call to do everything which is lengthy, will cover so many lines and so many calls will be used just to check page loading status, or you can just use Webdriver Basics which is easy but with one exception that it will constantly active that webdriver window.
Milchmann wrote:
09 May 2022, 08:47
Xeo786 wrote:
09 May 2022, 03:06
have you tried following solution? which I suggested previously viewtopic.php?f=6&t=102616&start=60#p460741
msgbox % round(Page.ExecuteSync("return window.devicePixelRatio") * 100,0) "%"
Have you tried this feature you suggested?
0,67,75,80,90, 100 and 125 = 100%
Zoom under 50 % = 0
zoom 125, 150, 200 = 200%
These are very roughly rounded values, which I needed more precisely. The console gives out the exact values.
I am clueless what is the issue but above code works for me :think:
Milchmann wrote:
09 May 2022, 08:47
Unfortunately, I've discovered another problem, or I'm not good enough.
No "value" values are output from "text areas" that are queried with Javascript.

Code: Select all

page.cdp.querySelectorAll("#ex123")[1].outerhtml
outputs:
<textarea class="text sr " wrap="off" id="ex123" cols="20" style="top:0px; left:55px; width:95px; height:21px;" rows="1" role="textbox"></textarea>
with $1.value in the console I get the correct value.

Code: Select all

page.cdp.querySelectorAll("#ex123")[1].value
returns 0.
Do you have an idea or do you need more information?
as you can see that HTML has no value / innerText attribute, but that that page might get value using JS, there for I suggest try use that same command in Session.CDP.Evaluate()

Code: Select all

msgbox, % Session.CDP.Evaluate("document.querySelector('textarea').value")
"When there is no gravity, there is absolute vacuum and light travel with no time" -Game changer theory

DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Rufaydium WebDriver (no selenium/websocket)

Post by DRocks » 10 May 2022, 21:34

Wow I have to test this as soon as possible. Been looking for that for the last 4 years. Learned Node.js and Go web scraping in the mean time, but using AHK has so many avantages over other languages. Thanks for the script ! It will surely be useful.

Milchmann
Posts: 112
Joined: 05 Nov 2016, 08:50

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Milchmann » 11 May 2022, 08:38

as you can see that HTML has no value / innerText attribute, but that that page might get value using JS, there for I suggest try use that same command in Session.CDP.Evaluate()

Code: Select all

msgbox, % Session.CDP.Evaluate("document.querySelector('textarea').value")
No values.
But I just see that an event (change ) must be called there so that "value" is read.
grafik.png
grafik.png (7.63 KiB) Viewed 3672 times
Strange is that it is read out automatically under Selenium, without me having to call a listener extra here.

Code: Select all

xxx := driver.findElementByID("ex123").Attribute("value")
How can I create and call the event for the textarea?

User avatar
Xeo786
Posts: 759
Joined: 09 Nov 2015, 02:43
Location: Karachi, Pakistan

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Xeo786 » 11 May 2022, 15:26

Milchmann wrote:
11 May 2022, 08:38
as you can see that HTML has no value / innerText attribute, but that that page might get value using JS, there for I suggest try use that same command in Session.CDP.Evaluate()

Code: Select all

msgbox, % Session.CDP.Evaluate("document.querySelector('textarea').value")
No values.
But I just see that an event (change ) must be called there so that "value" is read.
grafik.png

Strange is that it is read out automatically under Selenium, without me having to call a listener extra here.

Code: Select all

xxx := driver.findElementByID("ex123").Attribute("value")
How can I create and call the event for the textarea?
you can also dispatch event but with out your code and I can't tell what should be done.
sending null key sometimes dispatch event

Code: Select all

driver.findElementByID("ex123").sendkey(key.null)
of you can create JS code which creating onchange event and dispatches that event onto the element and Session.CDP.Evaluate(jscode) that js code

Code: Select all

js =
(
	const input = document.querySelector('textarea')
	input.dispatchEvent(new CustomEvent("change"))
)
Session.CDP.Evaluate(js)
but still I am not 100% sure until I inspect html page and look on to event listeners
"When there is no gravity, there is absolute vacuum and light travel with no time" -Game changer theory

Milchmann
Posts: 112
Joined: 05 Nov 2016, 08:50

Re: Rufaydium WebDriver (no selenium/websocket)

Post by Milchmann » 12 May 2022, 04:05

Milchmann wrote:
11 May 2022, 08:38
as you can see that HTML has no value / innerText attribute, but that that page might get value using JS, there for I suggest try use that same command in Session.CDP.Evaluate()

Code: Select all

msgbox, % Session.CDP.Evaluate("document.querySelector('textarea').value")
Almost right. :D

Code: Select all

msgbox, % Session.CDP.Evaluate("document.querySelector('textarea').value;").value
It works now.

Thanks
Last edited by Milchmann on 12 May 2022, 14:30, edited 1 time in total.

ahk7
Posts: 575
Joined: 06 Nov 2013, 16:35

Re: Rufaydium WebDriver (no selenium/websocket)

Post by ahk7 » 12 May 2022, 14:12

I tried out the latest version but now I get all sorts of WinHttp.WinHttpRequest errors from "WDM.ahk" while the previous version I had still works (I copied all new files into a new folder, chrome and webdriver match.
It starts the session alright but as soon as I try stuff like Session.getSessionByUrl(url) Session.title() I get these errors below. Something I'm missing?
Error in #include file WDM.ahk wrote:Source: WinHttp.WinHttpRequest
Description: The URL does not use a recognized protocol
---> 169: WebRequest.Open(Method, url, false)

Source: WinHttp.WinHttpRequest
Description: This method cannot be called until the Open method has been called
---> 170: WebRequest.SetRequestHeader("Content-Type","application/json")

Source: WinHttp.WinHttpRequest
Description: This method cannot be called until the Open method has been called
---> 175: WebRequest.Send()

etc
...

Post Reply

Return to “Scripts and Functions (v1)”