scripting "Save as PDF" in Safari

Does anyone know how to use Applescript to get Safari to “Save as PDF”. I want the equivalent result of clicking the “Save As PDF” button in the print dialog box. I’ve seen a solution here where you set up a PDF printer but since I’m in a networked environment I don’t want to maintain that on a bunch of Macs.
This is part of a Filemaker solution where a user pastes a URL into a field, clicks a button, and the URL opens in Safari, Saves as PDF to desktop, inserts PDF into FMP container field, then deletes PDF on desktop.

Hi,

I have the pdf workflow enabled:

http://www.apple.com/applescript/print/

so your print window is probably different. Also using the older version of Safari. Here’s how I click the pdf button:

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” with command down – change with to using
tell front window
tell window “Print”
tell UI element 1
tell UI element 4
click menu button 1
end tell
end tell
end tell
end tell
end tell
end tell

I can’t remember how I clicked an item from the popup menu at the moment.

The hard part about this is that the Print window is a sheet (I think you call it that).

gl,

I don’t have PDF workflow enabled and my users probably won’t either. Is there a way to script this without enabling PDF workflow? I made the changes your script you suggested and got this. It craps out at “click menu button 1” with NSReceiverScriptEvaluation Error:4


tell application "Safari" to activate
tell application "System Events"
	tell process "Safari"
		keystroke "p" using command down -- change with to using
		tell front window
			tell sheet "Print"
				tell UI element 1
					tell UI element 4
						click menu button 1
					end tell
				end tell
			end tell
		end tell
	end tell
end tell

Never used System Events before, very cool.

Hi markman,

I think you’re suppose to use:

tell window “Print”

What I was saying is that it’s a sheet, but you call it window.

What I do is go through every target and get every ui element. For instance, I would run this in the Script Editor:

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” using command down – change with to using
tell front window
tell window “Print”
every ui element
end tell
end tell
end tell
end tell

Then I look at the result:

{UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”}

and get every ui element of the next target:

{image “image” of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”, pop up button 1 of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”, UI element 3 of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”, UI element 4 of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”, pop up button 2 of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”, static text “Presets:” of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”, static text “Printer:” of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”, pop up button 3 of UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”}

Then I go throu all the list elements until I find the right one and continue on until I find the button to click. As I wrote before, Your print window is probably different, so you can’t use my script.

gl,

Kel,
I really appreciate your help on this. I feel I’m very close.

When I run:
tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” using command down – change with to using
tell front window
tell window “Print”
every ui element
end tell
end tell
end tell
end tell

I get this in script editors event log:

tell application “Safari”
activate
end tell
tell application “System Events”
keystroke “p” using command down
get UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari”
“System Events got an error: NSReceiverEvaluationScriptError: 4”

When it craps out, “UI element 1” is highlighted. So it appears it doesn’t recognize it.

I’ve enabled “Enable access for assistive devices” in the Universal Access system preference. I’m running 10.3.9.

To make sure I understand correctly, you mean my Print window is probably different because it is named with the web page title or because you have PDF workflow enabled. I’m not sure what your Print window is different.

So you run the script you sent me just to get a list of UI elements, then try each one in your script until it works? One of them will be the Save as PDF button? Then I can hard code that UI element and it will work for all users?
But first I need ot get “every ui element” to work.
Of course, if I can get over this “…ScriptError: 4” issue.

Hi markman,

Everything is different on my computer (Safari, printer, pdf workflow enabled, OS 10.2.8, System Events). So, you might want to start from scratch with:

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” using command down – change with to using
tell front window
every UI element
end tell
end tell
end tell

When I run this, I get a list with a bunch of stuff and one of the items is this:

window “Print” of window “MacScripter BBS | Applescript Forums / scripting "Save as PDF" in Safari” of application process “Safari” of application "System Event. So next I run this:

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” with command down – change with to using
tell front window
tell window “Print”
every UI element
end tell
end tell
end tell
end tell

and I get this:

{UI element 1 of window “Print” of window “MacScripter BBS | Applescript Forums / Post a reply” of application process “Safari” of application “System Events”}

so next I run this:

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” with command down – change with to using
tell front window
tell window “Print”
tell UI element 1
every UI element
end tell
end tell
end tell
end tell
end tell

etc. You might want to even start with this:

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” with command down – change with to using
every UI element
end tell
end tell

Maybe Panther doesn’t allow front window, so maybe use the window name. Play around with it.

There are also apps around that help you get the path to the button. Check out Apple’s site or somebody might jump in here and give you a good reference. I have one that doesn’t help very much, uielementinspector.

http://www.apple.com/applescript/uiscripting/02.html

One thing I forgot to tell you is that after you manage to click the save to pdf button, I think you get a dialog where you name the document and choose a location to save. So you’ll need to script that somehow. I think it’s easier with pdf workflow because you can just save it to a certain location. Enabling pdf workflow is easy. All you need to do is create the folder “PDF Services” in your user Library folder. Then you just need to figure out how to choose an item from the pdf menu button.

A script could do that and make/place an alias file to some folder in the “PDF Services” folder. You could then rename the pdf file.

Good Luck in your experimenting,

Kel,
You are the best!!!
I followed your advice and this worked for me.

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” using command down – change with to using
tell front window
tell sheet “Print”
tell UI element 3
click button “Save As PDF.”
end tell
end tell
end tell
end tell
end tell

Now I have to figure out how to name the PDF file and save it. I suppose I could “get every UI element” of the Save dialog box the same way.

cheers,
Mark

Hi Mark,

This works here, but my Safari quits after the keystroke return.

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” with command down
tell front window
tell window “Print”
tell UI element 1
tell UI element 4
click button “Save As PDF.”
end tell
end tell
end tell
end tell
keystroke “MyPDF.pdf”
keystroke return
end tell
end tell

Wish I could remember how I chose themenu button menu item.

gl,

Kel,
I can name the PDF, but I can’t figure out how to change directory to the users Desktop.

Hi Mark,

I don’t think you can change the directory. It will save to the last place where something was saved. That’s the bad news.

The good news is I figured how to choose an item from the pdf workflow menu. After clicking the menu button, getting every ui element, you need to wait a while before closing the print window. I ended up with menu “BevelMenu” and clicked a menu item in there. Here’s the script in case you decide to try it.

tell application “Safari” to activate
tell application “System Events”
tell process “Safari”
keystroke “p” with command down
tell front window
tell window “Print”
tell UI element 1
tell UI element 4
click menu button 1
tell menu button 1
every UI element
– wait a few seconds
(*
tell menu “BevelMenu”
click menu item “PDF Folder” – an alias file to my pdf folder
end tell
*)
end tell
end tell
end tell
end tell
end tell
end tell
end tell

The pdf workflow documentation show how to write a script to process the pdf file.

gl,

Kel,
Thanks for the info on selecting the PDF script. Bummer about not selecting the directory. It kinda kills the whole idea of the script.
I’m bulding a travel approval database for our organization. Users past ea URL of a ticketed itinerary into a Filemaker field, then I want Safari to open the URL, save as PDF to Desktop, then have Filemaker import the PDF into container field, PDF is deleted. Currently the web link dies after travel is completed, this would link the itinerary with the travel approval form that initiated it.

I remember early versions of OSX had a field where you could type in the directory path. I hated it because is was so Windows-like. Now I wish I had it back.

Maybe I need to do PDF workflow.
Hey!!!, is there a way to enable PDF workflow via applescript? Could I check if its enabled then enable it if it isn’t? Do I need admin priveledges to do it?

Thanks,
Mark Thiessen

Hi Mark,

The following will create a PDF Services folder in the user Library folder and place an alias file to the user’s Desktop folder if one doesn’t exist. I think you should do this before the Print window is open. In the Print window you then choose the “Desktop” menu item.

set library_ref to (path to “dlib” from user domain)
set desktop_ref to (path to desktop)
try
set PDF_Services to (“” & library_ref & “PDF Services:”) as alias
on error
tell application “Finder”
set PDF_Services to (make new folder at library_ref with properties ¬
{name:“PDF Services”}) as alias
end tell
end try
tell application “Finder”
if not (exists alias file “Desktop” of PDF_Services) then
make new alias file at PDF_Services to desktop_ref
end if
end tell

I don’t think you’ll have permissions problem if the current user is running the script.

As I wrote before you can also have the pdf services pass a reference of the stored pdf to a script, but I don’t know if it’s a good idea. I don’t have FM, so couldn’t test it.

gl,

Kel,
Again, thanks.
If this script puts an alias of the desktop folder in the PDF Services folder, will the alias show up in the popup menu?

As in this excerpt from your previous script…

tell menu “BevelMenu”
click menu item “PDF Folder” – an alias file to my pdf folder
end tell

Or will I have to put an applescript in there that does the next steps?

Of course, I haven’t tried any of this with Filemaker yet. I’m just trying to see what script steps are required then I’ll try to tie it all together.

I’m in the middle of another project right now that will take me to Hungary next week. I hope I get to test it out before I leave.

There is a way you can save your stuff to PDF file. The basic idea is as follows:

  1. set the destination file path

  2. Copy your stuff to clipboard

  3. set the_clipboard_data (a variable) to the clipboard

  4. write the_clipboard_data to the file as data

This is listed in the book "AppleScript: A Comprehensive Guide to Scripting and Automation on MAC Osx. The application there is Preview–both copy to clipboard and open the saved PDF file. But the idea is cool and it works. Hope it works for the application you are using as well.

xhuang

Can’t seem to get this working in 10.4.9.

Any help would be greatly appreciated.

This script works here (10.4.3 at 1.5 Ghz) with Safari, TextEdit and Preview from a FastScripts keyboard shortcut. It does not work from within Script Editor, or as an app. It may need tweaking to work on other machines:


try
	
	tell application "System Events"
		
		set target_process to first application process whose frontmost is true and visible is true
		
		activate
		display dialog "Enter A Name For The PDF File..." & return default answer "" buttons {"Cancel", "OK"} default button 2 with title "Name The File"
		set PDF_name to text returned of the result
		
		delay 0.2
		
		try
			
			tell target_process
				activate
				set frontmost to true
				
				keystroke "p" using command down
				
				set PDF_button to UI element 6 of UI element 4 of sheet 1 of window 1 of target_process
				
				set {ButtonLeft, ButtonTop} to position of PDF_button
				set {ButtonWidth, ButtonHeight} to size of PDF_button
				set clickX to ButtonLeft + (ButtonWidth div 2)
				set clickY to ButtonTop + (ButtonHeight div 2)
				
				click at {clickX, clickY}
				
				delay 1
				
				keystroke (ASCII character 31)
				keystroke (return)
				
				delay 1
				
				keystroke PDF_name
				delay 1.2
				keystroke (return)
				
			end tell
			
		on error
			
			tell target_process
				activate
				set frontmost to true
				
				keystroke "p" using command down
				
				set PDF_button to UI element 1 of UI element 3 of UI element 1 of sheet 1 of window 1 of target_process
				
				set {ButtonLeft, ButtonTop} to position of PDF_button
				set {ButtonWidth, ButtonHeight} to size of PDF_button
				set clickX to ButtonLeft + (ButtonWidth div 2)
				set clickY to ButtonTop + (ButtonHeight div 2)
				
				click at {clickX, clickY}
				
				delay 1
				
				keystroke (ASCII character 31)
				keystroke (return)
				
				delay 1
				
				keystroke PDF_name
				delay 1.2
				keystroke (return)
				
			end tell
			
		end try
	end tell
end try


Also see NG’s ‘universal’ solution here:

http://bbs.applescript.net/viewtopic.php?id=19238

Peter B.


This is what worked for me. (Although not the most elegant solution but it works.)

  1. Install Acrobat 8. It creates a virtual printer called “Adobe PDF 8.0”. (version changes based on your install)
  2. Make “Adobe PDF 8.0” your default printer.
  3. Change the variable “filename”
  4. Run the script.

Help in the following:

  1. how do you specify a location, right now it prints to the desktop?
  2. Using the “Save as PDF…” instead of changing default printer to “Adobe PDF 8.0”
    A. This would be great if Acrobat 8 isn’t an optoin.

set filename to "filename"
set the clipboard to the result as text

tell application "Safari" to activate
tell application "System Events"
	tell process "Safari"
		keystroke "p" using command down 
		tell front window
			tell window "Print"
				tell UI element 1
					tell UI element 4
						keystroke return
						keystroke "v" using command down
						keystroke return
					end tell
				end tell
			end tell
		end tell
	end tell
end tell