Click Button on Web Page

I am trying to use javascript to click a button on a web page as using Applescript did not work if the place on the page changed .

This is detail of the button I want to access

Log in

It does not have name, class or ID I have run the following code using log in. Also changed “getElementsByName” to “getElementsByType”

Thanks for considering this, I know nothing about Javascript and got the information that created the following code from the web

to clickName(theName, elementnum)
	tell application "Safari"
		do JavaScript "document.getElementsByname('" & theName & "')[" & elementnum & "].click();" in document 1
	end tell
end clickName
set elementnum to 0
repeat 10 times
	clickName("Log in", elementnum)
	set elementnum to elementnum + 1
end repeat

Is this where you got your script? http://www.cubemg.com/how-to-click-a-button-on-a-web-page-with-applescript/

If not check it out. Also, use the Elements inspector to get what you need to know about the page.

If there’s not a name, id, class you can use, try the tagname (basically the text displayed by the button)

(From that same page)

to clicktagName(thetagName, elementnum)

tell application "Safari"

do JavaScript "document.getElementsByTagName('" & thetagName & "')[" & elementnum & "].click();" in document 1

end tell

end clicktagName

You might be able to use GUI scripting alone.
What is the website or page you are trying to click on?

Hi

Dividend.com

I was using GUI and that is why I looked for something else as the position of some of the components where moved occasionally. The following is what I use: this is from a simple page some are more complicated and the place references get longer and take a lot more time to figure out

repeat with Y from 30 to 50 --Login with "User Name " & "Password" on 12/09/2021 it was 37
			try
				set value of text field 1 of group 1 of group Y of RefEnd to "xx"
				set value of text field 1 of group 2 of group Y of RefEnd to "xx"
				exit repeat
			end try
			delay 1
		end repeat
		click button 1 of group 3 of group Y of RefEnd
		delay 3
end

This works for the 2 items in the try block and what I cannot work out is the click command.

to inputByName(theName, num, theValue)
	tell application "Safari"
		do JavaScript " 
  document.getElementsByName('" & theName & "')[" & num & "].value ='" & theValue & "';" in document 1
	end tell
end inputByName

inputByName("email", 0, "mitchbvi@mac.com")
inputByName("email", 1, "Div11122021#")

The suggestion of using “TagName” did not work I have expanded the HTML code from the inspector in case this helps.

Log in
= $0 Forgot password

Note the “=$O” I added manually as it shows in the inspector but is grayed out and there for does not copy

I would really like the website/URL so I can test. Unless it is a security issue?

Here is a sample script that will click the link in ESTOCKLY’s post

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

local UIElements, i, anElement
tell application "System Events"
	set anElement to application process "Safari"
	set anElement to UI element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window 1 of anElement
	set UIElements to UI elements of anElement
	repeat with i in UIElements
		set i to contents of i
		if UI element "http://www.cubemg.com/how-to-click-a-bu … plescript/" of i exists then
			tell UI element "http://www.cubemg.com/how-to-click-a-bu … plescript/" of i to perform action "AXPress"
			exit repeat
		end if
	end repeat
end tell

The url is https://www.dividend.com/login/?redirect_url=/login. That as you would expect brings up the login page. I see I left both user name and password in my post that described the part that worked. I will change the password.

I may not have explained myself but what you did in your example
set anElement to UI element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window 1 of anElement

is what I have been doing and I am trying to avoid GUI scripting as some parts change . I have been using UI Browser to get the GUI portion of the script but that adds time to the process every time something changes .

The part of the script that adds the input vales in this case username and password works what does not work is cling the “Log in” button. I could use GUI for this but the page I was using was to show the issue it gets a lot more complicate at least for me when I need to access a drop down list in say a footer or an item in a drop down list which itself is part of another drop down list.

I apologise if this all sounds unwieldy but Dividend.com often changes its site layout. Also I may be using terms incorrectly. But it seems to me if I can enter data into boxes on a website it should be relatively simple to click on another box using Javascript

thanks

What happens if you use the button class?

to clickClassName(theClassName, elementnum)
	tell application "Safari"
		do JavaScript "document.getElementsByClassName('" & theClassName & "')[" & elementnum & "].click();" in document 1
	end tell
end clickClassName

set cn to "t-w-full t-mt-2 t-bg-indigo-775 hover:t-bg-indigo-750 t-text-white t-font-semibold t-p-3 t-rounded"

clickClassName(cn, 0)

You could try this https://github.com/alexk111/automa
Its Google Chrome Extension to build Automation in Web browser.

I do believe you could use the trigger flow to search for xpath to trigger a button.

Ps.
If you do know Node-RED then I guess you will not have any problem to know how it works.
You could find many examples… :wink:

I have done do Javascript before in Safari but there is always issuess specially when a script
become more and 1 line. The practice to include javascript in IDE that use AppleScript is not
always the best approach I think… I have try.

This works for me, and it’s the same approach as mockman’s.

clickClassName("t-w-full t-mt-2 t-bg-indigo-775 hover:t-bg-indigo-750 t-text-white t-font-semibold t-p-3 t-rounded", 0)

to clickClassName(theClassName, elementnum)
	tell application "Safari"
		activate
		do JavaScript "document.getElementsByClassName('" & theClassName & "')[" & elementnum & "].click();" in document 1
	end tell
	
end clickClassName

I know you’re not interested, but I had fun getting a GUI version to work.

Here is my sample

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

local UIElements, i, anElement, subElements, loginPane, anItem, emailFlag, pwdFlag

tell application "System Events"
	set anElement to application process "Safari"
	set anElement to UI element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window 1 of anElement
	
	set subElements to groups of anElement whose subrole is "AXLandmarkMain"
	repeat with i in subElements
		set i to contents of i
		if (subrole of i) = "AXLandmarkMain" then
			set loginPane to i
			exit repeat
		end if
	end repeat
	try
		get loginPane
	on error
		return false
	end try
	set emailFlag to false
	set subElements to groups of loginPane whose subrole is not "AXEmptyGroup"
	repeat with i in subElements -- finds the Email group
		set i to contents of i
		if (static text 1 of i) exists then
			if (value of static text 1 of i) = "Email" then
				set anItem to text field 1 of i
				set focused of anItem to true
				tell me to delay 0.2
				set value of anItem to some item of "email@domain.com"
				set emailFlag to true
			end if
			if emailFlag then -- refresh screen to remove optional 'This field is required' notice
				set focused of text field 1 of i to true
				tell me to delay 0.2
				exit repeat
			end if
		end if
	end repeat
	set pwdFlag to false
	set subElements to groups of loginPane whose subrole is not "AXEmptyGroup"
	repeat with i in subElements -- finds the Password group
		set i to contents of i
		if (static text 1 of i) exists then
			if (value of static text 1 of i) = "Password" then
				set anItem to text field 1 of i
				set focused of anItem to true
				tell me to delay 0.2
				set value of anItem to my "mypwd"
				set pwdFlag to true
			end if
		end if
		if pwdFlag then exit repeat
	end repeat
	if emailFlag and pwdFlag then
		repeat with i in subElements -- finds the Login button
			set i to contents of i
			if (button "Log in" of i) exists then
				tell button "Log in" of i to perform action "AXPress"
				exit repeat
			end if
		end repeat
	end if
end tell

hi all

Sorry no response been in hospital for a couple days will get back to this shortly

Back on deck thanks again for all the help. Stockly & Mockman got me there.

The class name approach worked I had thought just the name of the button would work but it requires more precision . For me at least a lot easier to get to than using a GUI approach.

Peter

robertfern

Sorry I failed to acknowledge your GUI approach, thank you. I have been using UI browser to create the GUI part of my script. The web pages in Dividend.com have so many items and sub pages it takes for ever to locate the item I want and when it changes I have to start over again.

Having got past the login page with help from this forum I ma working on trying to access items on a sub page so far no luck.

Thanks again for all the help.

Peter

Sometimes the easiest way to click a button anywhere is to use mouse click.

  1. First make sure the target application is full screen.
  2. Get the x, y coordinate for the mouse cursor for the target button.

There are many ways to make mouse click and you could find them all in this forum.

That is the way I will do it if I need a fast solution.

So, on the browser page with the item you’re trying to access, try this:

Right-click (or control-click) on the item you want to access. Select “inspect” (or “Inspect Element”).

A new pane will open in your safari window (if it’s not already there) and the “Elements” tab will be active, and some portion of the HTML will be selected.

Copy that text.

Run the first script below in your script editor.

A Choose from List dialog will appear and show you the options for addressing that element.

By ID is preferred. If you use name, class name, etc. you’ll also need to provide a number. (The default is 0 for the first instance)

Select the ones you want to try, and paste them into the second script below (after the use statement).

That has the appropriate JavaScript handlers to click an element.

Uncomment handler calls for the method(s) you selected and pasted in above.

See if that works. (If you want to do more than click the element I may have a handler for that too.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

 set elementStuff to the clipboard

set clipboardText to ParseElementInspector(elementStuff)
set userSelection to choose from list clipboardText ¬
	with title ("Element Name, Id or Class") ¬
	with prompt ("Sected variable(s) for this element to copy/paste into your script") ¬
	default items 1 ¬
	OK button name ¬
	"Okay" cancel button name ¬
	"Cancel" multiple selections allowed true ¬
	with empty selection allowed
if userSelection is not in {false, {}} then
	
	set saveTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {return & return}
	set clipboardText to clipboardText as text
	set AppleScript's text item delimiters to saveTID
	set the clipboard to clipboardText
end if

on ParseElementInspector(elementInfo)
	set elementInfoText to {}
	set saveTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {" name="}
	set nameElements to text items of elementInfo
	if the (count of nameElements) > 1 then
		set elementName to text item 2 of nameElements
		set AppleScript's text item delimiters to {"\""}
		set elementName to text item 2 of elementName
		set the end of elementInfoText to "set theName to \"" & elementName & "\""
	end if
	set AppleScript's text item delimiters to {" id="}
	
	set idElements to text items of elementInfo
	if the (count of idElements) > 1 then
		set elementID to text item 2 of idElements
		set AppleScript's text item delimiters to {"\""}
		set elementID to text item 2 of elementID
		set the end of elementInfoText to "set theId to \"" & elementID & "\""
	end if
	
	set AppleScript's text item delimiters to {" class="}
	set classElements to text items of elementInfo
	if the (count of classElements) > 1 then
		set elementClass to text item 2 of classElements
		set AppleScript's text item delimiters to {"\""}
		set elementClass to text item 2 of elementClass
		set the end of elementInfoText to "set theClass to \"" & elementClass & "\""
	end if
	set AppleScript's text item delimiters to saveTID
	return elementInfoText
end ParseElementInspector

Handler Script


use scripting additions

set the elementNumber to 0
--set theScript to JSForClickByID(theId)
--set theScript to JSForClickByName(theName, elementnum)
--set theScript to JSForClickByClassName(theClassName, elementnum)
--set theScript to JSForClickBytagName(thetagName, elementnum)

tell application "Safari"
	activate
	set safariJSScriptResults to do JavaScript " " & theScript in current tab of window 1
end tell

to JSForClickByID(theId)
	return " document.getElementById('" & theId & "').click();"
end JSForClickByID

to JSForClickByName(theName, elementnum)
	return " document.getElementsByName('" & theName & "')[" & elementnum & "].click();"
end JSForClickByName

to JSForClickByClassName(theClassName, elementnum)
	return " document.getElementsByClassName('" & theClassName & "')[" & elementnum & "].click();"
end JSForClickByClassName

to JSForClickBytagName(thetagName, elementnum)
	return " document.getElementsByTagName('" & thetagName & "')[" & elementnum & "].click();"
end JSForClickBytagName


NOTE: These two snippets are from a JavaScriptBrowser library I’m working on. When it’s ready I’ll share if anyone’s interested.

Hi eStockly

I know I must be thick but I just cannot follow your I instructions properly.

When I select the box with the Ex-Div date I get this

Run the 1st routine and use selection is

Clipboard text is

I am sure I am not making this very clear. But I cannot copy the data from the listbox it just beeps but even if I could not sure where to put the result.

My apologies

It’s not you, it’s the script. It is definitely a work in progress, but I think you gave me some useful information.

What were looking for in doing the Inspect Element right-click is a way to identify the object. In this case it’s a button we want to click.

It’s best to use ID (because those are unique and you don’t need an element number).

In this case we have a class we can identify it with. The class a long and complicated name, but that makes it more likely it will be the right one, in my experience.

Try running this script with that page open in Safari.

If it clicks a button, but not the right button, you’ll need to try different numbers for the element number (1, 2, 3, etc.)

If it doesn’t work at all we can try something else.


 set theClassName to "t-py-3 t-mr-2 t-mb-2 t-w-max t-px-3 t-text-black hover:t-bg-mitre-gray-200 t-text-sm t-flex t-items-center t-relative t-min-w-150 t-justify-between"

set the elementNumber to 0
set theScript to JSForClickByClassName(theClassName, elementnum)

tell application "Safari"
	activate
	set safariJSScriptResults to do JavaScript " " & theScript in current tab of window 1
end tell

to JSForClickByClassName(theClassName, elementnum)
	return " document.getElementsByClassName('" & theClassName & "')[" & elementnum & "].click();"
end JSForClickByClassName


The confusing part to use elementNumber in JavaScript is that the top first button on the
page could be > 1. In other words it could be a number that Applescript user could only know
after testing. It would make sense to use xpath instead or better approach.

Ps.
The elementNumber is a index of a element and the first index could be a menu item.
Thats why a real button event could have the first element to be 5 or something else.
That is the reason why its difficult to count buttons visualy and define a elementNumber to click.

If the maintainer of the website update it… the elementNumber index will not maybe be the same
and it could brake the code.

Do you have an example of using xPath?

Ideally you would use the “id” of an element, but when that is not available you use name, classname, etc. with the element number. It does take trial and error to get right, and is vulnerable to the page layout changing, but as far as I know all schemes like this are.

Using the element number is also vulnerable to a page loading different HTML elements contextually, but (so far) I’ve found when they do that the elements I need generally have an ID.

@All

I will give you a solution how to use xpath from a chrome webdriver.

chrome webdriver could you get from here: https://chromedriver.storage.googleapis.com/index.html

Next

You need Selenium

Now you could make a python script like this.
You need to change the search path of the chromedriver
In this example I have done so in /usr/local/bin folder on my machine.

You have 2 examples in this python script checkbox and button click.
The button use xpath and checkbox is using element_id

If you do not know python its not so difficult to learn.

To know more about Selenium you could go here
https://www.selenium.dev
https://www.geeksforgeeks.org/how-to-get-current_url-using-selenium-in-python/?ref=lbp