Click a hard to reach button in Safari 500 times?

On this page VirusTotal I would like to click the “more”-button (the button with three dots) in the second section, the section that lists subdomains, 500+ times (to list all subdomains). How can I do that scriptwise in Safari?

I can’t find a working xpath nor can I tab to this button.

An ugly hack is perfectly fine!

Thank you.

I can get GUI scripting to work in Firefox, but not in Safari. I can’t get to the button with the 3 dots.

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

local myButton, myElement, subDomains, p, c, t
tell application "System Events" to tell application process "Firefox"
	set subDomains to group 1 of group 1 of group 2 of group 1 of group 2 of group 1 of group 1 of group 1 of group 8 of group 1 of group 1 of (group 1 of (group 2 of (group 1 of (UI element 1 of scroll area 1 of group 1 of group 1 of group 1 of window 1 whose role is "AXWebArea")) whose subrole is "AXApplicationGroup") whose subrole is "AXApplicationGroup")
	set c to count of UI elements of subDomains
	set myButton to group 1 of group 2 of group 2 of group 1 of group 2 of group 1 of group 1 of group 1 of group 8 of group 1 of group 1 of (group 1 of (group 2 of (group 1 of (UI element 1 of scroll area 1 of group 1 of group 1 of group 1 of window 1 whose role is "AXWebArea")) whose subrole is "AXApplicationGroup") whose subrole is "AXApplicationGroup")
	repeat 500 times
		tell myButton to perform action "AXPress"
		set p to c
		repeat with t from 40 to 1 by -1
			set c to count of UI elements of subDomains --group 1 of group 1 of group 2 of group 1 of group 2 of group 1 of group 1 of group 1 of group 8 of group 1 of group 1 of (group 1 of (group 2 of (group 1 of (UI element 1 of scroll area 1 of group 1 of group 1 of group 1 of window 1 whose role is "AXWebArea")) whose subrole is "AXApplicationGroup") whose subrole is "AXApplicationGroup")
			if c > p then exit repeat
		end repeat
		if t = 0 then
			tell me to say "Timed out!"
			return false
		end if
		if not (exists myButton) then exit repeat
	end repeat
end tell

only problem I’m running into is after awhile, Firefox will popup a captcha, and reset the page to beginning.

Virus Total seems to provide an API. Isn’t that an option?

I got my own free VirusTotal account and got an api-Key
Here is my AppleScript that uses the API.

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

property apiKey : "???????....????????" -- put your own api-key here
property theRec : missing value

local jsonString
set jsonString to do shell script "curl --request GET --url https://www.virustotal.com/api/v3/domains/google.com/subdomains --header 'accept: application/json' --header 'x-apikey: " & apiKey & "'" --4fa6204224833372be2b50078762c06b6542cd75027e8d33fa55c58051727a3d'"
set theRec to (current application's NSJSONSerialization's JSONObjectWithData:((current application's NSString's stringWithString:jsonString)'s dataUsingEncoding:(current application's NSUTF8StringEncoding)) options:0 |error|:(missing value)) as record

It works but it only returns the first 10 subdomains in an AppleScript record.
Still trying to figure out how to get more records, or it might be that I have to pay for a premium account.

Here’s a newer version that will loop thru 100 at a time till it gets them all.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
-- https://docs.virustotal.com/docs/url-search-modifiers

property apiKey : "????....?????"
property jlist : {}
property theRec : missing value

on run
	local jsonString, theCursor, theLink, c
	set progress description to "VirusTotal.com API"
	set progress additional description to "Preparing…"
	set progress total steps to -1
	set theLink to "https://www.virustotal.com/api/v3/domains/google.com/subdomains?limit=100"
	repeat until theLink = ""
		set jsonString to do shell script "curl --request GET --url '" & theLink & "' --header 'accept: application/json' --header 'x-apikey: " & apiKey & "'"
		set my theRec to (current application's NSJSONSerialization's JSONObjectWithData:((current application's NSString's stringWithString:jsonString)'s dataUsingEncoding:(current application's NSUTF8StringEncoding)) options:0 |error|:(missing value)) as record
		set c to count |data| of my theRec
		if c = 0 then exit repeat
		set my jlist to my jlist & |data| of my theRec
		set theLink to next of links of my theRec
		set progress additional description to "(" & (count of my jlist) & ") \"" & theLink & "\""
	end repeat
end run

Excellent! Thanks a lot!

Do you think you could explain what this line does?

Using AppleScriptObj-C it converts the jsonText to an AppleScript record using the Objective-C bridge.

Here is an updated version of my script.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
-- https://docs.virustotal.com/docs/url-search-modifiers

property apiKey : "????....????"
property jlist : {}
property theRec : missing value

on run
	local jsonString, theCursor, theLink, limit, encoding, c, t, p
	set limit to 50
	set p to "Preparing…"
	set progress description to "VirusTotal.com API"
	set progress additional description to p
	set progress total steps to -1
	set t to 0
	set theLink to "https://www.virustotal.com/api/v3/domains/google.com/subdomains?limit=" & limit
	set encoding to current application's NSUTF8StringEncoding
	repeat until theLink = ""
		set progress additional description to p & "'Getting'"
		set jsonString to do shell script "curl --request GET --url '" & theLink & "' --header 'accept: application/json' --header 'x-apikey: " & apiKey & "'"
		set progress additional description to p & "'Converting'"
		set my theRec to (current application's NSJSONSerialization's JSONObjectWithData:((current application's NSString's stringWithString:jsonString)'s dataUsingEncoding:encoding) options:0 |error|:(missing value)) as record
		set c to count |data| of my theRec
		if c < limit then exit repeat
		set t to t + c
		set my jlist to my jlist & |data| of my theRec
		try
			set theLink to next of links of my theRec
		on error
			set theLink to ""
			exit repeat
		end try
		set p to "(" & t & ") "
	end repeat
	
	say "Done"
end run

it does a better job of detecting the end of data

The amount of data that gets returned is large.
Do you have a list of the fields you actually want, so as to discard the ones not needed?

I only care about the subdomain, e.g.,

drive.google.com
mail.google.com

etc.

You could actually shorten than even more:

drive
mail

if it makes it easier.

Thank you.

Here is a newer version that is much faster because it only saves the domain name in the list “jList”…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
-- https://docs.virustotal.com/docs/url-search-modifiers

property apiKey : "????....????"
property jlist : {}
property theRec : missing value
property tmpList : missing value

on run
	local jsonString, theCursor, theLink, limit, encoding, c, t, p
	set limit to 100
	set p to "Preparing…"
	set progress description to "VirusTotal.com API"
	set progress additional description to p
	set progress total steps to -1
	set t to 0
	set theLink to "https://www.virustotal.com/api/v3/domains/google.com/subdomains?limit=" & limit
	set encoding to current application's NSUTF8StringEncoding
	repeat until theLink = ""
		set progress additional description to p & "'Getting'"
		set jsonString to do shell script "curl --request GET --url '" & theLink & "' --header 'accept: application/json' --header 'x-apikey: " & apiKey & "'"
		set progress additional description to p & "'Converting'"
		set my theRec to (current application's NSJSONSerialization's JSONObjectWithData:((current application's NSString's stringWithString:jsonString)'s dataUsingEncoding:encoding) options:0 |error|:(missing value)) as record
		set my tmpList to |data| of my theRec
		set c to count my tmpList
		repeat with j from 1 to c
			set end of my jlist to |id| of item j of my tmpList
		end repeat
		if c < limit then exit repeat
		set t to t + c
		try
			set theLink to next of links of my theRec
		on error
			set theLink to ""
			exit repeat
		end try
		set p to "(" & t & ") "
	end repeat
	
	say "Done"
end run

p.s. I increased the limit to 100 to go faster

I don’t understand the output. How can I get the result into a spreadsheet or similar?

Thank you.

I can add a section to output the results to a CSV text file.

1 Like

That would be very appreciated :slight_smile:

Here it is…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
-- https://docs.virustotal.com/docs/url-search-modifiers

property apiKey : "????....????"
property jlist : {}
property theRec : missing value
property tmpList : missing value

on run
	local fileName, jsonString, theCursor, theLink, limit, encoding, c, t, p
	set limit to 100
	set t to 0
	set progress description to "VirusTotal.com API"
	set progress additional description to "Preparing…"
	set progress total steps to -1
	try
		set fileName to choose file name with prompt "Enter File-Name to save VirusTotal data as csv…" default name "Untitled.csv"
	on error
		return
	end try
	set fileName to fileName as text
	set p to "(" & t & ") "
	set theLink to "https://www.virustotal.com/api/v3/domains/google.com/subdomains?limit=" & limit
	set encoding to current application's NSUTF8StringEncoding
	repeat until theLink = ""
		set progress additional description to p & "'Getting'"
		set jsonString to do shell script "curl --request GET --url '" & theLink & "' --header 'accept: application/json' --header 'x-apikey: " & apiKey & "'"
		set progress additional description to p & "'Converting'"
		set my theRec to (current application's NSJSONSerialization's JSONObjectWithData:((current application's NSString's stringWithString:jsonString)'s dataUsingEncoding:encoding) options:0 |error|:(missing value)) as record
		set my tmpList to |data| of my theRec
		set c to count my tmpList
		repeat with j from 1 to c
			set end of my jlist to |id| of item j of my tmpList
		end repeat
		if c < limit then exit repeat
		set t to t + c
		try
			set theLink to next of links of my theRec
		on error
			set theLink to ""
			exit repeat
		end try
		set p to "(" & t & ") "
	end repeat
	try
		set fileName to open for access fileName with write permission
	on error eStr number eNum
		display alert "Error opening file " & fileName giving up after 10
		return false
	end try
	set eof fileName to 0
	set tid to text item delimiters
	set text item delimiters to return
	write (jlist as text) to fileName
	close access fileName
	set text item delimiters to tid
	say "Done"
end run