Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Phoenix_E

macrumors newbie
Original poster
May 23, 2017
4
0
I had an applescript that used to work but now it no longer does. I'm not sure what's wrong with it but if someone could help me out it'd be greatly appreciated. Everytime I run this it returns "msng" and i can't figure out how to fix it.
Code:
tell application "Safari"
    quit
end tell

set defaultAnswer to ""
set cancelButton to "Cancel"
set buttonResearch to "ReSearch"

display dialog "Query: " default answer defaultAnswer buttons {cancelButton, buttonResearch} default button buttonResearch cancel button cancelButton with icon 1
copy the result as list to {button_pressed, text_returned}


if (button_pressed is buttonResearch) and (text_returned is not "") then
    set theUrl to "http://www.wolframalpha.com/input/?i=" & encode_text(text_returned, true, false)
    tell application "Safari"
        tell window 1 to set current tab to (make new tab with properties {URL:theUrl})
        tell me to say "let me look that up for you now"
        tell document 1
            repeat
                delay 2
                if (do JavaScript "document.readyState") = "complete" then exit repeat
            end repeat
            do JavaScript "document.getElementById('pod_0200').getElementsByClassName('action subpod-copyablept ')[0].click()"
            set theAnswer to do JavaScript "document.body.lastChild.getElementsByTagName('pre')[0].innerHTML;"
        end tell
    end tell
    activate
    
    display dialog theAnswer
    
end if

tell application "Safari"
    quit
end tell

on encode_char(this_char)
    set the ASCII_num to (the ASCII number this_char)
    set the hex_list to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}
    set x to item ((ASCII_num div 16) + 1) of the hex_list
    set y to item ((ASCII_num mod 16) + 1) of the hex_list
    return ("%" & x & y) as string
end encode_char

on encode_text(this_text, encode_URL_A, encode_URL_B)
    set the standard_characters to "abcdefghijklmnopqrstuvwxyz0123456789"
    set the URL_A_chars to "$+!'/?;&@=#%><{}[]\"~`^\\|*"
    set the URL_B_chars to ".-_:"
    set the acceptable_characters to the standard_characters
    if encode_URL_A is false then set the acceptable_characters to the acceptable_characters & the URL_A_chars
    if encode_URL_B is false then set the acceptable_characters to the acceptable_characters & the URL_B_chars
    set the encoded_text to ""
    repeat with this_char in this_text
        if this_char is in the acceptable_characters then
            set the encoded_text to (the encoded_text & this_char)
        else
            set the encoded_text to (the encoded_text & encode_char(this_char)) as string
        end if
    end repeat
    return the encoded_text
end encode_text
 

superscape

macrumors 6502a
Feb 12, 2008
937
223
East Riding of Yorkshire, UK
Hi,

Not sure at first sight, but wouldn't you be better off using their API rather than screen scraping a web page? Even if you get your script working, it'll break if they change their page's HTML.

For example:

Code:
set appID to "XXXXXX-XXXXXXXX"
set theSearchTest to text returned of (display dialog "Please enter your text" default answer "")
set theResponse to do shell script "curl -d input=" & theSearchTest & " -d appid=" & appID & " http://api.wolframalpha.com/v1/query"

...obviously, you'll need to sign up for a free app ID. I'll leave the exercise of parsing the XML and escaping theSearchText to you. :)
 
Last edited:

Mark FX

macrumors regular
Nov 18, 2011
159
17
West Sussex, UK
superscape said:
, it'll break if they change their page's HTML.

That's exactly what appears to have happened here.
As after testing the posted script, I tracked the problem down to the second "do JavaScript" command.
Works fine up until that point in the AppleScript.
Although I rewrote the AppleScript code to make it more readable.

I don't know enough JavaScript, to help out with what the exact problem is in the second "do JavaScript" command.
 

Phoenix_E

macrumors newbie
Original poster
May 23, 2017
4
0
Hi,

Not sure at first sight, but wouldn't you be better off using their API rather than screen scraping a web page? Even if you get your script working, it'll break if they change their page's HTML.

For example:

Code:
set appID to "XXXXXX-XXXXXXXX"
set theSearchTest to text returned of (display dialog "Please enter your text" default answer "")
set theResponse to do shell script "curl -d input=" & theSearchTest & " -d appid=" & appID & " http://api.wolframalpha.com/v1/query"

...obviously, you'll need to sign up for a free app ID. I'll leave the exercise of parsing the XML and escaping theSearchText to you. :)
I ended up integrating the web API into the code and I got it working again, thanks for the idea!
[doublepost=1495651161][/doublepost]Well now I have a new issue, I can't get my repeat loop to work while the web page is loading. It keeps on going before its loaded.

Code:
tell application "Safari"
        tell window 1 to set current tab to (make new tab with properties {URL:theUrl})
        tell document 1
            repeat
                delay 1
                if (do JavaScript "document.readyState") = "complete" then
                    exit repeat
                end if
            end repeat
 

Mark FX

macrumors regular
Nov 18, 2011
159
17
West Sussex, UK
Your repeat loop won't run because the "document.readyState" gets Safari to return a C String Ref, or NSString.
So you have to convert it into something that an AppleScript will understand, which in this case is AS text.
So change your repeat loop to something like this.

Code:
repeat until ((do JavaScript "document.readyState") as text) = "complete"
    delay (1.0)
end repeat

This should work.
 

Phoenix_E

macrumors newbie
Original poster
May 23, 2017
4
0
Your repeat loop won't run because the "document.readyState" gets Safari to return a C String Ref, or NSString.
So you have to convert it into something that an AppleScript will understand, which in this case is AS text.
So change your repeat loop to something like this.

Code:
repeat until ((do JavaScript "document.readyState") as text) = "complete"
    delay (1.0)
end repeat

This should work.

Code:
tell application "Safari"
        tell window 1 to set current tab to (make new tab with properties {URL:theUrl})
        tell document 1
            
            repeat until ((do JavaScript "document.readyState") as text) = "complete"
                delay 1
            end repeat
            
            set theAnswer to do JavaScript "document.getElementsByTagName('pre')[0].innerHTML;"
        end tell
    end tell

It's still grabbing the answer before the page is loaded and grabbing a null value, any ideas?
 

Mark FX

macrumors regular
Nov 18, 2011
159
17
West Sussex, UK
The problem appears to be that the "(do JavaScript "document.readyState")" seems to reach the "complete" state almost immediately.
Even after changing the repeat loop to something like this below, for the purposes of testing.

Code:
set x to 0 as integer
repeat
    set x to x + 1
    set readyState to ((do JavaScript "document.readyState") as text)
    if readyState = "complete" then
        exit repeat
    end if
    delay (1.0)
end repeat
set theAnswer to (readyState & return & "Repeat = " & (x as text))
display dialog theAnswer

The repeat loop exists almost straight away, so it appears that the JavaScript is returning a completed status, even before the page is fully loaded in the Safari tab.
So you may have to rethink the delaying process you use, and think of an alternative to "document.readyState".

As I've stated previously, I'm not that familiar with JavaScript myself.

Perhaps finding a way to get Safari to return a page loaded result, instead of using JavaScript.
But After looking at Safari's Scripting Dictionary, I can't find any help in there.

In short, either Safari is telling you the package has arrived when it hasn't, or the wolframalpha site is telling Safari the package has arrived when it hasn't, one of them is lying, but in either case, by using "document.readyState" in this way, your trying to open and retrieve the package contents, before it has actually been delivered.

You may have to guesstimate a delay value, instead of using the repeat loop.
Which is not ideal, as different information searches may take different amounts of time, and could even be affected by network speed and performance.
 
Last edited:

Phoenix_E

macrumors newbie
Original poster
May 23, 2017
4
0
The problem appears to be that the "(do JavaScript "document.readyState")" seems to reach the "complete" state almost immediately.
Even after changing the repeat loop to something like this below, for the purposes of testing.

Code:
set x to 0 as integer
repeat
    set x to x + 1
    set readyState to ((do JavaScript "document.readyState") as text)
    if readyState = "complete" then
        exit repeat
    end if
    delay (1.0)
end repeat
set theAnswer to (readyState & return & "Repeat = " & (x as text))
display dialog theAnswer

The repeat loop exists almost straight away, so it appears that the JavaScript is returning a completed status, even before the page is fully loaded in the Safari tab.
So you may have to rethink the delaying process you use, and think of an alternative to "document.readyState".

As I've stated previously, I'm not that familiar with JavaScript myself.

Perhaps finding a way to get Safari to return a page loaded result, instead of using JavaScript.
But After looking at Safari's Scripting Dictionary, I can't find any help in there.

In short, either Safari is telling you the package has arrived when it hasn't, or the wolframalpha site is telling Safari the package has arrived when it hasn't, one of them is lying, but in either case, by using "document.readyState" in this way, your trying to open and retrieve the package contents, before it has actually been delivered.

You may have to guesstimate a delay value, instead of using the repeat loop.
Which is not ideal, as different information searches may take different amounts of time, and could even be affected by network speed and performance.

I'm just going to stick with a 3.5 delay, it seems to be enough time for all of it. I also entered an if statement to simply open up the answer in a new tab if the returned value is null so I guess i'm all set, thanks for all the help
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.