【问题标题】:AppleScript won't go beyond top levelAppleScript 不会超越顶层
【发布时间】:2021-06-13 02:18:51
【问题描述】:

我找到了一个用于下载加密货币信息的脚本,以便我可以使用 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 项有关的大而长的错误框。我不会复制和粘贴,因为错误框包含网页的整个源代码.错误是这样的:

无法获取文本项 2 of

从那里它是源代码。

为什么这个脚本在 URL 的基础而不是 URL 的子目录上工作?

感谢您的帮助。

【问题讨论】:

  • 我在https://www.worldcoinindex.com/watchlist 的源代码中看不到任何&lt;tbody&gt; 标签。
  • 当我搜索 tbody 时,它给了我两次点击。一个开始和结束标签。您是否列出了任何货币?如果您不这样做,它可能不会显示。

标签: curl applescript applescript-numbers


【解决方案1】:

由于我没有访问https://www.worldcoinindex.com/watchlist 的帐户并在登录时查看它源代码,我相信它有&lt;tbody&gt;&lt;/tbody&gt; tags 并为您提供使用 curl 的替代解决方案。

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

将以下内容添加到现有 AppleScript script 的顶部,同时注释掉 codeset theHtml to do shell script ... 行。

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

请注意,JavaScript command 中的myTable 来自主域上的table,可能需要针对关注列表。

查看页面来源,例如:

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

你也可以使用例如:

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

... 替换为class=源代码中所示



更新:

这是一个版本的示例 AppleScript 代码,它将打开一个新的Safari 文档 到目标URL,然后在后台动态创建一个Numbers document,完成后把它放在最前面。不使用curl 或解析HTML 的方式确实不应该放在首位。没有剪贴板或粘贴到数字

请注意,一旦确定了idSafari 窗口 可以保持背景,而一旦窗口首先出现,然后您可以在 脚本 运行时将焦点设置在其他地方。新的 Safari window 在创建时实际上已经在后台,因为 Safari 没有被告知activate

我为网站创建了一个登录,并将前三个硬币添加到我的关注列表中,这个截图是动态创建的数字 文档。如果您在 example AppleScript 代码。

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

示例 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 代码就是这样,没有任何包含的错误处理 em> 不包含任何适当的附加错误处理。用户有责任根据需要或需要添加任何错误处理。查看AppleScript Language Guide 中的try statementerror statement。另请参阅Working with Errors。此外,在适当的情况下,可能需要在事件之间使用delay 命令,例如delay 0.5延迟设置得当。

【讨论】:

  • ??? 这太神奇了。它工作得很好。我想这意味着我必须打开该页面并登录。所以我发现这个脚本可以在 Safari 中打开正确的选项卡:do shell script "open -a \"Safari\" \"" &amp; "https://www.worldcoinindex.com/watchlist" &amp; "\""
  • @Loweded Wookie,我会使用 tell application "Safari" to make new document with properties {URL:"https://www.worldcoinindex.com/watchlist"} 而不是 do shell script 命令来打开 URL
  • @Loweded Wookie,RE:“我想这意味着我必须打开并登录该页面。” -- 是的,但是您没有通过curl_ command 获得 data 以及为什么我提供此作为替代方案。我很确定整个过程可以编码为非交互式。换句话说,如果可以保存登录凭据,甚至可以通过编程方式输入,脚本 可以从头到尾运行,而您只需运行它。
  • 很奇怪,它现在停止工作并出现错误消息 The variable theHtml is not defined.
  • 好像不太喜欢tell application "Safari" to ¬ set theHtml to do JavaScript ¬ "document.getElementById('myTable').innerHTML;" in document 1这个方法。我恢复到 do 脚本方法,它工作正常。我会暂时坚持这个。
【解决方案2】:

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

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

【讨论】:

  • 我正在查看的页面上肯定有一个 tbody。我开始认为我可能知道问题出在哪里。当我使用 Safari 时,我看到了我想要的信息,因为我已登录。但是,当我运行脚本时,我没有。问题是,如果我使用主页,我看不到我特别想要的硬币。我也只看到网站上大约 500 个硬币中的 100 个。
  • @LowededWookie:我们说话的时候,我正在查看有问题的页面,并且任何地方都没有 tbody 元素。当然,我没有登录(我什至没有帐户),所以也许你是对的,这就是问题所在。恐怕我不是 curl 专家,但我相信您可以扩展 curl 命令以使用登录名和密码或证书(不确定该站点如何处理登录)。您可能需要与那里的站点经理交谈以获取详细信息。
  • 当然,任何地方都没有tbody元素,因为指示的网页内容是单张图片,而不是文字。
  • 有了一个账户,你可以设置一堆硬币来关注。当页面上有硬币时,肯定是 100% 的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-11
  • 2014-01-09
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多