AppleScript 不会超越顶级

AppleScript won't go beyond top level

我找到了一个用于下载有关加密货币的信息的脚本,这样我就可以使用 AppleScript 下载到 Numbers 电子表格中。这是脚本:

set mySheetName to "Coin Prices"
set myTableName to "Coin Prices"
set tgtCell to "A2"

set theHtml to do shell script "curl -s " & quoted form of "https://www.worldcoinindex.com"
set text item delimiters to {"<tbody>", "</tbody>"}
set tableContents to theHtml's text item 2 # item 2 is the body of the price table
set text item delimiters to {"<h2>"} # site uses new h2 for each currency
set tableChunks to tableContents's text items 2 thru -1
set pasteStr to ""
repeat with aChunk in tableChunks
    set text item delimiters to "><span>$ </span><span class=\"span\">"
    tell aChunk's text item 1 to set {theSymbol, thePrice} to {first word, last word}
    set pasteStr to pasteStr & theSymbol & tab & thePrice & return
end repeat
set the clipboard to pasteStr


tell application "Numbers"
    tell front document
        tell sheet mySheetName to tell table myTableName
            
            activate
            set selection range to range tgtCell
            delay 0.3
            tell application "System Events" to keystroke "v" using {option down, shift down, command down}
        end tell
    end tell
end tell

在我设置这条线之前,它工作得很好:

set theHtml to do shell script "curl -s " & quoted form of "https://www.worldcoinindex.com/watchlist"

我检查了网页代码,它完全一样,但我得到一个很大的长错误框,与第 2 项有关。我不会复制和粘贴,因为错误框包含了完整的源代码网页。错误是这样的:

Can’t get text item 2 of

这是源代码。

为什么这个脚本基于 URL 而不是 URL 的子目录?

感谢大家的帮助。

简短的回答是主页包含明确的 html table,而监视列表页面似乎是由 [=19= 生成的 div 元素的结构化系列] 并且看起来像 table。监视列表页面上没有 'tbody' 元素,因为那里没有 table。 text items 命令将第一页分成三部分(第二部分是你想要的);它根本不会拆分监视列表页面,它会生成一个数组,其中包含一个包含所有 html 的项目。当您向 1 个元素的数组询问其第二项时,您会收到错误消息。

您将不得不检查第二页的 html 并弄清楚如何拆分文本以提取您想要的信息。

因为我没有帐户来访问 https://www.worldcoinindex.com/watchlist 并在登录时看到它 源代码,我相信你的话它有 <tbody></tbody> tags 并为您提供使用 curl.

的替代解决方案

假设您正在使用 Safari 并在目标 URL 页面登录 已完全加载,您可以使用以下 example AppleScript code 来获取数据你找。

将以下内容添加到现有 AppleScript script 的顶部,同时注释掉 [=59] 的 set theHtml to do shell script ... 行=]代码.

tell application "Safari" to ¬
    set theHtml to do JavaScript ¬
        "document.getElementById('myTable').innerHTML;" in document 1

注意JavaScript命令中的myTable来自table 在主域上,可能需要针对 Watchlist.

进行调整

查看 页面源代码 例如:

<table id="myTable" class= ... >
<thead>

您也可以使用例如:

"document.getElementsByClassName('...')[0].innerHTML;"in document 1

... 替换为 class=

源代码 中所示

更新:

这是 example AppleScript code 的一个版本,它将打开一个新的 Safaridocument到目标URL,然后动态创建一个 文档 在后台,完成后将其放在最前面。不要以一开始就不应该做的方式使用 curl 或解析 HTML。没有剪贴板或粘贴到 Numbers.

请注意,Safari window 可以在其 id 确定后保留在后台,这一旦 window 第一次出现只需要一点时间,然后您可以在 script 运行时将焦点设置在其他地方。新的 Safari window 实际上已经在后台创建了 Safari没有被告知 activate.

我为网站创建了一个 login 并将前三个 coins 添加到我的 watchlist,这张截图是动态创建的 Numbers document。如果您在 中将 theURL 设置为 URL AppleScript code.

请注意,按照当前编码,如果未登录,它将通知您并中止 脚本 的 运行。我希望稍后更新 code 以处理未登录和动态登录的情况,但这是 example[=126 的下一次迭代=] AppleScript code.

示例 AppleScript 代码:

property theURL : "https://www.worldcoinindex.com/watchlist"
-- property theURL : "https://www.worldcoinindex.com"

property myNumbersSheetName : "Coin Prices"
property myNumbersTableName : "Coin Prices"


--  # Do not modify code below unless necessary.

property winID : missing value
property itemCount : missing value
property loginStatus : missing value
property thisNumbersDocument : missing value
property theNumbersDocumentName : missing value
property theSafariDocumentName : missing value

--  # Create a new Safari document to the target URL.
--  # Get the id of the newly created window.
--  # Wait for the page to finish loading.
--  # Get the name of the newly created document.
--  # Get Login status and if not already logged in,
--  # notify user and abort the running of the script.
--  # Get the count of ticker symbols for Numbers.

tell application "Safari"
    make new document with properties {URL:theURL}
    set winID to id of window 1
    my waitForSafariPageToFinishLoading()
    set theSafariDocumentName to name of window id winID
    tell document theSafariDocumentName
        set loginStatus to ¬
            do JavaScript ¬
                "document.getElementsByClassName('logout-nav-container')[0].innerHTML;"
        if loginStatus contains "Login" then
            display dialog ¬
                "You are not logged in!   Please login, " & ¬
                "then run script again..." buttons {"OK"} ¬
                default button 1 with title ¬
                "Login Required To Run This Script"
            return
        else
            set itemCount to my getTickerSymbolCount()
        end if
    end tell
end tell


--  # Create a new document in Numbers in the background.
--  # Create two columns and one row more than the number of
--  # ticker symbols on the page. Set the column header names.

tell application "Numbers"
    set columnCount to 2
    set rowCount to itemCount + 1
    set thisNumbersDocument to make new document
    set theNumbersDocumentName to the name of thisNumbersDocument
    tell thisNumbersDocument
        delete every table of every sheet
        tell active sheet to set its name to myNumbersSheetName
        tell sheet myNumbersSheetName
            set thisTable to ¬
                make new table with properties ¬
                    {name:myNumbersTableName ¬
                        , column count:columnCount ¬
                        , row count:rowCount}
            tell thisTable
                set value of cell "A1" to "Ticker Symbol"
                set value of cell "B1" to "Last Price"
            end tell
        end tell
    end tell
end tell


--  # Get the 'Ticker Symbol' and 'Last Price' for 
--  # the number of symbols on the page, setting their 
--  # values to the target cells in the Numbers document.

tell application "Safari"
    tell document theSafariDocumentName
        set n to 2
        repeat with i from 0 to itemCount - 1
            set |Ticker Symbol| to ¬
                first paragraph of ¬
                (do JavaScript ¬
                    "document.getElementsByClassName('ticker')[" & i & "].innerText;")
            my addToNumbersTable("A", n, |Ticker Symbol|)
            set |Last Price| to ¬
                (do JavaScript ¬
                    "document.getElementsByClassName('number pricekoers lastprice')[" & i & "].innerText;")
            my addToNumbersTable("B", n, |Last Price|)
            set n to n + 1
        end repeat
    end tell
end tell


-- # Set focus to cell A1 and bring 
-- # the Numbers document frontmost.

tell application "Numbers"
    --  # Set focus to cell A1.
    tell table myNumbersTableName of ¬
        sheet myNumbersSheetName of ¬
        document theNumbersDocumentName to ¬
        set selection range to range "A1"
    activate
end tell



--  ##  Handlers  ##

to getTickerSymbolCount()
    tell application "Safari" to ¬
        tell document ¬
            theSafariDocumentName to ¬
            return ¬
                (do JavaScript ¬
                    "document.getElementsByClassName('ticker').length;") ¬
                    as integer
end getTickerSymbolCount

to addToNumbersTable(c, n, v)
    --  # Sets the value of the target cell.    
    tell application "Numbers" to ¬
        tell table myNumbersTableName of ¬
            sheet myNumbersSheetName of ¬
            document theNumbersDocumentName to ¬
            set value of cell (c & n) to v
end addToNumbersTable

on waitForSafariPageToFinishLoading()
    --  # Wait for page to finish loading in Safari.
    --  # This works in **macOS Catalina** (10.15.7) and 
    --  # macOS Big Sur (11.4) and may need adjusting for
    --  # updated versions of Safari in these version of 
    --  # macOS, or other versions of macOS past or future.
    tell application "System Events" to repeat until ¬
        exists (buttons of groups of toolbar 1 of window 1 of ¬
            process "Safari" whose name = "Reload this page")
        delay 0.5
    end repeat
end waitForSafariPageToFinishLoading


注意:示例 AppleScript code 就是这样,没有任何包含的 错误处理 不包含任何额外的 错误处理 可能是适当的。用户有责任根据需要或需要添加任何 错误处理 。查看 try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay 命令 在适当的事件之间可能是必要的,例如delay 0.5,适当设置延迟