Resolved Need help with applescript

Discussion in 'Mac Programming' started by Phoenix_E, May 23, 2017.

  1. Phoenix_E macrumors newbie

    Phoenix_E

    Joined:
    May 23, 2017
    #1
    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
    
    
     
  2. superscape, May 24, 2017
    Last edited: May 24, 2017

    superscape macrumors 6502a

    superscape

    Joined:
    Feb 12, 2008
    Location:
    East Riding of Yorkshire, UK
    #2
    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. :)
     
  3. Mark FX macrumors regular

    Mark FX

    Joined:
    Nov 18, 2011
    Location:
    West Sussex, UK
    #3
    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.
     
  4. Phoenix_E thread starter macrumors newbie

    Phoenix_E

    Joined:
    May 23, 2017
    #4
    I ended up integrating the web API into the code and I got it working again, thanks for the idea!
    --- Post Merged, May 24, 2017 ---
    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
    
     
  5. superscape macrumors 6502a

    superscape

    Joined:
    Feb 12, 2008
    Location:
    East Riding of Yorkshire, UK
    #5
    I thought you'd abandoned automating Safari in favour of using the API?
     
  6. Mark FX macrumors regular

    Mark FX

    Joined:
    Nov 18, 2011
    Location:
    West Sussex, UK
    #6
    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.
     
  7. Phoenix_E thread starter macrumors newbie

    Phoenix_E

    Joined:
    May 23, 2017
    #7
    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?
     
  8. Mark FX, May 28, 2017
    Last edited: May 28, 2017

    Mark FX macrumors regular

    Mark FX

    Joined:
    Nov 18, 2011
    Location:
    West Sussex, UK
    #8
    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.
     
  9. Phoenix_E thread starter macrumors newbie

    Phoenix_E

    Joined:
    May 23, 2017
    #9
    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
     

Share This Page