Applescript to Export all safari tabs to pdf... almost done

Hello everybody, i was trying to write a script to export to pdf all opened safari tabs (each tab to a different pdf file).

I was able to do that thanks to very helpful posts I’ve found here with little tweakings, giving also the name of the specific tab to the exported pdf file.

It seems to work but there’s probably something redundant, so i was wondering for your help.

Also, there’s one problem left that i can’t solve which is "how to get the script to add numbers in bracket to the file name of the exported pdf if it finds that the file already exists in the same folder.

Thanks in advance for your help



set SaveFolderPath to POSIX path of (choose folder with prompt "Select Folder to Save PDF Files")
tell application "Safari" to activate
tell application "System Events"
	tell process "Safari"
		tell application "Safari"
			
			tell window 1
				
				set i to 1
				set ctabs to (count tabs)
				
				repeat with i from 1 to ctabs
					
					
					tell application "Safari" to activate
					tell application "Safari" to get the name of the current tab of window 1
					set tabName to the name of the current tab
					
					tell application "System Events"
						tell process "Safari"
							click menu item "Show Reader" of menu "View" of menu bar 1
							click menu item "Export as PDF…" of menu "File" of menu bar 1
							repeat until exists sheet 1 of window 1
								delay 1
							end repeat
							keystroke "g" using {command down, shift down}
							repeat until exists sheet 1 of sheet 1 of window 1
								delay 1
							end repeat
							log "passed delay"
							tell sheet 1 of sheet 1 of window 1
								set value of combo box 1 to (tabName & ".pdf") as string
								click button "Go"
								
							end tell
							click button "Save" of sheet 1 of window 1
							click menu item "Close tab" of menu "File" of menu bar 1
							set resultDialogReply to display dialog "Close after 1 second..." giving up after 1
						end tell
						
						set i to i + 1
					end tell
					
				end repeat
			end tell
		end tell
		
	end tell
end tell



AppleScript: 2.11 (208)
Browser: Safari 13.1.2 (15609.3.5.1.3) on Catalina 10.15.6
Operating System: macOS 10.14

Hi macuser83. Welcome to MacScripter.

Your script does seem to be almost there. But there’s some undesirable nesting of ‘tell’ statements to different applications, the value of the combo box is being set to the file name when it should be set to the folder path, and there’s some superfluous setting of the variable ‘i’. Otherwise, the main elements seem to be in place.

Sorry you’ve had to wait a couple of days for a reply. I spent much of yesterday trying to write a version of the script that was absolutely reliable with multiple tabs, but there’d always be at least one tab for which my efforts didn’t work properly — no doubt a timing problem with the GUI scripting. I’ve also only just noticed your request for a way to add numbers to the file names when necessary. This’ll require more thought.

Meanwhile, though, here’s a clean-up of your own code based on the points raised above:


-- Keep code for Safari separate from the code for System Events.
tell application "Safari"
	activate
	-- Tell Safari, as the known frontmost application, to display the 'choose folder' dialog.
	set SaveFolderPath to POSIX path of (choose folder with prompt "Select Folder to Save PDF Files")
	tell window 1
		set current tab to tab 1
		set ctabs to (count tabs)
	end tell
end tell

repeat with i from 1 to ctabs
	tell application "System Events"
		tell process "Safari"
			click menu item "Show Reader" of menu "View" of menu bar 1
			click menu item "Export as PDF…" of menu "File" of menu bar 1
			repeat until exists sheet 1 of window 1
				delay 1
			end repeat
			-- The sheet opens alread primed with a file name based on the tab name.
			if (i is 1) then
				-- Make sure the file gets saved to the folder chosen above.
				-- This is only necessary first time round the repeat, as the folder becomes the default next time.
				keystroke "g" using {command down, shift down}
				repeat until exists sheet 1 of sheet 1 of window 1
					delay 1
				end repeat
				log "passed delay"
				tell sheet 1 of sheet 1 of window 1
					set value of combo box 1 to SaveFolderPath -- NB. the folder path here, not the file name.
					click button "Go"
					
				end tell
			end if
			click button "Save" of sheet 1 of window 1
			click menu item "Close tab" of menu "File" of menu bar 1
		end tell
		
		tell application "Safari" to display dialog "Close after 1 second..." giving up after 1
	end tell
end repeat

OK. This is working fairly well so far, but may need further timing adjustments. It inserts numbers into file names which have already been used, starting with “(2)”. (So “My Tab Name.pdf”, “My Tab Name (2).pdf”, “My Tab Name (3).pdf”, etc.)

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

-- Get a new name for a PDF file to be saved, one which isn't in a list of names already taken.
on newPDFName(currentName, takenNames)
	-- Initially try inserting " (2)" into the name (or replacing an already taken number) just before the extension.
	set n to 2
	set newName to current application's class "NSMutableString"'s stringWithString:(currentName)
	set regex to current application's NSRegularExpressionSearch
	tell newName to replaceOccurrencesOfString:("(?: \\(\\d++\\))?\\.pdf$") withString:(" (" & n & ").pdf") options:(regex) range:({0, its |length|()})
	-- If that name's taken too, try again with incrementing numbers until an unused name's produced.
	repeat while ((newName as text) is in takenNames)
		set n to n + 1
		tell newName to replaceOccurrencesOfString:("(?<=\\()\\d++(?=\\)\\.pdf$)") withString:(n as string) options:(regex) range:({0, its |length|()})
	end repeat
	-- Update the list of taken names.
	set newName to newName as text
	set end of takenNames to newName
	
	return newName
end newPDFName

on main()
	-- Bring Safari to the front and use it, as the frontmost application, to display the 'choose folder' dialog.
	tell application "Safari"
		activate
		set SaveFolder to (choose folder with prompt "Select Folder to Save PDF Files")
		tell window 1
			set current tab to tab 1
			set ctabs to (count tabs)
		end tell
	end tell
	
	-- Get the names of the folder's existing items. Use the Finder for this, not System Events,
	-- because the latter (in Mojave) returns 'POSIX path' names (ie. with any slashes changed to colons).
	tell application "Finder" to set takenNames to name of SaveFolder's items
	-- But the POSIX path of the folder /will/ be needed.
	set SaveFolderPath to POSIX path of SaveFolder
	
	repeat with i from 1 to ctabs
		tell application "System Events"
			tell process "Safari"
				-- Wait for and click the "Show Reader" menu item.
				tell menu item "Show Reader" of menu "View" of menu bar 1
					repeat until (it exists)
						delay 0.2
					end repeat
					click
				end tell
				-- After a slight pause, wait for and click "Export as PDF…".
				delay 0.5
				tell menu item "Export as PDF…" of menu "File" of menu bar 1
					repeat until (enabled)
						delay 0.2
					end repeat
					click
				end tell
				-- Wait for the Export dialog sheet to appear.
				tell sheet 1 of window 1
					repeat until (it exists)
						delay 0.2
					end repeat
					-- Change the destination file name if necessary
					set fileName to value of text field "Export As:"
					if (fileName is in takenNames) then set value of text field "Export As:" to my newPDFName(fileName, takenNames)
					-- On the first repeat iteration, set the destination folder too.
					if (i is 1) then
						keystroke "g" using {command down, shift down}
						tell sheet 1
							repeat until (it exists)
								delay 0.2
							end repeat
							set value of combo box 1 to SaveFolderPath
							click button "Go"
							repeat while (it exists)
								delay 0.2
							end repeat
						end tell
					end if
					-- Click the "Save" button and wait for the Export dialog sheet to go.
					click button "Save"
					repeat while (it exists)
						delay 0.2
					end repeat
				end tell
				-- Wait for "Export as PDF…" to be re-enabled too. (May be superfluous.)
				repeat until (enabled of menu item "Export as PDF…" of menu "File" of menu bar 1)
					delay 0.2
				end repeat
			end tell
		end tell
		-- Also pause briefly before and after closing the tab.
		delay 0.5
		tell application "Safari" to close tab 1 of window 1
		delay 0.5
	end repeat
end main

main()

Greetings to all.

I would not use the “Export as PDF …” menu of this application at all. As far as I know, this menu usually renders the page markup far from complete. Perhaps something has changed in recent versions of Safari and I am wrong. But I doubt it.

Therefore, I will repeat the well-known code for exporting a separate tab using the “Print …” menu. I would recommend the OP just modifying it to export multiple tabs.


set SaveFolder to POSIX path of (choose folder)
tell application "Safari" to activate

tell application "System Events" to tell application process "Safari"
	click menu item "Print…" of menu 1 of menu bar item "File" of menu bar 1
	repeat until exists sheet 1 of window 1
		delay 0.02
	end repeat
	tell window 1 to tell sheet 1
		
		click menu button "PDF"
		repeat until exists menu 1 of menu button "PDF"
			delay 0.02
		end repeat
		click menu item "Save as PDF" of menu 1 of menu button "PDF"
		
		repeat until exists sheet 1
			delay 0.02
		end repeat
		tell sheet 1
			keystroke "g" using {shift down, command down}
			repeat until exists combo box 1 of sheet 1
				delay 0.02
			end repeat
			tell sheet 1
				set value of combo box 1 to SaveFolder
				-- Now click the Go button
				click button "Go"
				repeat while it exists
					delay 0.02
				end repeat
			end tell
			-- Set the file name and save
			set value of text field 1 to "TestResults.pdf"
			click button "Save"
		end tell
		
	end tell
end tell

Sorry for the late reply and thank you all for the suggestions.

In the meantime i think i found i better solution to the “overwrite” problem and avoid duplicate files all along. I also got rid of “show reader” passage as i didn’t like the format.



set SaveFolderPath to POSIX path of (choose folder with prompt "Select Folder to Save PDF Files")
tell application "Safari" to activate
tell application "System Events"
	tell process "Safari"
		tell application "Safari"
			tell window 1
				
				set i to 1
				set ctabs to (count tabs)
				
				repeat with i from 1 to ctabs
					
					tell application "Safari" to activate
					tell application "Safari" to get the URL of the current tab of window 1
					set taburl to the URL of the current tab  -- now every pdf generated has the name as the url where it's from, much better
					tell application "System Events"
						tell process "Safari"
							try
								click menu item "Export as PDF…" of menu "File" of menu bar 1
								
							on error  -- sometimes i get error from safari "unable to export" since the file is too long and it doesn't have the necessary time to load the long text before "export as pdf" command, so i tried this so with no effect unfortunately
								
								keystroke space  -- the intention was to to tell safari to keep going with the cycle because when there's that error the script stops, anyway it doesn't work, it's like this passage gets completely ignored when the script runs
								
							end try
							
							repeat until exists sheet 1 of window 1
								delay 1
							end repeat
							tell sheet 1 of window 1
								set value of text field 1 to (taburl & ".pdf") as string  -- now every pdf generated has the name as the url where it's from
								click button "Save"
								
								if exists then
									keystroke space -- with this i'm able to overwrite a possible duplicate file, mind you that i had to activate complete "tab" keyboard function in system preferences (keyboard options)
								end if
							end tell
							
							click menu item "Close tab" of menu "File" of menu bar 1
							set resultDialogReply to display dialog "Close after 1 second..." giving up after 1
						end tell
						
						set i to i + 1
					end tell
					
				end repeat
			end tell
		end tell
		
	end tell
end tell



this way seems to be better but there are still few issues:

the problem with a very long text in a page, which can’t be exported as pdf as it shows error and stops the script all along. the ideal solution would be to tell safari to wait for complete load of the page (but only when i get this kind error, so that there’s no need to put too much delay. you know like: when you get that error, then reload the page, wait for complete load and then export as pdf)

sometimes the destination folder is stuck with the first i choose, even if it asks for a destination folder every time i run the script (that’s a minor issue anyway)

Finally it would be cool before all of this accomplishment, to extract all the links (filtered by a word given by the user) from a webpage and open each one in a different tab, and then run the above script.

I found on this forum (god bless this forum) something helpful but it opens every possible link it finds on the webpage, whereas i would need to tell him to only open the links containing “whatever” in the url, this is the script i’m referring to:



--Script to open page links in Safari tabs
-- John Maisey 16/5/5
--
set myList to {}

tell application "Safari"
   set myURL to URL of front document
   set URLsource to source of front document
end tell

set {myTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "href=\""}
set myChunks to (text items 2 thru -1 of URLsource)
set AppleScript's text item delimiters to myTID

repeat with myChunk in myChunks
   set {myTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "\""}
   set myList to myList & (text item 1 of myChunk)
   set AppleScript's text item delimiters to myTID
end repeat

repeat with myListNo from 1 to length of myList
   set myLink to item myListNo of myList
   if myLink does not contain "://" then
       set myCount to -2
       repeat
           if (myLink starts with "../") or (myLink starts with "./") then
               set myLink to (characters ((offset of "/" in myLink) + 1) thru -1 of myLink) as text
               set myCount to myCount - 1
           else
               exit repeat
           end if
       end repeat
       set {myTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, "/"}
       set myBase to (text items 1 thru myCount of myURL) as text
       set AppleScript's text item delimiters to myTID
       set myLink to (myBase & "/" & myLink) as text
       set (item myListNo of myList) to myLink
   end if
end repeat

tell application "Safari"
   repeat with theURL in myList
       my new_tab()
       set the URL of document 1 to theURL
   end repeat
end tell

--credit http://www.macosxhints.com/article.php?story=20030414185226343
on new_tab()
   tell application "Safari" to activate
   tell application "System Events"
       tell process "Safari"
           click menu item "New Tab" of menu "File" of menu bar 1
       end tell
   end tell
end new_tab



Thanks again, have a great day