3

I'm using this script for Google Chrome to pause the script until the page is fully loaded:

tell application "Google Chrome"
        repeat until (loading of front window's tab 2 is false)
            1 + 1 --just an arbitary line
        end repeat
        loading of front window's tab 2 
    end tell 

This don't seems to work with Safari, any equivalent?

3 Answers 3

13

1. AppleScript source property

You could try using Safari's source property, which is "" until the HTML code gets loaded into it (which can only be done once the page is loaded). Note, however, that this doesn't necessarily imply that the page has been rendered:

tell application "Safari"
     .
     .
    repeat while document 1's source = ""
        delay 0.5
    end repeat
     .
     .
end tell

The source property is reset to "" even between page loads/reloads.

2. Reload button UI element

If you want to know that a page is loaded and rendered on screen, then a reliable method is to determine whether the button in the URL bar is a "reload" button (page loaded and rendered), or a "cancel" button (page still loading/rendering):

tell application "System Events" to repeat until exists (buttons of ¬
    UI elements of groups of toolbar 1 of window 1 of ¬
    process "Safari" whose name = "Reload this page")

    delay 0.5
end repeat

3. JavaScript readyState property

If you have Allow JavaScript from Apple Events ticked in the Develop menu, then you can access the readyState property of the document:

tell application "Safari"
     .
     .
    tell document 1 to repeat
        do JavaScript "document.readyState"
        if the result = "complete" then exit repeat
        delay 0.5
    end repeat
     .
     .
end tell

The document.readyState JavaScript property returns one of five values:

  • uninitialized: Has not started loading yet
  • loading: Is loading
  • loaded: Has been loaded
  • interactive: Has loaded enough and the user can interact with it
  • complete: Fully loaded
16
  • 1
    @d-b The issue is probably timing. The JavaScript code executes both independently and without any awareness of the AppleScript that invoked it. Consider this scenario: a line of AppleScript opens a webpage in a new Safari tab, then the next line invokes the JavaScript code on this new tab to poll the readyState value, which is logged every 0.5 seconds. Any reasonable person would expect this approximate sequence of values : {"loading", "loading", "loading", "interactive", "complete"}. What actually happens is: {"complete", "complete", "loading", "loading", "interactive", "complete"}.
    – CJK
    Apr 8 at 16:49
  • 1
    PS. Whether or not I did this intentionally when I wrote this answer originally, those three methods described are in the order of what I would say represents their reliability/effectiveness. I'd recommend using the source property described in the first case, as that will be an empty string for a blank document, and for any webpage that isn't fully downloaded. While it may not be rendered at the point it registers as being loaded, that won't matter, as you can still run JS code on a page that has loaded its DOM even while it may not have fully displayed and formatted it.
    – CJK
    Apr 8 at 17:29
  • 1
    @d-b I see what you mean. It appears the same issue that I thought would be specific to JS is also at play here when using source. That never used to be the case, because AppleScript commands are supposed to execute synchronously, meaning if you set the URL property first, and then read the source property, that second command shouldn't begin to execute until after the URL property has changed. However, I've just tested it and it begins to set the URL property while then proceeding to read the source, so retrieves it for the page you're navigating away from. How stupid.
    – CJK
    Apr 10 at 20:36
  • 1
    ...Cont'd @d-b To work around this problem, before navigating to a new URL, navigate first away from whatever page it's on by setting the URL property to "about:blank". Establish a loop and repeat until source = "". Then set the URL again, this time to your desired destination, and now do as before, i.e. repeat while source = "".
    – CJK
    Apr 10 at 20:47
  • 1
    @d-b Yes, I completely agree. I loathe GUI scripting and anyone who uses it. But the fact that there isn't a native way is an issue you need to take up with Apple's engineers or project design team. Chromium browser tab objects have a loading property, so it's absurd that Safari doesn't. But the workaround I just mentioned will mean you don't have to resort to GUI scripting, and just stick to the source property. Regarding pages with infinite scrolling... I'll have a think about that, but AppleScript probably isn't going to cut it.
    – CJK
    Apr 10 at 20:54
1

I was having trouble with the "reload button" method as well, and this answer didn't fix it. Turns out if you've got extensions that add icons to the toolbar, the "group 2" needs to be changed to a different number. Because I've got a lot going in the toolbar, I've got the reload button in group 7.

To find out which group your reload button is in, run this script, incrementing the group number each time. One of the results will have "Reload this page" in it. That's the one to use.

tell application "System Events"
    tell process "Safari"
        accessibility description of every button of group 7 of toolbar 1 of front window
    end tell
end tell
3
  • I assume this refers to apple.stackexchange.com/a/418604/9058 ? Might work better as an edit to that answer, actually.
    – nohillside
    Jul 11, 2022 at 6:08
  • Ah! I didn't realise that was possible. Thanks. I'll know for next time.
    – jurgen
    Jul 12, 2022 at 7:07
  • You still can do the edit, actually :-)
    – nohillside
    Jul 12, 2022 at 7:23
0

In the accepted answer "2. Reload button UI element" did not work for me, but here is what did:

-- Safari Version 14.0.3 (15610.4.3.1.7, 15610)


tell application "Safari"
    --activate
    make new document with properties ¬
        {URL:"https://apple.stackexchange.com/questions/343624/applescript-wait-for-page-fully-loaded"}
end tell


tell application ¬
    "System Events" to tell process ¬
    "Safari" to tell group 2 of toolbar 1 of front window to ¬
    repeat until exists (first button where its accessibility description = "Reload this page")
        delay 0.5
    end repeat

-- Additional code as needed goes here:
1
  • user3439894 The script in the accepted answer "2. Reload button UI element" did not work for me. The script runs without throwing an error; but fails to recognize the existence of the "Reload this page" button and never exits. I have no doubt that the script once worked, however, there have been 2 version updates to Safari since that script was posted and stuff happens. I shared my answer not because it was the best to be had but because it does work and might help someone along.
    – user414152
    Apr 12, 2021 at 20:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .