3

Objectives:

I want to create an AppleScript .scpt file that does the following:

  1. Accesses a router's webpage (i.e., its IP address).

  2. From this webpage, gets the IP addresses that are currently connected to both networks. (By "both networks", I refer to the separate 2.4Ghz and 5.0Ghz wireless networks.)

  3. From the webpage, gets the respective Dbm signal strengths of each connected device (i.e., each connected IP address).


Implementation:

I want one AppleScript list object to contain all of the IP addresses:

  • E.g.: theListOfIPs contains {"192.168.0.1", "192.168.0.", "192.168.0.3", "192.168.0.4", "192.168.0.5", "192.168.0.6.", "192.168.0.7"}.

(I do not have the need to differentiate between the IPs that are connected to the 2.4GHz network and the IPs that are connected to the 5.0GHz network. All IPs should simply be contained in theListOfIPs.)

And, one AppleScript list object to contain their corresponding signal strengths:

  • E.g.: theListOfTheirSignalStrengths contains {"0", "-75", "-40", "0", "0", "-63", "-72"}.

Notes:

  • I would like all of this to be completed "behind the scenes." Unobtrusiveness is really key, because the script will need to periodically check the router's website for network updates.

  • Ultimately, changes to the network status will be written to a .txt log file, and an alert notification will be displayed, when certain conditions are met. I know how to code these components; I need help actually importing the data into the script.

  • Browser of choice: Google Chrome


Background:

I have used the shell command , curl, before, in order to import the unabridged HTML source code of a given website into an AppleScript, as a text object. I understand that, sadly, one cannot similarly or conveniently get all JavaScript elements into an AppleScript as a single text object.

Instead, one must get each and every JavaScript element individually, by some identifier, like its id, class, tag, or name. This makes things more complicated (because you can't simply parse everything in AppleScript).

By using Chrome's Inspect feature, and the Elements pane of Chrome's JavaScript console, I've determined the relevant JavaScript identifiers. The two JavaScript element IDs that contain all IP addresses, as well as their signal strengths, are wifi-24 and wifi-5.

Can someone teach me how to write the necessary JavaScript code correctly, and then parse the resulting HTML text, to isolate the basic network data that I desire?


  • The problem is that the desired URL is behind a username/password page. If I pasted the URL here, it would be meaningless to you. – rubik's sphere Aug 12 '17 at 21:27
  • Okay. I wasn't asking for a customized solution. I just want to know if this is even possible, and, if it is, a general idea of how to approach it. Here is a more direct version of my question: Is it possible to scrape all of the JavaScript elements from a website? Your comment leads me to believe that the answer to this question varies significantly from site to site, but I do not understand why the answer would vary. Isn't this a yes/no question? – rubik's sphere Aug 13 '17 at 0:48
  • Your question is all over the place. Yes it is possible. Without an actual example of a site you are interested in .js scraping, there is no one applescript fits all approach. – Mr. Kennedy Aug 13 '17 at 0:54
  • @Mr.Kennedy Can you point me in the right direction, so I can start learning about this? What is the relevant command to accomplish this? I don't know where to begin. – rubik's sphere Aug 13 '17 at 1:09
  • To scrape all the javascript, you'll need to learn how html and javascript work together. View the source HTML - look for the *.js files. Dynamic pages will present more issues. Start with a simple and small example of html/JS and build your AppleScript. Then figure out more complex HTML/JS situations and develop your tool to accommodate them. – Mr. Kennedy Aug 13 '17 at 1:13
3

Based on the discussions had, this should handle the original scope of the question.

Note: This is example code and does not contain much, if any, error handling. I'll leave that to you since this is only a portion of the overall script, once you put all the other pieces together.

--  # 
--  #   Get the target information from theTargetURL in Google Chrome.
--  #   
--  #   Do this in the background, so get the 'tab id' and 'window id' of
--  #   the target URL ('theTargetURL') if it exists, and process accordingly. 

set theTargetURL to "http://192.168.1.1/0.1/gui/#/"

tell application "Google Chrome"
    if running then
        set theWindowList to every window
        repeat with thisWindow in theWindowList
            set theTabList to every tab of thisWindow
            repeat with thisTab in theTabList
                if theTargetURL is equal to (URL of thisTab as string) then

                    --  #   Get the targeted content of the web page which contains the information.
                    --  #   Note that document.getElementById(elementID) can only query one
                    --  #   element at a time, therefore call it twice, once with each elementID.

                    set rawWiFi24HTML to thisTab execute javascript "document.getElementById('wifi-24').innerHTML;"
                    set rawWiFi5HTML to thisTab execute javascript "document.getElementById('wifi-5').innerHTML;"

                    tell current application

                        --  #   Process the 'rawWiFi24HTML' and 'rawWiFi5HTML' variables.
                        --  #   Setup some temporary files to handle the processing.

                        set rawHTML to "/tmp/rawHTML.tmp"
                        set rawIP to "/tmp/rawIP.tmp"
                        set rawDBM to "/tmp/rawDBM.tmp"

                        --  #   Combine the value of  the'rawWiFi24HTML' and 'rawWiFi5HTML' variables into the 'rawHTML' temporary file.

                        do shell script "echo " & quoted form of rawWiFi24HTML & " > " & rawHTML & "; echo " & quoted form of rawWiFi5HTML & " >> " & rawHTML

                        --  # Process the 'rawHTML' into the 'rawIP' and 'rawDBM' temporary files.
                        --  # These files will contain comma delimited content of the targeted info.

                        do shell script "grep 'IP:' " & rawHTML & " | sed -e 's:</span>.*$::g' -e 's:^.*>::g' | tr '\\12' ',' > " & rawIP & "; grep 'device.parsedSignalStrength' " & rawHTML & " | sed -e 's: dBM.*$::g' -e 's:^.*\"::g' | tr '\\12' ',' > " & rawDBM

                        -- Process 'rawIP' and 'rawDBM' temporary files into 'theIPAddressList' and 'theSignalStrengthList' lists.

                        set theIPAddressList to my makeListFromCSVFile(rawIP)
                        set theSignalStrengthList to my makeListFromCSVFile(rawDBM)

                        --  #   Clean up, remove temporary files.

                        do shell script "rm /tmp/raw*.tmp"

                    end tell

                end if
            end repeat
        end repeat
    end if
end tell

--  # Handler used to create a list from a CSV file.

on makeListFromCSVFile(thisFile)
    set thisFilesContents to (read thisFile)
    set AppleScript's text item delimiters to {","}
    set thisList to items 1 thru -2 of text items of thisFilesContents as list
    set AppleScript's text item delimiters to {}
    return thisList
end makeListFromCSVFile




--  #########################################
--  #   
--  #   Checking the output of the code:
--  #   
--  #   The following commands are here just to show the contents
--  #   of the two lists displayed in a default list box, and then a way 
--  #   both lists might be combined, the output of which is logged.
--  #   
--  #   This of course can be removed after testing is finished.
--  #   
tell current application
    --  #
    choose from list theIPAddressList & theSignalStrengthList
    --  #
    repeat with i from 1 to (count of theIPAddressList)
        log "IP: " & item i of theIPAddressList & " @ " & item i of theSignalStrengthList & " Dbm"
    end repeat
    --  #
end tell
--  #   
--  #########################################

I do have to say that generally speaking, one is not supposed to parse HTML with tools like grep and sed, however, for certain pages, like in this use case, it's pretty safe to do. Although, if it breaks, it's not hard to fix.

  • When I incorporated your code into my larger script, I was getting the error: Can’t make current application into type file.. I realized that the following line in my script was responsible for the error: use framework "Foundation". After I changed your line (read POSIX file thisFile) to (read POSIX path of thisFile) or simply to (read thisFile), your code now functions properly within my script, without error. – rubik's sphere Aug 14 '17 at 12:45
  • Yes, this is why I said "Note: This is example code ...", because if you take the code as is and copy it into a new document in Script Editor as the only code in the script, it works, but when one starts integrating code from other sources there is bound to be issues that need to be addressed. – user3439894 Aug 14 '17 at 12:49
  • Is it just me, or are the final list objects nested versions of themselves? That is, if you return theIPAddressList or if you return theSignalStrengthList, you will see that item x of either list (where x is any item of the list), is actually the desired list itself. This peculiarity will be masked if you use choose from list, but you can see the true list contents if you use return. Here are screenshots. – rubik's sphere Aug 14 '17 at 13:18
  • @rubik's sphere, I have changed the code to create comma delimited temporary files and the way in which the contents of those files are turned into the wanted lists. – user3439894 Aug 14 '17 at 21:33
  • You wrote, "Generally speaking, one is not supposed to parse HTML with tools like grep and sed." Could you explain why this is, exactly? What is the alternative for parsing HTML text? – rubik's sphere Aug 17 '17 at 9:00
0
  1. Go to the web page in the Chrome browser.
  2. Open the Dev Tools' JavaScript browser.
  3. Stick this in the console and hit enter:

 

$('script').each(function(){
    console.log($(this).html())
});
  • I followed these instructions. What should I be looking for or what's the next step? Thank you. – rubik's sphere Aug 13 '17 at 1:19
  • You could've at least made it log instead of alerting, that's just painful. – Sirens Aug 13 '17 at 6:52
  • @Sirens there you go. My main point was to demonstrate that the OP was headed in the wrong direction. Per the chat room conversation, they've found a better way. – Mr. Kennedy Aug 14 '17 at 0:16

You must log in to answer this question.

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