Applescript - Take Screenshot of ENTIRE Web Page - Safari

Hi there,

Is it possible to take a screenshot of the entire web page in safari?
I need an applescript that will do this - the page itself would require scrolling in order to see the entire thing.

Thanks!

Open Safari to the url you would like to get the image of. Then run this:


tell application "Safari"
	activate
	set winID to id of window 1
end tell

do shell script "screencapture -c -x -l " & winID

Thanks for your reply Halosurferdude,

But that script does nothing on my machine :frowning:

It certainly worked : it put the screenshot in the clipboard.

The problem is that it captures only what is displayed on the screen, not the entire page.

If you want to get the entire page you may use Print in a PDF.

# Build the name of the PDF to fit your needs
set thePDFname to "beurk.pdf"
set thePDFPath to (path to documents folder as text) & "the PDFs:"
set posixFolderPath to POSIX path of thePDFPath





tell application "System Events"
	set frontmostProcess to first process where it is frontmost -- this will be the script process
	if name of frontmostProcess is in {"Script Editor", "AppleScript Editor"} then # CAUTION the name changed
		set visible of frontmostProcess to false -- hide the script process
		repeat while (frontmostProcess is frontmost) -- wait until the script is hiden
			delay 0.2
		end repeat
		tell (first process where it is frontmost)
			set theProcess to its name
			set theApp to its file
		end tell
		set frontmost of frontmostProcess to true -- unhide the script process
	else
		tell frontmostProcess
			set theProcess to its name
			set theApp to its file
		end tell
	end if
	set theApp to name of theApp
end tell

activate application theApp
tell application "System Events" to tell process theProcess
	set nbw to count windows
	keystroke "p" using command down
	(*
Wait for the availability of the sheet *)
	repeat
		if exists sheet 1 of window 1 then exit repeat
	end repeat
	--name of menu buttons of sheet 1 of window 1
	--> {"PDF"} # but I don't know if it's spelled this way worldwide
	tell sheet 1 of window 1
		set PDFButton to first menu button
		click PDFButton
		-- name of menu items of menu 1 of PDFButton
		--> {"Ouvrir le PDF dans Aperçu", "Enregistrer au format PDF
", "Enregistrer au format PostScript
", "Faxer le document PDF
", missing value, "@ PDF-BAT.qfilter", "@ PDF-prĂ©presse CMJN.qfilter", "@ PDF-web.qfilter", "@ PDFX3-ISO.qfilter", "Add PDF to iTunes", "Envoyer le document PDF par courrier Ă©lectronique", "Enregistrer le document PDF dans le dossier de reçus web", missing value, "Modifier le menu
"}
		
		click menu item 2 of menu 1 of PDFButton
		(*
Wait for the availability of the Print sheet *)
		repeat
			if exists sheet 1 then exit repeat
		end repeat
		
		(*
Set the name of the new PDF *)
		tell sheet 1
			# Set the Desktop as destination folder
			
			set value of text field 1 to thePDFname
			keystroke "g" using {command down, shift down}
			repeat until exists sheet 1
				delay 0.02
			end repeat
			tell sheet 1
				# CAUTION. before 10.11 the target field was a text field. Now it's a combo box
				if class of UI elements contains combo box then
					--> {static text, combo box, button, button}
					set value of combo box 1 to posixFolderPath
				else
					--> {static text, text field, button, button}
					set value of text field 1 to posixFolderPath
				end if
				get name of buttons (*Aller, Annuler*)
				keystroke return # ditto click button 1 (ou Aller)
			end tell
			get name of buttons
			--> {missing value, missing value, missing value, "Enregistrer", "Nouveau dossier", "Annuler"}
			--click button -3 -- ditto keystroke return
			keystroke return
		end tell # sheet 1 (the Save As one)
	end tell # sheet 1 of window 1
end tell

# Now the pdf is available in the defined folder. 

If you may have use for the screencapture feature, here are several instructions using it :


tell application "Safari"
	activate
	set winID to id of window 1
end tell

# store the screenshot in the clipboard
--do shell script "screencapture -c -x -l " & winID

# WARNING : I found no explanation about the -l parameter.

# store the screenshot in the defined location
--do shell script "screencapture -x " & quoted form of POSIX path of ((path to desktop as text) & "my screenshot.png") & space & winID

# store the screenshot in the defined location and open it in Preview
--do shell script "screencapture -x -P " & quoted form of POSIX path of ((path to desktop as text) & "my screenshot.png") & space & winID

# store the screenshot in the defined location and open it in Preview. It allow you to define interactively the area to capture.
do shell script "screencapture -x -i -P " & quoted form of POSIX path of ((path to desktop as text) & "my screenshot.png") & space & winID

I would interested if somebody may explain what the -l parameter is supposed to rule.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) mercredi 2 aout 2017 18:44:21

Yvan,

Bonjour! (Well its day here and I lived in Bordeaux when in first and second grade.)

-l followed by the window ID specifies that screen capture operate on the specific window.

The call

do shell script "screencapture -c -x -l " & winID

specifies to copy to the clipboard (-c), no sound (-x), at specified window (-l).

Your solution to get the entire page and not just the screen shot is nicely done.

Best!

Thanks

I asked because there is no parameter -l in the man page.
I just found the parameter -i whose description is :
[format]-i Capture screen interactively, by selection or window. The con-
trol key will cause the screen shot to go to the clipboard. The
space key will toggle between mouse selection and window selec-
tion modes. The escape key will cancel the interactive screen
shot.[/format]

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) mercredi 2 aout 2017 21:25:17

For the fun I built an alternate version which extract the localized strings used from system resources.

# Build the name of the PDF to fit your needs
set thePDFname to "beurk.pdf"
set thePDFPath to (path to documents folder as text) & "the PDFs:"
set posixFolderPath to POSIX path of thePDFPath

# Extract the localized strings
set theBundle to (path to library folder from system domain as text) & "PrivateFrameworks:PrintingPrivate.framework:Versions:A:Plugins:PrintCocoaUI.bundle:Contents:Resources:"
set x to "64.title"
set SaveAsPDFellipsis_loc to localized string x from table "CocoaPrintWindow" in bundle (theBundle as «class furl») --> "Enregistrer au format PDF
"
(*
set x to "64.ibExternalAccessibilityDescription"
set SaveAsPDF_loc to localized string x from table "CocoaPrintWindow" in bundle (theBundle as «class furl») --> "Enregistrer au format PDF" # I don't know where it's used
*)
set x to "65.title"
set PDF_loc to localized string x from table "CocoaPrintWindow" in bundle (theBundle as «class furl») --> "PDF"


tell application "System Events"
	set frontmostProcess to first process where it is frontmost -- this will be the script process
	if name of frontmostProcess is in {"Script Editor", "AppleScript Editor"} then # CAUTION the name changed
		set visible of frontmostProcess to false -- hide the script process
		repeat while (frontmostProcess is frontmost) -- wait until the script is hiden
			delay 0.2
		end repeat
		tell (first process where it is frontmost)
			set theProcess to its name
			set theApp to its file
		end tell
		set frontmost of frontmostProcess to true -- unhide the script process
	else
		tell frontmostProcess
			set theProcess to its name
			set theApp to its file
		end tell
	end if
	set theApp to name of theApp
end tell # System Events

activate application theApp
tell application "System Events" to tell process theProcess
	--set nbw to count windows # unused
	set frontmost to true
	keystroke "p" using command down
	(*
Wait for the availability of the sheet *)
	repeat
		if exists sheet 1 of window 1 then exit repeat
	end repeat
	--class of UI elements of sheet 1 of window 1
	--> {group, static text, group, static text, pop up button, static text, pop up button, static text, text field, checkbox, static text, radio button, radio button, text field, static text, text field, static text, pop up button, static text, static text, radio group, static text, text field, pop up button, checkbox, checkbox, button, menu button, button, button, button}
	--name of menu buttons of sheet 1 of window 1
	--> {"PDF"} # but I don't know if it's spelled this way worldwide
	tell sheet 1 of window 1
		click menu button PDF_loc
		-- name of menu items of menu 1 of PDFButton
		--> {"Ouvrir le PDF dans Aperçu", "Enregistrer au format PDF
", "Enregistrer au format PostScript
", "Faxer le document PDF
", missing value, "@ PDF-BAT.qfilter", "@ PDF-prĂ©presse CMJN.qfilter", "@ PDF-web.qfilter", "@ PDFX3-ISO.qfilter", "Add PDF to iTunes", "Envoyer le document PDF par courrier Ă©lectronique", "Enregistrer le document PDF dans le dossier de reçus web", missing value, "Modifier le menu
"}
		
		click menu item SaveAsPDFellipsis_loc of menu 1 of menu button PDF_loc
		(*
Wait for the availability of the Print sheet *)
		repeat
			if exists sheet 1 then exit repeat
		end repeat
		
		(*
Set the name of the new PDF *)
		tell sheet 1
			# Set the Desktop as destination folder
			
			set value of text field 1 to thePDFname
			keystroke "g" using {command down, shift down}
			repeat until exists sheet 1
				delay 0.02
			end repeat
			tell sheet 1
				# CAUTION. before 10.11 the target field was a text field. Now it's a combo box
				(*
				if class of UI elements contains combo box then
					--> {static text, combo box, button, button}
					set value of combo box 1 to posixFolderPath
				else
					--> {static text, text field, button, button}
					set value of text field 1 to posixFolderPath
				end if
				*)
				# An alternate way would be 
				set value of UI element 2 to posixFolderPath
				# But there is no guarantee that the index remains equal to 2
				get name of buttons (*Aller, Annuler*)
				keystroke return # ditto click button 1 (ou Aller)
			end tell
			get name of buttons
			--> {missing value, missing value, missing value, "Enregistrer", "Nouveau dossier", "Annuler"}
			--click button -3 -- ditto keystroke return
			keystroke return
		end tell # sheet 1 (the Save As one)
	end tell # sheet 1 of window 1
end tell

# Now the pdf is in the defined folder.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) jeudi 3 aout 2017 12:09:22

Thank you Yvan!

I made a small modification, so that it sets date and time as the filename and saves it into a screenshot folder on the desktop.

(my management of dates and times in applescript needs some work, I know.)

Your solution works perfectly!

set {year:y, month:m, day:d} to (current date)
set CurrentTime to (do shell script "date +\"%l %M %p\" | awk '{$1=$1;print}'")
set theDate to y & space & m & space & d as text
set ssfileName to theDate & " - " & CurrentTime & ".pdf"

set thePDFPath to (path to desktop folder as text) & "Screenshots"
set posixFolderPath to POSIX path of thePDFPath


tell application "Safari"
	activate
	delay 1
	set the URL of the front document to "http://www.google.com"
	delay 30
end tell

tell application "System Events"
	set frontmostProcess to first process where it is frontmost -- this will be the script process
	if name of frontmostProcess is in {"Script Editor", "AppleScript Editor"} then # CAUTION the name changed
		set visible of frontmostProcess to false -- hide the script process
		repeat while (frontmostProcess is frontmost) -- wait until the script is hidden
			delay 0.2
		end repeat
		tell (first process where it is frontmost)
			set theProcess to its name
			set theApp to its file
		end tell
		set frontmost of frontmostProcess to true -- unhide the script process
	else
		tell frontmostProcess
			set theProcess to its name
			set theApp to its file
		end tell
	end if
	set theApp to name of theApp
end tell

activate application theApp
tell application "System Events" to tell process theProcess
	set nbw to count windows
	keystroke "p" using command down
	
	repeat
		if exists sheet 1 of window 1 then exit repeat
	end repeat
	
	tell sheet 1 of window 1
		set PDFButton to first menu button
		click PDFButton
		click menu item 2 of menu 1 of PDFButton
		
		repeat
			if exists sheet 1 then exit repeat
		end repeat
		
		
		tell sheet 1
			# Set the Desktop as destination folder
			
			set value of text field 1 to ssfileName
			delay 2
			keystroke "g" using {command down, shift down}
			repeat until exists sheet 1
				delay 2
			end repeat
			tell sheet 1
				# CAUTION. before 10.11 the target field was a text field. Now it's a combo box
				if class of UI elements contains combo box then
					--> {static text, combo box, button, button}
					set value of combo box 1 to posixFolderPath
				else
					--> {static text, text field, button, button}
					set value of text field 1 to posixFolderPath
				end if
				get name of buttons
				keystroke return
			end tell
			get name of buttons
			
			keystroke return
		end tell
	end tell
end tell


Here’s an alternative approach. It creates an invisible Web view of the same size, downloads the URL again, then saves it a PDF. About the only difference in the result is that the resulting PDF is a single page, no breaks.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
property theView : missing value -- the WebView
property pdfData : missing value -- the PDF data
property theTitle : missing value -- the frame title
property readyFlag : true -- flag that signifies done
use scripting additions

tell application "Safari"
	tell (window 1 whose visible is true)
		set {x1, y1, x2, y2} to bounds
		set theURL to URL of tab 1 whose visible is true
	end tell
end tell

if current application's NSThread's isMainThread() as boolean then
	-- set up WebView
	my setUpWebviewSized:{x2 - x1, y2 - y1}
	-- load the URL
	my processURL:theURL
else
	-- set up WebView
	my performSelectorOnMainThread:"setUpWebviewSized:" withObject:{x2 - x1, y2 - y1} waitUntilDone:true
	-- load the URL
	(my performSelectorOnMainThread:"processURL:" withObject:theURL waitUntilDone:true)
end if
repeat while not my readyFlag
	delay 0.3
end repeat
set thePath to current application's NSString's stringWithFormat_("%@/%@.pdf", POSIX path of (path to desktop), theTitle)
pdfData's writeToFile:thePath atomically:true
display dialog "Finished" buttons {"OK"} default button 1

-- needs to be done on the main thread
on setUpWebviewSized:theSize
	-- make a WebView
	set my theView to current application's WebView's alloc()'s initWithFrame:{origin:{x:0, y:0}, |size|:theSize}
	-- tell it to call delegate methods on me
	theView's setFrameLoadDelegate:me
end setUpWebviewSized:

-- needs to be done on the main thread
on processURL:thePageURL
	-- load the page
	(my theView)'s setMainFrameURL:thePageURL
	-- set ready flag to false
	set my readyFlag to false
end processURL:

-- called when the WebView loads a frame
on WebView:aWebView didFinishLoadForFrame:webFrame
	-- the main frame is our interest
	if webFrame = aWebView's mainFrame() then
		set my theTitle to aWebView's mainFrameTitle()'s stringByReplacingOccurrencesOfString:"/" withString:"_"
		set docView to webFrame's frameView()'s documentView()
		set my pdfData to docView's dataWithPDFInsideRect:(docView's frame())
		set my readyFlag to true
	end if
end WebView:didFinishLoadForFrame:

on WebView:WebView didFailLoadWithError:theError forFrame:webFrame
	-- got an error, bail
	WebView's stopLoading:me
	error theError's localizedDescription() as text
end WebView:didFailLoadWithError:forFrame:

Thank you Shane.

Will be part of my library of scripts.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) jeudi 3 aout 2017 15:38:48

I was asked about my old GUI scripting version because some details evolved.
Here is the updated version.

(*
http://www.macscripter.net/viewtopic.php?id=45871
*)

# Build the path of the folder storing the PDFs to fit your needs
set thePDFsRoot to (path to documents folder as text)
set theFolderName to "the PDFs"
set thePDFsFolder to thePDFsRoot & theFolderName
tell application "System Events"
	# Grab the system version
	set sys2 to (system attribute "sys2") as integer
	if not (exists folder thePDFsFolder) then make new folder at end of folder thePDFsRoot with properties {name:theFolderName}
end tell
set posixPDFsFolder to POSIX path of thePDFsFolder

# Extract the localized strings
set theBundle to ((path to library folder from system domain as text) & "PrivateFrameworks:PrintingPrivate.framework:Versions:Current:Plugins:PrintCocoaUI.bundle:Contents:Resources:") as «class furl»

set x to "64.title"
set SaveAsPDF_loc to localized string x from table "CocoaPrintWindow" in bundle theBundle --> "Enregistrer au format PDF
"
if SaveAsPDF_loc is x then
	if sys2 < 13 then -- there is an ellipsis (or 3 dots) but I'm not sure that the resource is available
		-- 10.10 appends ellipsis (or 3 dots) but the resource isn't available
		set SaveAsPDF_loc to 2 -- use the index which will not be modified
	else
		set SaveAsPDF_loc to "Save as PDF"
	end if
end if

set x to "65.title"
set PDF_loc to localized string x from table "CocoaPrintWindow" in bundle theBundle --> "PDF"
if PDF_loc is x then set PDF_loc to "PDF"

set x to "Save"
set save_loc to localized string x from table "Localizable" in bundle theBundle --> "Enregistrer"

tell application "System Events"
	set frontmostProcess to first process where it is frontmost -- this will be the script process
	if name of frontmostProcess is in {"Script Editor", "AppleScript Editor", "Script Debugger"} then # CAUTION the name changed
		set visible of frontmostProcess to false -- hide the script process
		repeat while (frontmostProcess is frontmost) -- wait until the script is hiden
			delay 0.2
		end repeat
		tell (first process where it is frontmost)
			set theProcess to its name
			set theApp to its file
		end tell
		set frontmost of frontmostProcess to true -- unhide the script process
	else
		tell frontmostProcess
			set theProcess to its name
			set theApp to its file
		end tell
	end if
	set theApp to name of theApp
end tell # System Events
if theProcess is "Finder" then error "Can't print Finder windows"

activate application theApp
tell application "System Events" to tell process theProcess
	set frontmost to true
	class of UI elements --> {window, menu bar}
	set wName to name of window 1
	set nbWindows to count windows
	keystroke "p" using command down
	-- Two behaviors exist
	set gotIt to false
	repeat 10 times
		if (count windows) > nbWindows then
			set gotIt to true
			set targetItem to window 1 -- Firefox use this case
			exit repeat
		end if
		if exists sheet 1 of window 1 then
			set gotIt to true
			set targetItem to sheet 1 of window 1 -- Safari use this case
			exit repeat
		end if
		delay 0.2
	end repeat
	if not gotIt then error "No print sheet or window available"
	
	tell targetItem
		-- class of UI elements --> --> {static text, pop up button, static text, pop up button, static text, text field, checkbox, static text, radio button, radio button, text field, static text, text field, static text, pop up button, static text, static text, radio group, static text, text field, pop up button, static text, checkbox, checkbox, static text, checkbox, checkbox, static text, static text, static text, static text, static text, pop up button, pop up button, pop up button, pop up button, pop up button, pop up button, button, menu button, button, button, button, static text}
		click menu button PDF_loc
		-- name of menu items of menu 1 of menu button PDF_loc
		--> {"Ouvrir le PDF dans Aperçu", "Enregistrer au format PDF
", "Enregistrer au format PostScript
", "Faxer le document PDF
", missing value, "@ PDF-BAT.qfilter", "@ PDF-prĂ©presse CMJN.qfilter", "@ PDF-web.qfilter", "@ PDFX3-ISO.qfilter", "Add PDF to iTunes", "Envoyer le document PDF par courrier Ă©lectronique", "Enregistrer le document PDF dans le dossier de reçus web", missing value, "Modifier le menu
"}
		-- use the index with 10.10
		click menu item SaveAsPDF_loc of menu 1 of menu button PDF_loc
		(*
Wait for the availability of the Print sheet *)
		repeat
			if exists sheet 1 then exit repeat
		end repeat
		(*
Set the name of the new PDF *)
		tell sheet 1
			-- class of UI elements --> {static text, text field, UI element, static text, text field, group, radio group, group, pop up button, text field, splitter group, text field, static text, button, text field, static text, text field, static text, static text, text field, button, button, button}
			set thePDFname to wName & "_" & my dateTimeStamp() & ".pdf"
			set thePDFname to my remplace(thePDFname, {"/", ":"}, "|") -- I know, I'm a bit paranoid
			set value of text field 1 to thePDFname
			keystroke "g" using {command down, shift down}
			repeat until exists sheet 1
				delay 0.02
			end repeat
			tell sheet 1
				# CAUTION. before 10.11 the target field was a text field. Now it's a combo box
				-- class of UI elements
				--> {static text, text field, button, button} -- with 10.10 and older systems
				--> {static text, combo box, button, button} -- 10.11, 10.12, 10.13, 10.14, 10.15
				if exists combo box 1 then
					set value of combo box 1 to posixPDFsFolder
				else
					set value of text field 1 to posixPDFsFolder
				end if
				get name of buttons (*Aller, Annuler*)
				keystroke return # ditto click button 1 (ou Aller)
			end tell
			get name of buttons
			--> {missing value, missing value, missing value, "Enregistrer", "Nouveau dossier", "Annuler"}
			-- CAUTION, whith High Sierra and newer OS, the buttons are:
			--> {"Options de sĂ©curité ", "Nouveau dossier", "Annuler", "Enregistrer"}
			-- So clicking button -3 no longer apply
			-- we may apply click button save_loc or issue the shortcut 'return'
			keystroke return
		end tell # sheet 1 (the Save As one)
	end tell #  targetItem
end tell

# Now the pdf is in the defined folder.

#=====
(*
replaces every occurences of d1 by d2 in the text t
*)
on remplace(t, d1, d2)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d1}
	set l to text items of t
	set AppleScript's text item delimiters to d2
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end remplace

#=====

on dateTimeStamp()
	tell (current date) to return (((its year) * 10000 + (its month) * 100 + (its day)) as text) & "_" & text 2 thru -1 of ((1000000 + (its hours) * 10000 + (its minutes) * 100 + (its seconds)) as text)
end dateTimeStamp

#=====

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 6 mars 2020 18:45:40

Edited to give a custom name to the created PDF.

My script isn’t dedicated to Safari.
It apply to most applications.
Sometimes, the Print pane is a sheet but sometimes, the Print pane is a window.
I don’t know what rules that but my script do the job in both cases.

I was really interested by Shane’s proposal 
 until I applied it upon a document containing 10 pages.
The result was a document displaying the entire doc in a single page making it perfectly unusable.
Maybe there is a way to urge the code to split the stamp in a document of several readable pages but I don’t know it.
So, I returned to the brave old GUI scripting process.

@KniazidisR

Maybe because I never found the syntax required to use it. And I am not the unique being in this case.

set thePath to ((path to desktop as text) & "azer.pdf")
tell application "Safari"
	activate
	save document 1 in file thePath as "com.adobe.pdf"
end tell

issue : error “Erreur dans Safari : document 1 ne comprend pas le message « save ».” number -1708 from document 1
Same behavior of I try to apply the save command to window 1 or if I try to save as “PDF”.
Ditto if I define the path as a «class furl» object.
I never liked to play the sooth sayer so I use what I may work with.

Of course, if you know the correct incantation, I will be glad to learn it.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) vendredi 6 mars 2020 21:19:07

Here is simple version, using Web Inspector:


tell application "Safari"
	activate
	open location "https://www.apple.com"
end tell

tell application "System Events" to tell application process "Safari"
	repeat until (UI element "Reload this page" of group 2 of toolbar 1 of window 1 exists)
		delay 0.1
	end repeat
	display notification "The webpage is fully loaded now." sound name "Frog"
	click menu item "Show Web Inspector" of menu 1 of menu bar item "Develop" of menu bar 1
	repeat until tab group 1 of UI element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window 1 exists
		delay 0.1
	end repeat
	tell group 1 of tab group 1 of splitter group 1 of window 1
		tell static text 1 of group 2 of group 2 of group 2 of UI element 1 of scroll area 1 of group 1 to perform action "AXShowMenu"
		click menu item "Capture Screenshot" of menu 1
	end tell
	repeat until sheet 1 of window 1 exists
		delay 0.1
	end repeat
	click button "Save" of sheet 1 of window 1
end tell

tell application "Safari" to close tab 1 of window 1

@KniazidisR

I will localize your proposal to test it.

My script works with all tested applications.
Firefox is one of those which doesn’t use a sheet but a window.
I edited my message so that the script use a custom PDF name.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 7 mars 2020 11:18:48

@ KniazidisR

I did my best to localize your proposal.
I failed to find the resources describing the late menu so I trigger the wanted menu item by its index.
Would be good to check that it’s the correct index for the running operating system.

As you may see, I was forced to redesign the piece of code supposed to wait for the UI element “Reload this page”.

On my machine, the wanted item is not in group 2 but in group 3 and it can’t be identified by its name.

Some extraneous instructions display what is available here in group 2.

As I am pig headed I will continue to search for the resource describing the final menu but I am skeptical because my dedicated tools failed during my late attempts.


# Extract the localized strings
set theBundle to ((path to library folder from system domain as text) & "PrivateFrameworks:PrintingPrivate.framework:Versions:Current:Plugins:PrintCocoaUI.bundle:Contents:Resources:") as «class furl»
set x to "Save"
set save_loc to localized string x from table "Localizable" in bundle theBundle --> "Enregistrer"

set theBundle to ((path to library folder from system domain as text) & "PrivateFrameworks:Safari.framework:") as «class furl»
set x to "Reload this page"
set reloadThisPage_loc to localized string x from table "Localizable" in bundle theBundle --> "Recharger cette page"

set x to "Show Web Inspector"
set showWebInspector_loc to localized string x from table "Localizable" in bundle theBundle --> "Afficher l’inspecteur web"

set x to "Develop"
set develop_loc to localized string x from table "Localizable" in bundle theBundle --> "DĂ©veloppement"
(*
set x to "Capture Screenshot"
set captureScreenshot_loc to localized string x from table "Localizable" in bundle theBundle --> "Capture Screenshot" when it was supposed to return "Capturer l’aperçu" because there is no such resource
*)
tell application "Safari"
	activate
	open location "https://www.apple.com"
end tell

tell application "System Events" to tell application process "Safari"
	set frontmost to true
	repeat 100 times
		if (description of UI elements of group -1 of toolbar 1 of window 1) contains reloadThisPage_loc then exit repeat
		delay 0.1
	end repeat
	try
		tell button 1 of UI element 1 of group 2 of toolbar 1 of window 1
			its name --> missing value
			its description --> "uBlock Safari Icon"
		end tell
	end try
	display notification "The webpage is fully loaded now."
end tell

tell application "System Events" to tell application process "Safari"
	--keystroke "i" using {command down, option down}
	click menu item showWebInspector_loc of menu 1 of menu bar item develop_loc of menu bar 1
	repeat until tab group 1 of UI element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window 1 exists
		delay 0.1
	end repeat
	tell group 1 of tab group 1 of splitter group 1 of window 1
		click static text 1 of group 2 of group 2 of group 2 of UI element 1 of scroll area 1 of group 1
		tell static text 1 of group 2 of group 2 of group 2 of UI element 1 of scroll area 1 of group 1 to perform action "AXShowMenu"
		
		(name of menu items of menu 1) --> {"Ajouter", "Modifier", "Copier", "Supprimer", "Activer/DĂ©sactiver la visibilitĂ©", missing value, "Pseudo-classes forcĂ©es", missing value, "S’arrĂȘter", missing value, "Consigner l’élĂ©ment", "Capturer l’aperçu", "Faire dĂ©filer dans la prĂ©sentation", missing value, "Tout dĂ©velopper", "Tout condenser"}
		name of menu item -5 of menu 1 --> "Capturer l’aperçu"
		name of menu item 12 of menu 1 --> "Capturer l’aperçu"
		click menu item -5 of menu 1
	end tell
	repeat until sheet 1 of window 1 exists
		delay 0.1
	end repeat
	click button save_loc of sheet 1 of window 1
end tell

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) samedi 7 mars 2020 14:14:33

  1. The click static text 1
. instruction in my script is redundant. It can be removed.
  2. The newly opened tab can be closed after taking screenshot.
  3. Recent operations can be performed inside the 1 single tell application “System Events” to tell application process “Safari” block.

I updated my script according to the last 3 comments.

Here is a point of departure.


# Extract the localized strings
set theBundle to ((path to library folder from system domain as text) & "Frameworks:WebKit.framework:Versions:Current:Frameworks:WebCore.framework:") as «class furl»
set x to "Inspect Element"
set inspectElement_loc to localized string x from table "Localizable" in bundle theBundle --> "Enregistrer"

tell application "Safari"
	activate
end tell

tell application "System Events" to tell application process "Safari"
	set frontmost to true
	set {{x, y}, {w, h}} to {position, size} of window 1
	tell me to do shell script "/usr/local/bin/cliclick rc:" & x + w div 2 & "," & y + h div 2
	tell window 1
		-- class of UI elements --> {splitter group, button, button, button, group, button, group, toolbar}
		tell splitter group 1
			-- class of UI elements --> {splitter, tab}
			tell tab group 1
				-- class of UI elements --> {group}
				tell group 1
					-- class of UI elements --> {group, menu}
					tell menu 1
						-- class of UI elements --> {menu item, menu item, menu item, menu item, menu item, menu item, menu item, menu item, menu item}
						-- 	name of menu items--> {"PrĂ©cĂ©dent", "Recharger la page", "Ouvrir dans Dashboard
", missing value, "Afficher le code source de la page", "Enregistrer la page en tant que
", "Imprimer la page
", missing value, "Inspecter l’élĂ©ment"}
						click menu item inspectElement_loc
					end tell
				end tell
			end tell
		end tell
	end tell
end tell
-- Now, the Web Inspector is open

But I don’t understand what you want to do after reaching this point.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 8 mars 2020 16:59:09

I downloaded your examples but I don’t understand how you selected the wanted block after revealing the inspector.

I take the opportunity to post an enhanced version of the KniazidisR’s proposal.
I built it because during my tests I clicked on the radio button [Resources] which modified the behavior of the Web Inspector and discovered that the setting remains as is as long as I didn’t reset the original setting.
So I decided to urge the script to do the job.
As is, my version used the ‘developed’ structure.
You are free to compact it if you want.

Of course we may add the new instructions in the code triggering the contextual menu.

Other interesting news, I found the file storing the name of the menu item triggered in KniazidisR’s script. It’s a file named localizedStrings.js located in (path to library folder from system domain as text)& “PrivateFrameworks:WebInspectorUI.framework:Versions:A:Resources:fr.lproj:” (en.lproj for the English resource).
I have a script able to extract the localized version ‘on the fly’ but, in text format it uses 3154 bytes so I’m not sure that it’s a good idea to embed it in main scripts.

I will work again to refine it and will post it here some times ago so everybody will be free to use it. I will also post the script scanning the available resource files to identify the interesting one.
It’s boring because some files are encoded using utf8 but some others use ut16 :rolleyes:

-- https://macscripter.net/viewtopic.php?id=45871
----------------------------------------------------------------
use AppleScript version "2.5"
use framework "Foundation"
use scripting additions
----------------------------------------------------------------
# Extract the localized strings
set theBundle to ((path to library folder from system domain as text) & "PrivateFrameworks:PrintingPrivate.framework:Versions:Current:Plugins:PrintCocoaUI.bundle:Contents:Resources:") as «class furl»
set x to "Save"
set save_loc to localized string x from table "Localizable" in bundle theBundle --> "Enregistrer"

set theBundle to ((path to library folder from system domain as text) & "PrivateFrameworks:Safari.framework:") as «class furl»
set x to "Add page to Reading List"
set addPageToReadingList_loc to localized string x from table "Localizable" in bundle theBundle --> "Ajouter la page Ă  la liste de lecture"
set x to "Reload this page"
set reloadThisPage_loc to localized string x from table "Localizable" in bundle theBundle --> "Recharger cette page"

set x to "Show Web Inspector"
set showWebInspector_loc to localized string x from table "Localizable" in bundle theBundle --> "Afficher l’inspecteur web"
set x to "Hide Web Inspector"
set hideWebInspector_loc to localized string x from table "Localizable" in bundle theBundle --> "Masquer l’inspecteur web"

set x to "Develop"
set develop_loc to localized string x from table "Localizable" in bundle theBundle --> "DĂ©veloppement"

set x to "Capture Screenshot"
set captureScreenshot_loc to localized string x from table "Localizable" in bundle theBundle --> "DĂ©veloppement"

-- build the path to the resource file so we may reuse it if several strings are defined in it.
set theSource to my getResourceFile:((path to library folder from system domain as text) & "PrivateFrameworks:WebInspectorUI.framework:Versions:A:Resources:") fromTable:"localizedStrings.js"
set x to "Capture Screenshot"
set captureScreenshot_loc to my localize:x storedIn:theSource

tell application "Safari"
	activate
	open location "https://www.apple.com"
end tell

tell application "System Events" to tell application process "Safari"
	set frontmost to true
	repeat with i from 2 to (count groups of toolbar 1 of window 1)
		try
			if (description of UI elements of group i of toolbar 1 of window 1) contains addPageToReadingList_loc then exit repeat
			--> i = 2 --> {"uBlock Safari Icon"}
			--> i = 3 --> {"Ajouter la page Ă  la liste de lecture", "Certificat de Validation Ă©tendue Apple Inc.", "Adresse et recherche", "Interrompre le chargement de cette page"}
			--> i = 4 -- why not ?
		end try
	end repeat
	-- Now i is the index of the group to check. 
	-- After all we may imagine a 3rd party item installing a group at index 4
	-- as uBlock install its one at index 2
	repeat 100 times
		if (exists UI element reloadThisPage_loc of group i of toolbar 1 of window 1) then exit repeat
		delay 0.1
	end repeat
	tell me to display notification "The webpage is fully loaded now."
end tell

# Build the path of the folder storing the screenshot to fit your needs
set thePictures to (path to pictures folder as text)
set theFolderName to "Screenshots"
set theScreenshotsFolder to thePictures & theFolderName
tell application "System Events"
	if not (exists folder theScreenshotsFolder) then make new folder at end of folder thePictures with properties {name:theFolderName}
end tell
set posixScreenshotsFolder to POSIX path of theScreenshotsFolder

tell application "System Events" to tell application process "Safari"
	set frontmost to true -- Useful if we don't use the block downloading the Web page
	-- keystroke "i" using {command down, option down}
	click menu item showWebInspector_loc of menu 1 of menu bar item develop_loc of menu bar 1
	repeat until tab group 1 of UI element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window 1 exists
		delay 0.1
	end repeat
	
	tell group 1 of tab group 1 of splitter group 1 of window 1
		-- class of UI elements --> {group}
		tell group 1
			-- class of UI elements --> {scroll area}
			tell scroll area 1
				-- class of UI elements --> {UI element}
				tell UI element 1
					-- class of UI elements --> {group, toolbar, tab, group, group, group, group, group}
					tell tab group 1
						-- class of UI elements --> {group, radio button, radio button, radio button, radio button, radio button, radio button, radio button, radio button, radio button, radio button, radio button}
						-- name of radio buttons --> {"ÉlĂ©ments", "RĂ©seau", "DĂ©bogueur", "Ressources", "Chronologies", "Stockage", "Canvas", "Audit", "Console", missing value, missing value}
						click radio button 1 -- reset the 'standard' behavior
					end tell
					tell group 2
						-- class of UI elements --> {group, group}
						tell group 2
							-- class of UI elements --> {group, group, group}
							tell group 2
								-- class of UI elements --> {static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text}
								-- name of static text 1 --> "<"
								tell static text 1 to perform action "AXShowMenu"
							end tell
						end tell
					end tell
				end tell
			end tell
		end tell
		-- name of menu items of menu 1 --> {"Ajouter", "Modifier", "Copier", "Supprimer", "Activer/DĂ©sactiver la visibilitĂ©", missing value, "Pseudo-classes forcĂ©es", missing value, "S’arrĂȘter", missing value, "Consigner l’élĂ©ment", "Capturer l’aperçu", "Faire dĂ©filer dans la prĂ©sentation", missing value, "Tout dĂ©velopper", "Tout condenser"}
		click menu item captureScreenshot_loc of menu 1
	end tell
	
	repeat until exists sheet 1 of window 1
		delay 0.1
	end repeat
	
	keystroke "g" using {command down, shift down} -- to define the storage folder
	repeat until exists sheet 1 of sheet 1 of window 1
		delay 0.02
	end repeat
	tell sheet 1 of sheet 1 of window 1
		# CAUTION. before 10.11 the target field was a text field. Now it's a combo box
		-- class of UI elements
		--> {static text, text field, button, button} -- with 10.10 and older systems
		--> {static text, combo box, button, button} -- 10.11, 10.12, 10.13, 10.14, 10.15
		if exists combo box 1 then
			set value of combo box 1 to posixScreenshotsFolder
		else
			set value of text field 1 to posixScreenshotsFolder
		end if
		-- name of buttons (*Aller, Annuler*)
		keystroke return # ditto click button 1 (ou Aller)
	end tell
	
	click button save_loc of sheet 1 of window 1
	
	click menu item hideWebInspector_loc of menu 1 of menu bar item develop_loc of menu bar 1
	
end tell

#=====

on getResourceFile:path2resources fromTable:jsName
	set thisLocale to current application's NSLocale's currentLocale()
	set langX to thisLocale's localeIdentifier as text --> "fr_FR"
	set lang2 to text 1 thru 2 of langX
	if langX starts with "zh_Hans" then # "zh-Hans"
		set path2lproj to path2resources & "zh_CN.lproj"
	else if langX starts with "zh_Hant" then # "zh-Hant"
		set path2lproj to path2resources & "zh_TW.lproj"
	else if langX starts with "pt_PT" then -- "pt_PT"
		set path2lproj to path2resources & "pt_PT.lproj"
	else if langX starts with "pt_BR" then -- "pt_BR"
		set path2lproj to path2resources & "pt_BR.lproj"
	else if lang2 is in {"ar", "ca", "cs", "da", "el", "fi", "he", "hr", "hu", "id", "ko", "ms", "pl", "pt", "ro", "ru", "sk", "sv", "th", "tr", "uk", "vi"} then
		set path2lproj to path2resources & lang2 & ".lproj"
	else if lang2 is "de" then # {"de", "de-AT", "de-CH"}
		set path2lproj to path2resources & "German.lproj"
	else if lang2 is "en" then # {"en", "en_AU", "en_CA", "en_GB", "en_US"}
		set path2lproj to path2resources & "English.lproj"
	else if lang2 is "es" then # {"es", "es_419", "es_ES", "es_MX"}
		set path2lproj to path2resources & "Spanish.lproj"
	else if lang2 is "fr" then # {"fr_FR", "fr_CA", "fr_CH"}
		tell application "System Events"
			if exists folder (path2resources & "French.lproj") then
				set path2lproj to path2resources & "French.lproj"
			else
				set path2lproj to path2resources & "fr.lproj"
			end if
		end tell
	else if lang2 is "it" then
		set path2lproj to path2resources & "Italian.lproj"
	else if lang2 is "ja" then
		set path2lproj to path2resources & "Japanese.lproj"
	else if lang2 is "nb" then
		set path2lproj to path2resources & "no.lproj"
	else if lang2 is "nl" then # {"nl", "nl_BE"}
		set path2lproj to path2resources & "Dutch.lproj"
	end if
	
	return (path2lproj & ":" & jsName) as «class furl»
end getResourceFile:fromTable:

#=====

on localize:the_Key storedIn:theFile
	try
		set itsText to read theFile as «class utf8»
	on error
		set itsText to read theFile as «class ut16»
	end try
	set theDelim to "localizedStrings[" & quote & the_Key & quote & "] = " & quote
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, theDelim}
	set l to text items of itsText
	set AppleScript's text item delimiters to oTIDs
	set key_loc to paragraph 1 of (item 2 of l)
	set key_loc to text 1 thru -3 of key_loc
	return key_loc
end localize:storedIn:

#=====

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) dimanche 8 mars 2020 21:56:14

To test I edited your code as :

(*
	Elements window open,  text is highlight, execute this.
*)
tell application "System Events" to tell application process "Safari"
	set frontmost to true
	tell window 1
		tell splitter group 1
			tell tab group 1
				tell group 1
					tell group 1
						tell scroll area 1
							tell UI element 1
								perform action "AXShowMenu"
								-- get the name of every attribute
							end tell
						end tell
					end tell
					tell menu 1 to click (first menu item whose name starts with "Capture")
				end tell
			end tell
		end tell
	end tell
end tell

I did that because the index of the wanted menu item may change according to the visited Web page.
With MacScripter it’s -5. With macForEver it’s -3.

With the edited version, according to the area where I clicked before opening the Web Inspector I may get two behaviors.

(1) the Capture menu item appears and the save sheet is displayed.
(2) I get an error saying that the menu item of menu 1 isn’t available.

I really don’t know how to get a clean behavior.
I will just edited the script so that it become able to localize the infamous menu item.

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) lundi 9 mars 2020 16:11:09