Code: Select all
#IfWinActive ahk_class IEFrame ; if an internet explorer window is open
~Space Up::
If (A_PriorHotkey = A_ThisHotkey) and (A_TimeSincePriorHotkey < 200) ; If you double tap spacebar...
eGet("a", "Next.*|(.* )?\>+").Click() ; ...script will click on "a" elements that start with "Next" or end with ">"
Return
eGet(Tag, Text, AfterTag, AfterText)
- Tag: A space-delimited list with the format <tagname> <attribute>=<RegEx_Needle> <attribute>=<RegEx_Needle> ...
- Tagname: Put whatever tag you are looking for, e.g. a, span, img, etc. Use an asterisk ( * ) to look at all tags. (Note: using * will reduce performance because the script will now need to check likely hundreds more tags.)
- Attribute: (Optional) Attribute of the element you want to filter by, e.g. href, src, or width. Note: Use "ClassName" instead of "Class" (this is how AutoHotkey sees this attribute).
To find out the attributes of elements in a webpage, right click and select "Inspect Element" or use IE Element Spy: http://www.vowsoft.com/ies/ - RegEx_Needle: A regular expression needle to match against the tag. The script by default pads the expression with is)^\s*(%Needle%)\s*$, i.e. case-insensitive and matches entire phrase except leading and trailing spaces. But you can change this by changing TagRegExStart and TagRegExEnd in the function. You can include strings with spaces by enclosing the string in quotation marks, e.g. input value="some spaces and ""quotation marks"""
- Text: Text passed to this parameter is matched against the innerText of the element for a match, once more using a regular expression. It is equivalent to putting innerText="value" in the Tag parameter. If the desired tag is an input field, this parameter will also match the Class, Value, ID, or Name attributes (input elements never contain an innerText).
- AfterTag: The last two parameters are if you want to find a given element that comes AFTER another given element, which can be useful in certain situations. AfterTag contains the tag name and attribute matches for the FIRST element, using the same format as the Tag parameter.
- AfterText: The innerText match to use for the first element, again using the same format as the Text parameter.
- All: If you put "All" somewhere after the tag name, the script will return an array containing all elements that match your criteria instead of simply the first one.
- #=n: Will find the nth occurrence of your match and return that. For instance, a #=5 will fetch the 5th a element. Specify "last" to retrieve the last element found that matches the criteria given.
One important variable which is not passed as a parameter is the pointer to the web browser object. If an internet explorer window is currently active when eGet() is called, it will use this window. If you want to use another window, set the global variable "pwb" to the pointer to that browser object using the included function PWB_Get(). The web browser pointer will continue to be used for any additional eGet() calls within the next 2 seconds (for performance reasons), after which it will reset. To disable this behavior use PWB_Clear("Off").
Code:
Code: Select all
; === eGet(TAG, TEXT) ===
;
; Returns element object for the element if it is found in the current web browser object (global variable PWB).
; If there is no current web browser object, the active internet explorer window will become the current web browser object
;
; --- Parameters ---
;
; TAG
; Indicate a tag name (i.e. a, input, span, div, etc). Indicate an asterisk (*) for any tag (will make search more time-consuming).
; After the tag name you may optionally include a space and then a space-delimited list of tag attributes to match in the following format;
; attribute=value otherattribute=pattern.* lastattribute="value with spaces"
; All values are in case-insensitive RegEx format and will be assumed to be the entire space-trimmed matching string, i.e. they become i)^\s*%Value%\s*$
;
; TEXT
; Text passed to this parameter is matched against the innerText of the element for a match. It is equivalent to putting innerText="value" in the TAG parameter.
; If the desired TAG is an input field, this parameter will also match the Class, Value, ID, or Name attributes (input elements never contain an innerText).
; Use ID attribute for shorter, more efficient searching. Use IDRegEx attribute if you want to search ID using a regular expression
; To-do: Fix weird attribute names: see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
eGet(Tag, Text="", AfterTag="", AfterText="") ; ; https://autohotkey.com/boards/viewtopic.php?t=19889
{
Static UserConfig_A := "foo"
, TagRegExStart := "is)^\s*("
, TagRegExEnd := ")\s*$"
;----------------------------------------------------------------------------------------------------
Global Element := ""
EditableInputClasses = Text,Password,Checkbox
If !(PWB := PWB_Init())
Return False
SpecialAttributes := "#,All", Delimiter := Chr(1), Literal := """", After := "", EditableInputClasses := "," EditableInputClasses ","
Loop 2 {
If (A_Index = 2)
If (AfterTag = "") and (AfterText = "")
Break
Else
After := "After"
If RegExMatch(%After%Tag, "i)^[a-z0-9:]+(?=\s|$)", %After%TagName) and (%After%TagName <> "All")
%After%Tag := SubStr(%After%Tag, StrLen(%After%TagName) + 1)
Else
%After%TagName := "*", %After%Tag := A_Space %After%Tag
@5 := 1, %After%AttributesList := Text Delimiter, %After%n := 0, %After%# := 1
While (@5 := RegExMatch(%After%Tag, "i)\s(?:!([a-z:\-]+)|(\+|-)?([\w#:\-]+)=?(" Literal "(?:[^" Literal "]|" Literal Literal ")*" Literal "(?=\s|$)|\S*))", @, @5 + StrLen(@)))
If (@1 <> "")
%After%Tag := SubStr(%After%Tag, 1, @5 + StrLen(@)) UserConfig_%@1% SubStr(%After%Tag, @5 + StrLen(@))
Else If (@4 <> "") {
If (InStr(@4, Literal) = 1) and (@4 <> Literal) and (SubStr(@4, 0, 1) = Literal) and (@4 := SubStr(@4, 2, -1))
StringReplace, @4, @4, %Literal%%Literal%, %Literal%, All
%After%%@3% := @4, %After%AttributesList .= @3 Delimiter
} Else
%After%%@3% := @2 = "+" ? True : @2 = "-" ? False : True
Loop, Parse, SpecialAttributes, `,
StringReplace, %After%AttributesList, %After%AttributesList, %A_LoopField%%Delimiter%, , All
}
If (ID <> "") and (After = "") { ; short circuit to check for element IDs
Loop % 1 + PWB.Document.ParentWindow.Frames.Length {
If (A_Index = 1)
Document := PWB.Document
Else If !IsObject(Document := PWB.Document.ParentWindow.Frames[A_Index - 2].Document)
Document := ComObj(9, ComObjQuery(PWB.Document.ParentWindow.Frames[A_Index - 2], "{332C4427-26CB-11D0-B483-00C04FD90119}", "{332C4427-26CB-11D0-B483-00C04FD90119}"), 1).Document.DocumentElement
If (Element := Document.getElementById(ID))
Return Element
}
}
If All
Element := Object()
If (AfterAll <> "") or (After# = "Last") {
MsgBox, 262160, %A_ScriptName% - %A_ThisFunc%(): Error, The "All" and "# = Last" options are not supported for the "After" element.
Return False
}
If After and (TagName <> AfterTagName) {
QueryTag := "*"
If (TagName <> "*")
AttributesList .= "Tagname" Delimiter
If (AfterTagName <> "*")
AfterAttributesList .= "Tagname" Delimiter
} Else
QueryTag := TagName
Loop % 1 + PWB.Document.ParentWindow.Frames.Length {
If (A_Index = 1)
Document := PWB.Document
Else If !IsObject(Document := PWB.Document.ParentWindow.Frames[A_Index - 2].Document)
Document := ComObj(9, ComObjQuery(PWB.Document.ParentWindow.Frames[A_Index - 2], "{332C4427-26CB-11D0-B483-00C04FD90119}", "{332C4427-26CB-11D0-B483-00C04FD90119}"), 1).Document.DocumentElement ; http://www.autohotkey.com/board/topic/91443-comie-error-0x80070005-access-is-denied-with-paypal/
Loop % Document.GetElementsByTagName(QueryTag).Length {
@ := Document.GetElementsByTagName(QueryTag)[A_Index - 1]
Loop, Parse, %After%AttributesList, %Delimiter%
If (A_Index = 1) {
If (%After%Text <> "") and !RegExMatch((%After%TagName <> "input") ? @.innerText : !InStr(EditableInputClasses, "," @.Type ",") and (@.Value <> "") ? @.Value : (@.ID <> "") ? @.ID : @.Name, TagRegExStart %After%Text TagRegExEnd)
Break
} Else If (A_LoopField = "") and ((++%After%n = %After%#) or ((After = "") and (All or ((# = "Last") and !(Last := @))))) {
If After {
After =
Break
}
If !All
Return Element := @, PWB_Clear()
Element.Insert(@)
} Else If !RegExMatch(@[A_LoopField], TagRegExStart %After%%A_LoopField% TagRegExEnd)
Break
}
}
Return All ? Element : Element := Last ? Last : False, PWB_Clear()
}
; === eWait() ===
;
; Waits for the tag to appear
eWait(Tag, Text="", Timeout=4, ErrorAction="Exit", NewPWBEvery=4, Sleep=150)
{
Global PWB, Element
If Timeout
End := A_TickCount + Abs(Timeout) * 1000
; m("to")
While !eGet(Tag, Text)
If (Mod(A_Index, NewPWBEvery + 1) = 0)
PWB := ""
Else If (End > A_TickCount)
Sleep %Sleep%
Else If (Timeout < 0)
Return False
Else
Exit
If Element
Return Element
Else If (ErrorAction = "Exit")
Exit
Else If (ErrorAction = "ExitApp")
ExitApp
Else
Return
}
; === Dump(TAGNAME) ===
;
; Dumps the outerHTML of all elements of TAGNAME type into a blank notepad file. Used for debugging and to see all elements that AutoHotkey can access.
Dump(TagName="*")
{
EditorPath = "%A_AhkPath%\..\..\Utilities\Notepad++\Notepad++.exe" ; "%A_AhkPath%\..\SciTE\SciTE.exe"
OutputFile = %A_Temp%\COM+IE_Dump.txt
Tooltips = %True%
ReplaceInnerHTMLWith := " ... <TAG #%n%> ... " ; False
;------------------------------------------------------------------------------------------------------------------------
If !(PWB := PWB_Init())
Return False
FileDelete, %OutputFile%
VarSetCapacity(Output, 50000), n := 0, SpecialChar := Chr(1)
If Tooltips
Tooltips := Floor(PWB.Document.GetElementsByTagName(TagName).Length ** 0.3)
Loop % 1 + PWB.Document.ParentWindow.Frames.Length {
Output .= (A_Index = 1 ? "" : SpecialChar SpecialChar) "============================================================= Frame " A_Index " =============================================================" SpecialChar
If (A_Index = 1)
Document := PWB.Document
Else If !IsObject(Document := PWB.Document.ParentWindow.Frames[A_Index - 2].Document)
Document := ComObj(9, ComObjQuery(PWB.Document.ParentWindow.Frames[A_Index - 2], "{332C4427-26CB-11D0-B483-00C04FD90119}", "{332C4427-26CB-11D0-B483-00C04FD90119}"), 1).Document.DocumentElement
Loop % Document.GetElementsByTagName(TagName).Length {
n += 1, @ := Document.GetElementsByTagName(TagName)[A_Index - 1].outerHTML
If ReplaceInnerHTMLWith and (@ <> "") {
StartPos := 1
While InStr(Output, @, False, StartPos)
StartPos := InStr(Output, @, False, StartPos) + StrLen(@)
If (StartPos <> 1) {
Transform, ReplacementString, Deref, %ReplaceInnerHTMLWith%
Output := SubStr(Output, 1, StartPos - StrLen(@) - 1) ReplacementString SubStr(Output, StartPos)
}
}
Output .= SpecialChar n A_Tab @
If (Mod(n, Tooltips) = 1)
ToolTip, % "Number: " n "`n" SubStr(RegExReplace(@, ".{40}\K", "`n"), 1, 400)
}
}
If Tooltips
ToolTip
Output := RegExReplace(Output, "`r`n?|`r?`n", "`r`n`t")
StringReplace, Output, Output, %SpecialChar%, `r`n, All
FileAppend, %Output%, %OutputFile%
Run, %EditorPath% "%OutputFile%", , UseErrorLevel
If ErrorLevel
Run, "%OutputFile%"
Return Output, PWB_Clear()
}
; === ElementFromPoint() ===
;
; Gets element from x and y coordinates
ElementFromPoint(x="", y="")
{
; Send ^0
Global PWB, Element
If (x = "") and (y = "") {
CoordMode, Mouse
MouseGetPos, x, y
}
WinGet, IE, List, ahk_class IEFrame
Loop %IE% {
ControlGet, HWND, HWND, , Internet Explorer_Server1, % "ahk_id " IE%A_Index%
WinGetPos, x0, y0, x1, y1, ahk_id %HWND%
If (x >= x0) and (x <= x0 + x1) and (y >= y0) and (y <= y0 + y1) {
PWB := PWB_Get("ahk_id " IE%A_Index%)
Return Element := PWB.Document.elementFromPoint(x - x0, y - y0)
}
}
}
;=================================================== Helper Functions ===================================================
PWB_Init(WinTitle="")
{
Global PWB, Element
PWB_Clear(False), ComObjError(False)
If !PWB or (WinTitle <> "") {
TitleMatchMode := A_TitleMatchMode, Element := ""
SetTitleMatchMode, RegEx
HWND := WinExist("ahk_class IEFrame")
SetTitleMatchMode, %TitleMatchMode%
If !HWND
Return PWB_Error("No internet explorer windows exist.", A_ThisFunc)
If (WinTitle <> "") {
IfWinExist, %WinTitle% ahk_class IEFrame
PWB := PWB_Get(WinTitle)
Else
PWB := PWB_MatchTitle(WinTitle)
}
Else IfWinActive, ahk_class IEFrame
PWB := PWB_Get("A")
Else
PWB := PWB_Get("ahk_id " HWND)
}
Return PWB
}
; === PWB_MatchTitle(WINTITLE) ===
;
; Returns the web browser object of the window with the specified title. Uses fuzzy string matching to match given title with all browser objects.
PWB_MatchTitle(WinTitle)
{
Explorers := ComObjCreate("Shell.Application").Windows, BestScore := 0
While (3 > Iteration := A_Index)
For This In Explorers
If InStr(This.FullName "|", "\iexplore.exe|")
If (Iteration = 1) and (WinTitle = This.LocationName)
Return PWB := This
Else If (Iteration = 2) and (BestScore < Score := %A_ThisFunc%_Compare(WinTitle, This.LocationName))
BestScore := Score, PWB := This
Return PWB
}
; === PWB_Get(WINTITLE, SVR#) ===
;
; Gets a pointer to web browser object (pwb) from an already existing internet explorer window
PWB_Get(WinTitle="A", Svr#=1) ; Jethrow - http://www.autohotkey.com/board/topic/47052-basic-webpage-controls-with-javascript-com-tutorial/
{
Static msg := DllCall("RegisterWindowMessage", "str", "WM_HTML_GETOBJECT")
, IID := "{0002DF05-0000-0000-C000-000000000046}" ; IID_IWebBrowserApp
;,IID := "{332C4427-26CB-11D0-B483-00C04FD90119}" ; IID_IHTMLWindow2
SendMessage, msg, 0, 0, Internet Explorer_Server%Svr#%, %WinTitle%
If (ErrorLevel != "FAIL") {
lResult := ErrorLevel, VarSetCapacity(GUID, 16, 0)
If (DllCall("ole32\CLSIDFromString", "wstr", "{332C4425-26CB-11D0-B483-00C04FD90119}", "ptr", &GUID) >= 0) {
DllCall("oleacc\ObjectFromLresult", "ptr", lResult, "ptr", &GUID, "ptr", 0, "ptr*", pdoc)
Return ComObj(9, ComObjQuery(pdoc, IID, IID), 1), ObjRelease(pdoc)
}
}
PWB_Error("Unable to obtain browser object (PWB) from window:`n`n" WinTitle, A_ThisFunc)
}
; === PWB_Set() ===
;
; Same as above but doesn't let the browser object reset
PWB_Set(WinTitle="A", Svr#=1)
{
PWB_Clear("Off")
Return PWB_Get(WinTitle, Svr#)
}
; === PWB_Clear() ===
;
; Controls the behavior of whether the variable %pwb% is reset to empty after a few seconds
PWB_Clear(Set=True)
{
PWB_DefaultTimeout = 1500
;------------------------------------------------------------------------------------------------------------------------
Global Element, PWB, PWB_Timeout
Static Enabled, Initialized
If !Initialized {
If (PWB_Timeout = "")
PWB_Timeout := PWB_DefaultTimeout
Initialized := True
}
If (Set = "Off")
Enabled := False
Else If (Set = "On") or (Enabled = "")
Enabled := True
If PWB_Timeout and Enabled
If Set
SetTimer, %A_ThisFunc%, %PWB_Timeout%
Else
SetTimer, %A_ThisFunc%, Off
Return
PWB_Clear:
Element := PWB := ""
Return
}
; === PWB_Error() ===
;
; Displays errors
PWB_Error(Message, Function="")
{
ErrorDialogs := True
;------------------------------------------------------------------------------------------------------------------------
If ErrorDialogs
MsgBox, 262160, % A_ScriptName ": Error" (Function = "" ? "" : " with " Function "()"), %Message%`n`nTo disable these messages, change `%ErrorDialogs`% in %A_ThisFunc%() to `%false`%.
}
; === PWB_MatchTitle_Compare() ===
;
; Helper function. See http://www.autohotkey.com/board/topic/70202-string-compare-function-nonstandard-method/
PWB_MatchTitle_Compare(StringA, StringB, CaseSense=False, Digits=8)
{
Loop %Digits%
Max .= 9, Zeros .= 0
If (CaseSense and StringA == StringB) or (!CaseSense and StringA = StringB)
Return Max
Score := 0, SearchLength := 0, LengthA := StrLen(StringA), LengthB := StrLen(StringB)
Loop % (LengthA < LengthB ? LengthA : LengthB) * 2 {
If (A_Index & 1)
SearchLength += 1, Needle := "A", Haystack := "B"
Else
Needle := "B", Haystack := "A"
StartAtHaystack := 1, StartAtNeedle := 1
While (StartAtNeedle + SearchLength <= Length%Needle% + 1)
If (Pos := InStr(String%Haystack%, SubStr(String%Needle%, StartAtNeedle, SearchLength), CaseSense, StartAtHaystack)) {
StartAtHaystack := Pos + SearchLength, StartAtNeedle += SearchLength, Score += SearchLength ** 2
If (StartAtHaystack + SearchLength > Length%Haystack% + 1)
Break
} Else
StartAtNeedle += 1
}
Return (Score := Round(Score * 10 ** (Digits // 2) / (LengthA > LengthB ? LengthA : LengthB))) >= Max ? Max - 1 : SubStr(Zeros Score, 1 - Digits)
}
Code: Select all
; Log in to some website
eGet("input name=email").value := "my@email.com"
eGet("input name=password").value := "1234"
eGet("input type=submit").click()
;------------------------------------------------------------------------------------------------------
; Clicks search in the google window which is not currently active
pwb := PWB_Get("Google ahk_class IEFrame")
eGet("input value=""Google Search""").Click()
;------------------------------------------------------------------------------------------------------
; Shows the addresses of all the images on the current page
images := eGet("img all")
For n, element in images
output .= element.src "`n"
MsgBox, % Output
;------------------------------------------------------------------------------------------------------
; search for Joe Schmoe's name and clicks on the button to the right of it
eGet("input type=submit", "", "div", "Joe Schmoe").click()
;------------------------------------------------------------------------------------------------------
; displays the text of the first element of any kind with at least 30 characters that comes after a h2 element containing the text "News"
MsgBox, % eGet("*", ".{30,}", "h2", ".*News.*").innerText
;------------------------------------------------------------------------------------------------------
; Sends focus to first text input box, which is usually the search bar at the top of the page. Try google, amazon, or AutoHotkey forums.
^b::
If eGet("input type=text|search readonly=0 disabled=0") { ; This returns true if such an element exists. Note that 0 is used instead of false (%False% would work too).
ControlFocus, Internet Explorer_Server1, A ; Make sure keyboard focus is in the webpage control
Element.Focus() ; Send keyboard focus to that element
Sleep 100 ; Short sleep
Send ^a ; Select all within that element
}
Return
This script might seem pretty messy but it really can be useful for quick and dirty internet explorer macros, or for longer more complicated ones. Almost any element can be fetched with a single line of code, which is a huge improvement over the normal unwieldy COM navigation. I suggest you give it a quick try if you are trying to make a macro with a webpage using Internet Explorer.