The macosxhints Forums

The macosxhints Forums (http://hintsforums.macworld.com/index.php)
-   OS X Developer (http://hintsforums.macworld.com/forumdisplay.php?f=27)
-   -   GUI Scripting question (http://hintsforums.macworld.com/showthread.php?t=110252)

earachefl 03-21-2010 12:55 PM

GUI Scripting question
 
I'm trying to have Applescript enter a user name and password into a popup window that appears when I want to open my router's administration window. Using Accessibility Inspector, I find the following attributes on the user name text field:

Quote:

<AXApplication: “Safari”>
<AXWindow: “My Home Page”>
<AXSheet>
<AXTextField>

Attributes:
AXRole: “AXTextField”
AXRoleDescription: “text field”
AXHelp: “(null)”
AXValue (W): “”
AXEnabled: “1”
AXFocused (W): “1”
AXParent: “<AXSheet>”
AXWindow: “<AXWindow: “My Home Page”>”
AXTopLevelUIElement: “<AXSheet>”
AXPosition: “x=478 y=209”
AXSize: “w=230 h=22”
AXChildren: “<array of size 0>”
AXSelectedText (W): “”
AXSelectedTextRange (W): “pos=0 len=0”
AXNumberOfCharacters: “0”
AXVisibleCharacterRange (W): “pos=0 len=0”
AXInsertionPointLineNumber: “(null)”
How do I then tell Applescript how to deliver the needed text to this window? I've gotten as far as
Code:

tell application "System Events"
        tell process "Safari"
                window "My Home Page"
                keystroke "username"
        end tell
end tell

but obviously I need to give more information about which element to insert text into. Thanks to all.

mark hunte 03-21-2010 03:38 PM

This may work
Code:

activate application "Safari"
tell application "System Events"
        tell process "Safari"
                set value of text field 1 of sheet 1 of window 1 to "username"
                set value of text field 2 of sheet 1 of window 1 to "password"
        end tell
end tell

Although you probably should also look at saving your passwords in a keychain and accessing it through
"Keychain Scripting"

Code:

tell application "Safari" to activate
tell application "Keychain Scripting"
        (* Set the next line to match the name of the keychain you created *)
        set myChain to keychain "login.keychain"
        set theKey to the first key of myChain whose name is "netgear_router"
        set theKeyUserID to the account of theKey
        set theKeyPassword to the password of theKey
end tell
tell application "System Events"
        tell process "Safari"
                set value of text field 1 of sheet 1 of window 1 to theKeyUserID
                set value of text field 2 of sheet 1 of window 1 to theKeyPassword
        end tell
end tell

Also remember to check always ask for password in the keychain access control of the key

earachefl 03-21-2010 05:36 PM

Thanks, now I'm getting somewhere. I can get it to click through to the main router admin page using the following code. However, still not quite getting how to figure out which button to press on the next page. AI gives me the following attributes:
Quote:

<AXApplication: “Safari”>
<AXWindow: “http://192.168.1.1/”>
<AXGroup>
<AXScrollArea>
<AXWebArea: “”>
<AXGroup: “”>
<AXRadioButton: “”>

Attributes:
AXRole: “AXRadioButton”
AXSubrole: “(null)”
AXRoleDescription: “radio button”
AXChildren: “<array of size 0>”
AXHelp: “”
AXParent: “<AXGroup: “”>”
AXPosition: “x=422 y=425”
AXSize: “w=16 h=19”
AXTitle: “”
AXDescription: “”
AXValue: “0”
AXFocused (W): “0”
AXEnabled: “1”
AXWindow: “<AXWindow: “http://192.168.1.1/”>”
AXSelectedTextMarkerRange (W): “(null)”
AXStartTextMarker: “<NSCFType: 0x5919980>”
AXEndTextMarker: “<NSCFType: 0x59199a0>”
AXVisited: “0”
AXLinkedUIElements: “<array of size 2>”
AXSelected: “0”
AXBlockQuoteLevel: “0”
AXTopLevelUIElement: “<AXWindow: “http://192.168.1.1/”>”
AXTitleUIElement: “(null)”
AXAccessKey: “(null)”
so based on that information I tried the following:
Code:

activate application "Safari"
tell application "Safari"
        open location ("http://192.168.1.1")
end tell
delay 2
tell application "System Events"
        tell process "Safari"
                set value of text field 1 of sheet 1 of window 1 to "username"
                set value of text field 2 of sheet 1 of window 1 to "password"
                delay 2
                click button 1 of sheet 1 of window 1
                delay 2
                click radio button 1 of group 1 of web area 1 of scroll area 1 of group 1 of window 1
        end tell
end tell

but compiling gives me a syntax error:
Quote:

Expected end of line, etc. but found identifier
with the word "area" highlighted. Thanks again for your help.

mark hunte 03-21-2010 05:58 PM

Its a little hard for me to work out your elements.

You could try
Code:

click radio button 1 of group 1 of UI element 1 of scroll area 1 of group 1 of window 1
Or to work out the UI element path try and see what they are with
Code:

set RBs to radio buttons of UI element 1 of UI element 1 of UI element 1 of UI element 1 of window 1

earachefl 03-21-2010 07:02 PM

Hm... replacing "web area 1" with "UI element 1" at least gets it to compile, but running either that script or your other suggestion gets me the
Quote:

System Events got an error: NSReceiverEvaluationScriptError: 4
message.

So is AI not giving enough information to figure out what code to pass to System Events? FWIW, I'm trying to click on the radio button that disables the wireless access point. What more information do I need to figure this out?

tw 03-21-2010 07:12 PM

that error just means that it's not finding the specified UI element at the location specified. almost invariably it means that you've gotten something mixed up (used 'group 1' where you should have used 'group 2', or something like that). trial and error is the only way to parse it that I know of.

earachefl 03-21-2010 08:12 PM

This is turning out to be a lot harder than I thought.... Question: using the DOM Inspector in Firefox, the structure of the button's place in the page is shown as:
Quote:

html>body>center>table>tbody>tr>th>table>tbody>tr>th>table>tbody>tr>td>font>b>input
.... just a mess of nested tables. I also find from the source that the radiobutton's group name is "wirelessStatus". Is there a way of using that in the script?

tw 03-21-2010 11:01 PM

download UIElementInspector and play with it. it's a good tool, which should give you the info you need. and no, the DOM structure of the HTML document probably won't help (it's not how it renders in the browser, but how the browser renders it in the GUI).

if you want to switch to Safari, you can write javascript into an applescript, which may make the task easier. I don't know if you can do that in Firefox.

earachefl 03-22-2010 09:52 AM

Hey tw, thanks for the suggestions. I actually did download UIElementInspector and pasted the results into my second post above. Unfortunately, neither I nor Mark Hunte were able to figure out exactly which element to pass to System Events from that info. Did you take a look at that?

There oughta be a tool that you could use to drag and drop GUI elements into a script editor...

mark hunte 03-22-2010 11:05 AM

whats the name of the button.

put is name where the "radio button" is in this script and see if that works.
I tried this on a web page, and it worked fine for me. But I know the name of the button.

Code:

tell application "Safari"
        activate
        do JavaScript "document.getElementById('radio button').click()" in document 1
end tell


earachefl 03-22-2010 11:23 AM

I was just trying this... not quite there yet. The name of the radio button group is "wirelessStatus" and the button I want to click is named "Disable":
Quote:

<input type=radio name=wirelessStatus value=0>Disable</td>
I'm rusty on my Javascript... had tried writing this:
Code:

tell application "Safari"
        do JavaScript "document.getElementByID('wirelessStatusDisable').click()"
end tell

... and don't get an error message, but don't get a response either.
Also, the form name is "F1"... tried writing
Code:

tell application "Safari"
        do JavaScript "document.getElementByID('F1.wirelessStatusDisable').click()"
end tell

as well. Also tried
Code:

do JavaScript "document.getElementByID('F1.wirelessStatus')[1].click()"
and
Code:

do JavaScript "document.getElementByID('F1.wirelessStatus[1]').click()"
and
Code:

do JavaScript "document.getElementByID('F1.wirelessStatus[1]').checked = true"
and
Code:

do JavaScript "document.getElementByID('F1.wirelessStatus')[1].checked = true"

bramley 03-22-2010 02:32 PM

It seems far simpler to work out the process that your browser actually uses to login to the router - and emulate that process.

What happens when you type into your browser?
Code:

http://username:password@RouterIPNumber
Pretty much the standard way to login to any restricted area by http.

mark hunte 03-22-2010 02:45 PM

Ok I only know javascript by putting things together from real javascript examples..
And I think my first script will only work on buttons, not radio buttons.

So..

I have now got more than one radio button on different pages to be set.
And was coming back here to ask you the form name, and realise you where already trying to do, what I have done.

So I do not need to explain to much.

Try
Code:

do JavaScript "document.F1.wirelessStatus[1].checked=true" in document 1
for does who want to try this on other pages.

F1 = the form name
wirelessStatus = the radio button/s group name
[1] radio button number in group -- Remember that the group is an array so it starts from 0 onwards
checked=true = set checked,

uncheck would be . checked=false

Now I am just trying to figure out a way to do it by value. I can find the values no problem, just want them selected by it.

mark hunte 03-22-2010 03:16 PM

To add to my last post,
Get radio button by its value, and check it.

Code:

tell application "Safari"
        (*          get the number of  of the radio buttons in the array *)
        set counter to (do JavaScript "document.f1.r1.length" in document 1)
        set theCount to 0
        repeat counter times
                (*          get the value of the radio buttons *)
                set getItsValue to (do JavaScript "document.f1.r1[" & theCount & "].value" in document 1)
                --log getItsValue
                if getItsValue = "The Value- of -your button" then
                        (* set the state to check/unchecked  if match found*)
                        do JavaScript "document.f1.r1[" & theCount & "].checked=true" in document 1
                        exit repeat
                end if
                set theCount to theCount + 1
        end repeat
end tell


earachefl 03-22-2010 03:37 PM

Quote:

Originally Posted by bramley (Post 576919)
It seems far simpler to work out the process that your browser actually uses to login to the router - and emulate that process.

What happens when you type into your browser?
Code:

http://username:password@RouterIPNumber
Pretty much the standard way to login to any restricted area by http.

Ah, interesting, didn't know that.

earachefl 03-22-2010 03:53 PM

Quote:

Originally Posted by mark hunte (Post 576923)
To add to my last post,
Get radio button by its value, and check it.

Seems awfully convoluted... I know what the length of the array is (2) since there are only two choices, and I know that I want the second button, "Disable" to be checked. But somehow, using document.F1.wirelessStatus[1] as the identifier doesn't work, and also using document.getElementByID('wirelessStatus') or document.getElementByID('F1.wirelessStatus') doesn't work. So I guess I need to brush up on my JavaScript...

mark hunte 03-22-2010 03:53 PM

Quote:

Originally Posted by bramley (Post 576919)
It seems far simpler to work out the process that your browser actually uses to login to the router - and emulate that process.

What happens when you type into your browser?
Code:

http://username:password@RouterIPNumber
Pretty much the standard way to login to any restricted area by http.

I used to use that a lot years ago, but if I remember right it got broken in some browser.

Also do you know what you do if you have none alphanumeric characters in the password or user name, that would be interpreted by the browser wrong?

bramley 03-23-2010 08:27 AM

Quote:

Originally Posted by mark hunte (Post 576928)
I used to use that a lot years ago, but if I remember right it got broken in some browser.

Also do you know what you do if you have none alphanumeric characters in the password or user name, that would be interpreted by the browser wrong?

Not disputing that it got broken, but the scheme mentioned by me is in the HTTP 1.0 Protocol i.e it is something that all modern browsers should have implemented.

Don't focus on the specifics and ignore my general point. There are several authentication methods mentioned in the http protocol - I've just mentioned the one all routers that I've ever dealt used. It stands to reason that one of the methods mentioned in the protocol is in use in this situation.

Identify the method in use - it has to be discernable from the source code of the webpage.

Gotta be better and more reliable than screen scraping i.e GUI scripting.

mark hunte 03-23-2010 01:12 PM

Quote:

Originally Posted by earachefl (Post 576927)
Seems awfully convoluted... I know what the length of the array is (2) since there are only two choices, and I know that I want the second button, "Disable" to be checked. But somehow, using document.F1.wirelessStatus[1] as the identifier doesn't work, and also using document.getElementByID('wirelessStatus') or document.getElementByID('F1.wirelessStatus') doesn't work. So I guess I need to brush up on my JavaScript...

Its just another way I got working .. :)

Are you able to zip up a copy of the html (take out any thing you should keep secure ) and post it.

That way I can look at the actual tags myself.

mark hunte 03-23-2010 01:40 PM

Just put,
Code:

<form name="F1">
<input type=radio name=wirelessStatus value=0>Disable</td>
<input type="radio" name=wirelessStatus value=1>Enable</td>
</form>

Code:

do JavaScript "document.F1.wirelessStatus[0].checked=true" in document 1
which worked.

But a copy of the page would help to see whats really going on..

earachefl 03-25-2010 06:04 PM

Quote:

Originally Posted by mark hunte (Post 577024)
Just put,


Code:

do JavaScript "document.F1.wirelessStatus[0].checked=true" in document 1
which worked.

But a copy of the page would help to see whats really going on..

Trying to compile this, I get:
Quote:

Syntax Error: Expected end of line, etc. but found identifier.
Trying to post zip of source file but unsuccessful so far...

earachefl 03-25-2010 06:13 PM

1 Attachment(s)
Quote:

Originally Posted by mark hunte (Post 577024)
Just put,

But a copy of the page would help to see whats really going on..

Here tis...

mark hunte 03-26-2010 02:47 AM

You need to enclose it with the tell block.. :)

Code:

tell application "Safari"
        do JavaScript "document.F1.wirelessStatus[1].checked=true" in document 1
end tell

And this works on the page you sent me.

mark hunte 03-26-2010 03:17 PM

A Toggle for the two button Radio button array.

It checks to see if radio button 0 is checked.
If it is, a 1 will be returned. The result 1 will be used to identify the radio button 1 as the radio button that will get checked.

If it is not checked, then a 0 will be returned, The result 0 will be used to identify the radio button 0 as the radio button that will get checked.
This is a simple toggle to check R. Buttons zero or one.

Code:

tell application "Safari"
        set theBool to (((do JavaScript "document.F1.wirelessStatus[0].checked" in document 1) as boolean) as integer)
        do JavaScript "document.F1.wirelessStatus[" & theBool & "].checked=true" in document 1
end tell


earachefl 03-26-2010 05:43 PM

Solved! Syntax error, of course, on my part... I was placing the last quotation mark at the end of the line instead of before "in document 1". Final code is short and sweet:
Code:

activate application "Safari"
tell application "Safari"
        open location ("http://username:password@192.168.1.1")
        delay 1
        do JavaScript "document.F1.wirelessStatus[1].checked = true" in document 1
        do JavaScript "document.F1.submit()" in document 1
end tell

Script Editor does tell me "missing value", though, for what it's worth.
Now I just have to learn how to force Safari to quit after running this...

hayne 03-26-2010 08:42 PM

tell application Safari
quit
end tell

mark hunte 04-03-2010 10:45 AM

Quote:

Originally Posted by earachefl (Post 577447)
Solved! Syntax error, of course, on my part... I was placing the last quotation mark at the end of the line instead of before "in document 1". Final code is short and sweet:
Code:

activate application "Safari"
tell application "Safari"
        open location ("http://username:password@192.168.1.1")
        delay 1
        do JavaScript "document.F1.wirelessStatus[1].checked = true" in document 1
        do JavaScript "document.F1.submit()" in document 1
end tell

Script Editor does tell me "missing value", though, for what it's worth.
Now I just have to learn how to force Safari to quit after running this...

Glad its working, but are you not forgetting something..

earachefl 04-04-2010 11:38 AM

Quote:

Originally Posted by mark hunte (Post 578166)
Glad its working, but are you not forgetting something..

??? A thank you? Thanks to all!

mark hunte 04-04-2010 11:56 AM

Your welcome, :):)

earachefl 04-04-2010 11:59 AM

Quote:

Originally Posted by mark hunte (Post 578228)
Your welcome, :):)

I feel like I've been scolded :(
sorry for my lack of etiquette - and hey, how'd I get upgraded to a Triple-A player?


All times are GMT -5. The time now is 06:09 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.