While AutoHotkey is an amazing tool for Web Scraping, many people complain about being limited to connecting with COM to IE. In the below videos I walk through how you can use AutoHotkey and Selenium to automate web scraping in virtually any browser you wish. 🙂
Update: 5/19/2020– While to the best of my knowledge Selenium still works, when automating Chrome, I recommend using GeekDude’s Chrome class. I have some examples of working with an older version of his Chrome class here.
Installing Selenium
In order to control Selenium with AutoHotkey you need to install the SeleniumBasic. The current version is 2.09.0 and can be downloaded here. Selenium is now on version 3 and there is a new SeleniumBasic version promised to be released soon which will connect to version 3 of Selenium. Make sure you download the WebDrivers of choice for your browsers.
If all of this sounds confusing, don’t feel bad. It is ridculous! I found this post which documents/clarifies much of the confusion (although Selenium 3 is now out)
Please note several people reported when installing Selenium Basic it did not install in the program files location (i.e. here: C:\Program Files\SeleniumBasic or C:\Program Files (x86)\SeleniumBasic). They also had problems getting Selenium to launch. I recommend you make sure Selenium installs into one of the Program Files location and also make sure you get the Selenium drivers installed. After install I had the following files on my computer:
- C:\Program Files\SeleniumBasic\operadriver.exe
- C:\Program Files\SeleniumBasic\chromedriver.exe
- C:\Program Files\SeleniumBasic\edgedriver.exe
- C:\Program Files\SeleniumBasic\iedriver.exe
After installing the Selenium Basic- Make sure you get the latest Chrome driver here and extract the “chromedriver.exe” into the folder where SeleniumBasic is installed. Also keeping your Chrome version up to date. Currently I’m running 64.0.3282.39 64-bit version of Chrome and am using a 32-bit version of Selenium Webdriver (as there is no 64 bit version of Selenium webdriver).
Here are some links you might want to review (but you’ll need to adapt them for your purposes)
- Send keys to value: ;Need to add “driver” e.g. .SendKeys(driver.Keys.ENTER)
- AutoHotkey Forum on Selenium
- 15 common commands
- general documentation
- Clicking elements
- Good PDF documentation
- Decent tutorial on Selenium
- ok tutorial on Selenium
Using AutoHotkey and Selenium across various browsers
This video I show two ways I’ve learned how to start-up the Selenium Webdriver with AutoHotkey.
driver:= ComObjCreate("Selenium.WebDriver") ;Web driver driver.Start("firefox","http://duckduckgo.com/") ;chrome, firefox, ie, phantomjs, edge driver.Get("/") driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver ;~ driver:= ComObjCreate("Selenium.IEDriver") ;Chrome driver ;~ driver:= ComObjCreate("Selenium.FireFoxDriver") ;Chrome driver driver.Get("http://duckduckgo.com/")
Tutorial showing how to start up and navigate with AutoHotkey and Selenium
Getting information from a page with Selenium and AutoHotkey
While there are a lot of similarities to data extraction in Selenium, there are quite a few differences as well. The below code is what I use in the following video. It demonstrates some ways that you can extract data from a web page via Selenium and AutoHotkey.
driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver driver.Get("https://the-automator.com/") ;!!!!DO NOT USE!!! driver.findElement(By.id("search_form_input_homepage")).SendKeys("hello") ; Java bindings of Selenium. !!!!DO NOT USE!!! MsgBox % driver.findElementByID("site-description").Attribute("innerText") ;note case sensitive MsgBox % driver.executeScript("return document.getElementById('site-description').innerText") MsgBox % driver.executeScript("return document.getElementById('site-description').outerHTML") MsgBox % driver.findElementByID("cat").Attribute("value") ;lowercase value MsgBox % driver.findElementsByName("cat").item[1].Attribute("outerHTML") MsgBox % driver.findElementsByName("cat").item[1].Attribute("textContent") MsgBox % driver.findElementsByName("cat").item[1].Attribute("innerText") MsgBox % driver.findElementsByName("cat").item[1].Attribute("option value") MsgBox % driver.findElementByName("s").Attribute("innerTEXT")
Setting information on a page
Selenium and AutoHotkey are pretty different in how you set information. Selenium has a “sendkeys” method which seems to be pretty reliable at triggering events on a page.
- Make sure you review this: Send keys to value: ;Note: you need to add “driver” e.g. .SendKeys(driver.Keys.ENTER)
driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver driver.Get("https://the-automator.com/") ;~ !!!!DO NOT USE!!! driver.findElement(By.id("search_form_input_homepage")).SendKeys("hello") ; Java bindings of Selenium. !!!!DO NOT USE!!! driver.findElementsByName("s").item[2].SendKeys("hello world") driver.findElementsByName("s").item[2].SendKeys(driver.Keys.ENTER) ;http://seleniumhome.blogspot.com/2013/07/how-to-press-keyboard-in-selenium.html MsgBox pause driver.executeScript("arguments[0].setAttribute('value', 'hello world')", driver.findElementsByName("s")) ;sets value driver.findElementsByName("cat").item[2].SendKeys("hello world") driver.findElementsByName("cat").item[1].click() ;1 based, not zero
Setting text & clicking items on a page with Selenium and AutoHotkey
Using your Chrome Profile (Avoiding the need to re-login to a site)
In this video I demonstrate how you can leverage your Chrome profile so you do not need to keep logging into a website with Chrome
driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver ; put this "chrome://version/" in the url in chrome to find path to profile ;https://stackoverflow.com/questions/25779027/load-default-chrome-profile-with-webdriverjs-selenium driver.SetProfile("H:\Temp\Chrome\Cache\cache\Default") ; 'Full path of the profile directory url:="https://www.linkedin.com/feed/?trk=" driver.Get(url)
Iterating over Objects with Selenium and AutoHotkey
In the below video I demonstrate some of the important differences when iterating over objects with Selenium and AutoHotkey. A COM based object does not have an enumerator thus you cannot simply use a for-loop to iterate over them. Selenium does does have an enumerator however the objects are held in the Keys (not the values).
pwb := WBGet() obj:=pwb.document.GetElementsByName("s") ;.length for k, v in obj MsgBox % v.outerHTML loop, % obj.length COM_Data.= a_index a_tab obj[a_index-1].outerhtml "`n" ;zero based SciTE_Output(COM_Data) ;Text,Clear=1,LineBreak=1,Exit=0 ;https://the-automator.com/scite-output-pane/ MsgBox pause ^t:: driver:= ComObjCreate("Selenium.IEDriver") ;Chrome driver driver.Get("https://the-automator.com/") ;~ MsgBox % driver.FindElementsByName("s").Length ; does not work MsgBox % driver.FindElementsByName("s").Count ;need to use count obj:=driver.FindElementsByName("s") for k,v in obj { ;~ MsgBox % IsObject(v) a_tab v Selenium_Data.= a_index a_tab k a_tab k.Attribute("outerHTML") "`n" } SciTE_Output(Selenium_Data,1) ;Text,Clear=1,LineBreak=1,Exit=0
Demo video showing how to iterate over objects in Selenium
Various Selenium methods for getting & setting data on a page
In this tutorial I walk through various ways to get/set data on a page. With Selenium you can use both CSS and Xpath which are like QuerySelector.
I also shared these two resources from Michael Sorens which present the same data
driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver driver.Get("https://the-automator.com/") MsgBox,,ByTag name-Just first,% driver.findElementByTag("P").Attribute("outerHTML") ;ByTag (name)-(just first) MsgBox,,ByTag name-First in Array,% driver.findElementsByTag("P").item[1].Attribute("outerHTML") ;ByTag (name)-Array MsgBox,,ByID ,% driver.findElementByID("site-description").Attribute("outerHTML") ;ByID MsgBox,,ByName-Just First ,% driver.findElementByName("s").Attribute("outerHTML") ;ByName (Just first) MsgBox,,ByName (array),% driver.findElementsByName("s").item[2].Attribute("outerHTML") ;ByName- array- 2nd MsgBox,,ByClass-First,% driver.findElementByClass("entry-title").Attribute("outerHTML") ;ByClass - (Just first) MsgBox,,ByClass-Array,% driver.findElementsByClass("entry-title").item[2].Attribute("outerHTML") ;ByClass - Array MsgBox,,Partial Match on Link text,% driver.findElementByPartialLinkText("a time").Attribute("outerHTML") ;partial match text MsgBox,,Full Match on Link text,% driver.findElementByLinkText("Automating my world; 1 script @ a time!").Attribute("innerText") ;Full match of link text ;***********css******************* MsgBox,,CSS-Tag &Input,% driver.findElementsByCss("input[name='s']").item[1].Attribute("outerHTML") ;ByCss: tag of Input and name of S MsgBox,,CSS-Just anme,% driver.findElementsByCss("[name='s']").item[1].Attribute("outerHTML") ;ByCss: Just use name MsgBox,,CSS-JustID,% obj:=driver.findElementsByCss("[id='site-description']").item[1].Attribute("outerHTML") ;ByCss: just by id MsgBox,,CSS-Class,% obj:=driver.findElementsByCss("[class='entry-title']").item[1].Attribute("outerHTML") ;ByCss: Class MsgBox,,CSS-Atag element and url,% obj:=driver.findElementsByCss("a[href='https://www.linkedin.com/in/joeglines']").item[1].Attribute("outerHTML") ;ByCss: A tag & href=URL ;***********xPath***https://addons.mozilla.org/en-us/firefox/addon/firepath/**************** MsgBox,,XPATH-ID & Tag,% driver.findelementbyxpath(".//*[@id='site-title']/span/a").Attribute("outerHTML") ;XPath: ID=site-title & span tag MsgBox,,XPATH-ID and Input Hierarchy,% driver.findelementbyxpath(".//*[@id='prime_nav']/li[8]/form/label/input").Attribute("outerHTML") ;XPath: ID=prime_Nave & tag heirarchy
Various methods from Selenium & by using JavaScript Execution
I went through and documented some of the additinol methods I used from Selenium & by injecting JavaScript. Check them out below as well as the video walking through the usage.
driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver ;~ driver.SetProfile("H:\Temp\Chrome\Cache\cache\Default") ; 'Full path of the profile directory driver.Get("https://the-automator.com/") MsgBox,,Title via JavaScript, % driver.executeScript("return document.title") ;gets title MsgBox,,Title, % Driver.Title ;Displays gets tab title MsgBox pause driver.executeScript("window.location = 'https://www.youtube.com/user/JoeGlines'") ;navigate using javascript MsgBox % driver.executeScript("return document.location.pathname") ;get path of url MsgBox pause MsgBox,,Title, % Driver.Title ;Displays gets tab title driver.executeScript("history.go(-1)") ;Go back one page MsgBox pause MsgBox,,Title, % Driver.Title ;Displays gets tab title driver.executeScript("history.go(0)") ;refresh page MsgBox pause driver.executeScript("history.go(1)") ;Go forward one page driver.executeScript("window.scrollBy(0,550)") ;scroll down page MsgBox pause driver.executeScript("window.scrollBy(0,950)") ;scroll down page MsgBox % driver.executeScript("return document.domain") ;get domain of current page MsgBox,,URL, % driver.url() ;gets current URL MsgBox,,Href, % driver.executeScript("return document.location.href") ;get full url MsgBox,,Protocol, % driver.executeScript("return document.location.protocol") ;get protocol driver.Get("https://the-automator.com/?s=Selenium") MsgBox,,Search, % driver.executeScript("return document.location.search") ;get everything from ? on driver.executeScript("window.open('https://www.youtube.com/user/JoeGlines','_target','resizable=yes')") ;open new tab with new destiation MsgBox pause driver.executeScript("window.open('','_blank','resizable=yes')") ;open new blank tab return
Maneuvering Frames in Selenium with AutoHotkey
The below code provides some insights on how to navigate frames with AutoHotkey
driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver driver.Get("http://the-internet.herokuapp.com/nested_frames") ;switch to a child frame MsgBox % "count before change = " driver.FindElementsByTag("frame").count driver.SwitchToFrame("frame-top") MsgBox % "count after change = " driver.FindElementsByTag("frame").count driver.SwitchToFrame("frame-middle") MsgBox % driver.FindElementById("content").Text return
Downloading files with Selenium and AutoHotkey
In this tutorial I demonstrate how I used AutoHotkey and Selenium to download a PDF file. The same process will work for other files that are not, automatically, opened by Chrome.
driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver ;~ driver.SetProfile("H:\Temp\Chrome\Cache\cache\Default") ; 'Full path of the profile directory driver.SetPreference("download.default_directory","c:\temp") ;set path to where you want the file saved driver.get("chrome://settings-frame/content") driver.findElementByID("pdf-section").click() ;disable open pdf driver.Get("https://the-automator.com/download/group-tool.pdf")
Connecting to a current instance of Chrome
Thankfully tmplinshi has come up with a solution on how to connect to an already launched version of Chrome. Granted, you’ll need to launch Chrome with some command line parameters but this is an easy tweak to do by just adding them to your main shortcut to Chrome you’ll be able to connect to a current running Chrome window!
Here’s what you need to do for prep-work:
- Make sure all current versions of Chrome are closed
- Create a shortcut to chrome with this path: chrome.exe –remote-debugging-port=9222
- Launch Chrome from your new shortcut
Then you can use the below code to connect with it! Check out the below video demonstrating how it works.
;********************Connect to Chrome and show title*********************************** driver := ChromeGet() MsgBox, % driver.Window.Title "`n" driver.Url return ChromeGet(IP_Port := "127.0.0.1:9222") { driver := ComObjCreate("Selenium.ChromeDriver") driver.SetCapability("debuggerAddress", IP_Port) driver.Start() return driver } ;********************Create new Chrome window*********************************** ^t:: driver:= ComObjCreate("Selenium.CHROMEDriver") ;Chrome driver driver.Get("https://the-automator.com/") MsgBox, % driver.Window.Title "`n" driver.Url return ;********************Launch Chrome with parameters*********************************** ^+r::run chrome.exe "--remote-debugging-port=9222" ;Run in debugging mode