Open an array of URLs in Safari background tabs?

I have used JavaScript to create an array of a couple of URL links on a page.
I want to open each one in a new background tab in Safari.
How can I do that?

I understand I probably need to use AppleScript but I’m not sure how to use the array in AppleScript?

How about “Open a URL” action? Not sure if it opens in tabs or not, but my guess is that it will.

I don’t think that will work.
Open URL opens a new URL in a tab or a window depending on your application setting but it will not be in the background.

PS. Edited my first post to reflect that I was talking about an Array of strings.

Ah, I get it. You want your current tab to stay the active tab. I guess I should have realized that when you said "in the background".

Perhaps this is what you're looking for?

I have a script I run to open all my ‘news’ websites. Perhaps this is what you are looking for too. Here is the bash script :

#!/bin/zsh
 
# URLs to open
read -r -d '' URLS <<'EOS'
https://github.com/trending
http://hckrnews.com/
https://www.reddit.com/
https://www.reddit.com/r/all/
https://www.reddit.com/me/m/apple
https://www.reddit.com/me/m/music
https://www.reddit.com/me/m/linux
https://www.reddit.com/me/m/code
https://www.reddit.com/me/m/web
https://www.reddit.com/me/m/health
https://slashdot.org/
https://www.producthunt.com
EOS
 
# Split string into array
URLS=("${(@f)URLS}")
 
for u in $URLS; do
  open "$u"
done

Thanks Dan. That link was the one I was looking at.
The problem was that I did not know that I had to split a string into an array.
Thanks to nikivi's script I understood that it was what was needed.

@nikivi could you describe what the script is doing? I'm not good at bash at all :slight_smile:

I managed to solve it with AppleScript at last.
I made a version of that script to open Google search results in background tabs:

Open Google links in new tabs.kmmacros (3.3 KB)

It just opens a list of urls you specify in new tabs.

Hey Eric,

Well done. The querySelectorAll() Method is spiffy!  :smile:

Keyboard Maestro uses AppleScript to perform its Execute a JavaScript in Safari action.

If you do the JavaScript in AppleScript the array returns as an AppleScript list, so you can skip a processing step and bypass the Clipboard.

I've added a link limiter property for flexibility, so if your Google search returns 100 items but you only want to see the first X you're covered. Set it to 0 (zero) for no limit.

Open Google Search Links in New Tabs – Number limited by ‘linkLimit.scptd.zip (11.3 KB)

--------------------------------------------------------------------------------
# Auth: Christopher Stone (Adapted from a script by Eric Bradley)
# dCre: 2016/08/18 00:23
# dMod: 2016/08/18 00:35
# Appl: Safari
# Task: Open Google Search Links in New Tabs – Number limited by ‘linkLimit’.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @Safari, @Open, @Google, @URLs, @Tabs
--------------------------------------------------------------------------------
property linkLimit : 10 -- Set to 0 (zero) for no limit.
--------------------------------------------------------------------------------

set jsStr to text 2 thru -1 of "
var x = document.querySelectorAll('.g .rc .r a'); 
var myArray = []; 
for (i = 0; i < x.length; i++) {
   myArray.push(x[i].href)
}
myArray;
"

set googleLinks to doJavaScriptInSafari(jsStr)

if length of googleLinks > 0 then
   
   if (linkLimit ≠ 0) and (length of googleLinks > linkLimit) then
      set googleLinks to items 1 thru linkLimit of googleLinks
   end if
   
   makeSafariTabsFromUrlList(googleLinks)
   
end if

--------------------------------------------------------------------------------
--» HANDLERS
--------------------------------------------------------------------------------
on makeSafariTabsFromUrlList(urlList)
   repeat with i from 1 to number of items in urlList
      set x to item i of urlList
      tell application "Safari"
         tell front window
            make new tab at end of tabs with properties {URL:x}
         end tell
      end tell
   end repeat
end makeSafariTabsFromUrlList
--------------------------------------------------------------------------------
on doJavaScriptInSafari(javascriptStr)
   try
      tell application "Safari" to do JavaScript javascriptStr in front document
   on error e
      error "Error in handler doJavaScriptInSafari() of library NLb!" & return & return & e
   end try
end doJavaScriptInSafari
--------------------------------------------------------------------------------

-Chris

1 Like

Thanks Chris!
I'm glad I was able to pull it off. :sweat_smile:

And a HUGE thank you for your AppleScript version. It's so damn elegant. I really love it.

I think I grasp everything except this line:

set jsStr to text 2 thru -1 of

Why: 2 thru -1?

/Eric

Hey Eric,

I don't like having the first line of a text script (JavaScript in this case) misaligned from the rest of it.

set js to "var txt = 'Goofy'
txt;
"
doJavaScriptInSafari(js)

To me this is just pure yuck, so I typically add a blank line to the top of the script.

set js to "
var txt = 'Goofy'
txt;
"
doJavaScriptInSafari(js)

Some command parsers (not JavaScript) choke if the first line you pass them is whitespace, so my convention is to remove that first blank line. I do this with text 2 thru -1 which reads from the second to the last character of the text.

Doing this also allows the script to visualize better in Script Debugger's variable inspector:

When I look at the js variable in the inspector I don't want to see that leading \n – I want to see the beginning of the script.

By chomping that first newline character I get this instead:

Make sense?

-Chris

2 Likes

Oh, yeah.

The makeSafariTabsFromUrlList handler can be made trifle more efficient:

on makeSafariTabsFromUrlList(urlList)
   tell application "Safari"
      tell front window
         repeat with theURL in urlList
            make new tab at end of tabs with properties {URL:theURL}
         end repeat
      end tell
   end tell
end makeSafariTabsFromUrlList

-Chris

Thanks again.
It makes total sense!

This kind of information is invaluable for a hobbyist like me.

1 Like

That’s much cleaner too.
So, you can use repeat like in your example to loop through all the values (from the first to the last) and then stop?

I’m running out of “thankyou’s”…

:beer: :beer: :beer:

/Eric

Chris, thanks for sharing your technique about formatting JavaScript in AppleScript.

I totally get your point, and agree with it. You inspired me, and this popped out, perhaps slightly simpler: Just make the first line a comment.

set jsStr to "//
var x = document.querySelectorAll('.g .rc .r a'); 
var myArray = []; 
for (i = 0; i < x.length; i++) {
   myArray.push(x[i].href)
}
myArray;
"

1 Like

Hey Eric,

Yep.

There's a gotcha though.

If you run the first script below you'll find the output to be a bit confusing.

This is because theItem is a reference (and behind the scenes this list-iteration method is faster).

In the second script to get the output I want i have to de-reference theItem.

--------------------------------------------

set theList to {"one", "two", "three"}
set newList to {}

repeat with theItem in theList
   set end of newList to theItem
end repeat

newList

--------------------------------------------

set theList to {"one", "two", "three"}
set newList to {}

repeat with theItem in theList
   set end of newList to contents of theItem
end repeat

newList

--------------------------------------------

The confusing part is that in some applications you don't have to manually de-reference theItem – it gets done automagically.

But there's not a specific rule for when this automagic happens, so the only way to be sure it works without manual de-referencing is to test.

-Chris

I made a version in JXA inspired by you guys in the forum.

Google Links from search.js.jxa.zip (781 Bytes)

2 Likes