I’ve created a script to login to a website, clicking on specific links as it goes. The problem is, every time a URL is opened, it opens in a new tab, so I end up with unnecessary open tabs.
I’ve checked the .sdef for Safari, and whilst there are ‘current tab’ and ‘window’ properties, no matter how I try to use them or combine them, the script doesn’t compile.
I take it I need to reference the index name of the tab or window, but not sure how. Is there a simple way to simply open location/URL in the same tab?
Here’s the loop I’m currently using to open the URLs (the keystrokes are to highlight fields on the page and enter text “ I haven’t got around to parsing the HTML for form elements yet!).
tell application "System Events"
tell process "Safari"
activate
open location loginPage
my web_page_loading()
keystroke tab
keystroke userName
keystroke tab
keystroke login
keystroke return
my web_page_loading()
open location itemsPage
my web_page_loading()
open location newItem
my web_page_loading
keystroke tab
keystroke tab
keystroke tab
end tell
end tell
Many thanks,
K@
Model: MacPro Qaud Xeon
AppleScript: 2.5 / 2.2.2
Browser: Safari 6
Operating System: Mac OS X (10.8)
It works stand-alone.
Probably you put the code into the System Events tell block.
You could put the code into the web_page_loading() handler and pass the URL as parameter
Ah … not sure I know how. The web_page_loading sub was taken from a script that I didn’t write, and is basically to ensure the page has fully loaded before progressing.
I don’t want you to write the script for me, but can you tell me, from looking at the routine, where the best place to put it would be? There’s a ‘System events’ call here, too, but I’m thinking that somewhere down near the end, after the repeat loops:
on web_page_loading()
set theDelay to 10 -- the time in seconds the script will wait to let a web page load
set numTries to 3 -- the number of stop/reload cycles before giving up
set myCounter to 0
set finished to false
repeat until finished is true
set myCounter to myCounter + 1
set my_delay to 0.25
set startTime to current date
set endTime to startTime + theDelay
set web_page_is_loaded to false
delay my_delay
tell application "Safari"
activate
repeat until web_page_is_loaded is true
if endTime is greater than (current date) then -- only wait theDelay seconds for a web page to load otherwise stop the page loading and try to reload again
if name of window 1 contains "Loading" or name of window 1 contains "Untitled" or name of window 1 contains "Failed to open page" then
delay my_delay
else
set web_page_is_loaded to true
set finished to true
delay my_delay
end if
else
tell application "System Events"
tell process "Safari"
if myCounter is numTries then -- give up if the page doesn't load after numTries stop/reload cycles
keystroke "." using command down -- stop the page
delay my_delay
tell application "Finder"
activate
display dialog "The web page will not load!"
end tell
set connected to true -- a global variable which will stop this script if there's a problem
set web_page_is_loaded to true
set finished to true
tell application "Safari" to activate
else
keystroke "." using command down -- stop the page
delay my_delay
keystroke "r" using command down -- reload the page
delay my_delay
set web_page_is_loaded to true
end if
end tell
end tell
end if
end repeat
end tell
end repeat
end web_page_loading
as you call web_page_loading() always after an open location line
put it just at the beginning
on web_page_loading(theURL)
tell application "Safari"
tell window 1 to set URL of current tab to theURL
end tell
set theDelay to 10 -- the time in seconds the script will wait to let a web page load
-- .
I think it’s because the sub now needs a URL parameter. It opens and gets to the login screen, but doesn’t do the keystrokes correctly, and doesn’t login.
I’ve tried putting an if loop in the sub, but that doesn’t work either.
I don’t really want to have to duplicate the whole sub without a parameter just for that step, but I may resort to that if I can’t tweak it in the right direction!
on web_page_loading(theURL)
if theURL is not missing value then
tell application "Safari"
tell window 1 to set URL of current tab to theURL
end tell
end if
set theDelay to 10 -- the time in seconds the script will wait to let a web page load
-- .
in the case you call web_page_loading() after the keystrokes use
It still messes up the page-loading check. It’s not major, so I’m not too worried. It just seemed like it should be a very simple thing to do, but perhaps not.
Once your specified page is loaded, you might try getting rid of the undesired tabs using a repeat loop.
The first approach creates a new document and sets its url to that of the desired web page. The original page containing the multiple tabs is then discarded using the close window 2 command found at the end of the script. Advantage of this approach: It works relatively quickly and cleanly, without resorting to GUI scripting. Possible disadvantage: Will reopening the desired web page retain the login information that has been entered? If not, using this approach would be pointless.
New document, non-GUI approach:
tell application "Safari"
tell window 1
set my_url to "enter desired url here"
set all_tabs to every tab
repeat with a_tab in all_tabs
set current tab to a_tab
if URL of current tab = my_url then
tell application "Safari" to make new document
set URL of document 1 to my_url
exit repeat
end if
end repeat
end tell
close window 2
end tell
Another approach uses GUI scripting in order to manipulate the Close Other Tabs command in Safari’s File menu. Advantage: the specified page is left untouched; no need to reopen it. Disadvantage: GUI scripting can be slow and unreliable.
“Close Other Tabs” approach, using GUI scripting:
tell application "Safari"
activate
tell window 1
set my_url to "enter desired url here"
set all_tabs to every tab
repeat with a_tab in all_tabs
set current tab to a_tab
if URL of current tab = my_url then
tell application "System Events"
tell process "Safari"
click menu item "Close Other Tabs" of menu "File" of menu bar 1
exit repeat
end tell
end tell
end if
end repeat
end tell
end tell
Scripts tested using Mac OS 10.4.11 and Safari 4.1.3. Your results may vary; modify as needed. Hope this helps.
Model: iMac 1 GHz PowerPC G4
AppleScript: 2.1.2
Browser: Safari 4.1.3
Operating System: Mac OS X (10.4)
tell application "Safari"
tell window 1
set my_url to "desired urll"
set all_tabs to every tab
repeat with i from (count all_tabs) to 1 by -1
set current tab to item i of all_tabs
if URL of current tab = my_url then
else
tell current tab to close
end if
end repeat
end tell
end tell
This works:
tell application "Safari"
tell current tab of its window 1 to close
end tell
-- These work with Safari 5.1.2 in Snow Leopard.
tell application "Safari" to close (tabs of front window whose visible is false) -- Close all but the current tab.
tell application "Safari" to close (tabs of front window whose URL is not my_url) -- Close all which don't have the specified URL.
-- This works with Safari 5.1.2 in Snow Leopard and with Safari 4.1.3 in Tiger.
tell application "System Events"
set frontmost of application process "Safari" to true
keystroke "w" using {option down, command down} -- Close all but the current tab.
end tell
Edit: It was Safari 5.1.2 when I wrote these. They still work in Safari 5.1.7. But I notice that Option-Command-“w” crassly has a different meaning (Close All Windows) if there’s only one tab open in the front window, so that method’s best avoided!
Your ways are even better. I hope to take up on Safari scripting soon, it still feels a bit odd and strange, but your examples helps.
And kudos to andmr for figuring out the two other scripts, and the efforts. I find Safari quirky. And I have experience with it before. I could easily see what was going on in Script Debugger. And saw that the list of tabs, was a list of references, when deleted from the start, every thing goes well, until one tab is passed over (the current tab, from then on, the next tab doesn’t exist, and that error occured. Not inituive without Script Debugger!
I better go hide, from the picket fence that is waiting .