【问题标题】:Automator - AppleScript recording and changing into valuesAutomator - AppleScript 记录并更改为值
【发布时间】:2018-01-15 06:39:27
【问题描述】:

我正在录制一个 Automator 脚本,以帮助我一次抓取一个用于获取一周信息的 URL。我想将具体值设为一个变量。

当我录制脚本后,我希望特定值(即 2018-01-02)能够更改为可以在脚本中更改的变量(即一天到 2018-01 -03)。我无法将日期更改为 Automator 中的变量。如果我将脚本复制到文本文档中,我无法将其恢复到 Automator。

有没有办法做到这一点?

作为文本的脚本如下所示:

-- Click the “2018-01-02” button.
delay 2.631525
set timeoutSeconds to 2.000000
set uiScript to "click UI Element \"2018-01-03\” of group 7 of UI Element 1 of scroll area 1 of group 23 of UI Element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window \"Historical Data Feed\" of application process \"Safari\""
my doWithTimeout( uiScript, timeoutSeconds )

在 Automator 中看起来像:

  • 点击“2018-01-02”按钮

【问题讨论】:

  • 我想知道here 的任何信息是否可以帮助您实现最终目标。无需尝试让 Automator 抓取您需要的数据,而是已经存在允许您以编程方式检索历史财务数据的 API。
  • 但是,如果您仍然希望继续使用当前方法,请添加指向您录制该脚本的 URL 的链接,这将有助于了解我们正在处理的内容。我发现了带有“日期”按钮的外汇历史数据提要小程序,所以我怀疑它是相似的,但最好使用有问题的实际页面。
  • 您好,感谢您的帮助!链接在这里:dukascopy.com/swiss/english/marketwatch/historical
  • 太好了,谢谢。你能告诉我你想用这个 Automator 和 AppleScripting 完成什么作为你的最终目标吗?因此,例如,要精确:您要单击日期按钮,选择特定日期,然后选择特定工具,然后单击“下载”按钮吗?引导我完成它,或使用相关信息更新您的问题。我想您最终希望以某种方式下载一些数据。
  • 最大的目标是通过运行脚本下载一个月的买卖数据。我只会添加月份和货币对,脚本会让所有文件出现在桌面上。那很好啊。因此,对于每天(无周末)运行的脚本,在 GMT 时间和 1 秒烛台上下载出价和询价数据为 CSV 文件。

标签: macos applescript automator


【解决方案1】:

@Matts 给出了关于在 Automator 中使用变量的一个很好的答案。但是,在更深入地讨论了您的目标的性质之后,很明显知道如何在 Automator 中引用变量根本不是问题,也不会帮助您。

事实上,甚至不用Automator。它不会做你想做的事。尝试与 Safari 进行物理交互自动化的整个努力意味着它将涉及相当多的 AppleScripting,而且它是最糟糕的一种——GUI(图形用户界面)脚本。

从Automator中出来并使用Script Editor。确保 脚本编辑器 具有相关的可访问权限,以便 GUI 脚本工作。您可以通过转到系统偏好设置>安全和隐私>隐私>辅助功能,解锁窗口左下方的挂锁,然后在脚本编辑器中找到允许控制您的计算机的应用程序列表。确保已选中。

简而言之,GUI 脚本几乎就是这样做的:控制您的计算机,使其能够发出鼠标点击并按下按钮或菜单项,就好像用户在现场亲自操作一样。

但是,弄清楚如何在可按下或单击的屏幕元素的 GUI 层次结构中引用对象是一场噩梦。

我认为您的 Automator 制造代码的 sn-p 误导了您:

    click UI Element "2017-01-03” of group 7 of UI Element 1 of scroll area 1 of ¬
        group 23 of UI Element 1 of scroll area 1 of group 1 of group 1 of tab group 1 ¬
        of splitter group 1 of window "..." of application process "Safari"

我想您看到了UI Element "2017-01-03" 并推断必须能够通过用适当的日期字符串替换当前存在的日期字符串来访问特定日期的数据。因此,您为什么要在 Automator 中使用变量。但它不会奏效。该日期字符串仅报告元素的名称(恰好是称为static text 元素的东西),其中包含一段带有日期的文本,但不是可编辑的。因此,引用UI Element "2017-01-02" 只会抛出错误,因为不存在这样的元素。

这就是我目前所想出的。这绝不是一个完整的包:我还没有编写可以直接实现您的目标的脚本,但我肯定会为您提供所有必要的组件,以便您能够拼凑出一个成品。相信我,我做了其中最累人的部分,这是一个艰苦的搜索,以获取您希望能够在 GUI 层次结构中单击的每个按钮的所有特定对象引用。

首先,重要说明:我没有使用您在 cmets 中发布的 URL 来进行我的 GUI 检查。该网页过于繁忙和复杂,这会使工作变得更加困难。但幸运的是,他们有一个指向页面的链接,该页面仅包含我们将与之交互的小部件。但是,由于页面的 GUI 构成不同(小部件与您的原始链接相同,只是页面的其余部分不同),我编写的任何代码都不适用于您的原始链接。所以你必须使用我在脚本中提供的 URL,即https://www.dukascopy.com/plugins/fxMarketWatch/detach.php?id=ct23。


引用 GUI 对象

声明一些属性变量,您可以根据要从中检索数据集的月份和年份进行更改。您还可以通过简短的缩写代码或其完整描述来指定您的仪器:

    property |URL| : "https://www.dukascopy.com/plugins/fxMarketWatch/detach.php?id=ct23"
    property Instrument : {|short|:"AAPL.US/USD", |description|:"APPLE INC"}
    property |month| : "December"
    property |year| : "2017"

下一部分是 System Events 和 Safari 进程使用的地方,它是 GUI 脚本命令的根。我还将它与我们将要与之交互的所有元素的所有元素混为一谈。否则,您必须一遍又一遍地写出它们,而将它们作为一组 UI 元素引用一次会更容易,这些元素构成 tell... 块的基础:

    tell application "System Events" to ¬
        tell application process "Safari" to ¬
            tell (window named |URL|) to ¬
                tell UI element 1 of scroll area 1 of group 1 of ¬
                    UI element 1 of scroll area 1 of group 1 of ¬
                    group 1 of tab group 1 of splitter group 1
                                  .
                                  .
                    (* The rest of our code goes
                       inside this tell block  *)
                                  .
                                  .
                end tell

另请注意,命令将发送到与网页 URL 命名相同的窗口。所以这个脚本假定网页已经在 Safari 中加载——它不会为你加载它(尽管实现起来并不困难)。

还要确保在加载页面后登录。如果不这样做,单击下载按钮会弹出登录框,这将中断整个脚本并引发错误。但是,一旦您登录并单击框以“保持登录”,从那时起它将自行进入下载选项。

下一部分是努力的成果。这是我定义变量的地方,每个变量都引用一个 GUI 对象,您希望能够从脚本发出点击和按下。

这三个构成了您可以选择的每一行可用工具的主要组件:

    set Instruments to a reference to groups of group 1 of group 1 of group 3
        --> All Instruments (410 of them)
    set Instrument_Abbreviations to a reference to static texts of group 1 of group 2 of Instruments
        --> The short text code for each instrument
    set Instrument_Descriptions to a reference to static texts of group 2 of Instruments
        --> The long text for each instrument

这是用于选择时区、本地或 GMT 的一对元素:

    set LOCAL_GMT to a reference to checkboxes of group 1 of group 7 of group 4

下一个元素块需要一些工作才能浏览。这些是负责选择日期的人。按日期按钮可在屏幕上弹出日历,您可以在其中选择年、月和日。这也将构成您的程序循环的核心,因为您使用变量在一个月的几天中循环以检索所有数据文件,例如 12 月。

菜单和对象(例如这个日历)“弹出”的地方在于,它们在创建并出现在我们的屏幕上之前并不实际存在。因此,在 GUI 脚本中,当脚本尝试引用将在未来某个时间点存在但当前不存在且还不存在的对象时,可能会引发错误。使用a reference to 是解决这个问题的一种方法,我已经为大多数变量声明做到了这一点。

    set Date_button to a reference to button 1 of group 3 of group 4
        --> The date button
    set Calendar_year_button to a reference to button 2 of UI element 2 of row 1 of table 1 of group 5
        --> The button that pops up the year menu (as shown)
    set Calendar_year_list_items to a reference to static texts of groups of group 1 of group 1 of UI element 1 of row 1 of table 1 of group 5
        --> The year menu
    set Calendar_month_button to a reference to button 2 of UI element 1 of row 1 of table 1 of group 5
        --> The button that pops up the month menu
    set Calendar_month_list_items to a reference to static texts of groups of group 1 of group 1 of UI element 1 of row 1 of table 1 of group 5
        --> The month menu
    set Calendar_days to a reference to static texts of UI elements 2 thru -1 of rows 3 thru -2 of table 1 of group 5
        --> All the day text objects visible at any one time
        --> 6 rows x 7 days = 42 text objects

接下来的三个变量用于单击“勾选”按钮,该按钮会弹出一个菜单。这组中的最后一对是 BID/ASK 按钮。

    set Tick_button to a reference to static text 1 of group 1 of group 1 of list 2 of group 1 of group 4
        --> The tick button
    set Tick_menu_items to a reference to menu items of list 1
        --> The pop-up menu items as shown below
    set BID_ASK to a reference to checkboxes of group 1 of group 2 of group 4
        --> The "BID" and "ASK" buttons

接下来是下载按钮:

    set Download_button to a reference to button "Download" of group 8 of group 4

现在,当单击下载按钮时,GUI 会在此底部进行重建。首先,会显示一个进度条来代替所有暂时消失的按钮:

我忽略了这些元素,因为我认为没有必要在这么短的时间内访问取消按钮。

然后另一个重建和“另存为 CVS”和“重置”按钮出现。我们都需要:

    set Reset_button to a reference to button "Reset" of group 2 of group 4
    set Save_button to a reference to button "Save as .csv" of group 2 of group 2 of group 4

现在我们拥有了我们需要访问的所有 GUI 对象,通过引用存储在一组变量中,我们(我的意思是你)可以利用这些变量来执行实际的自动化过程。


执行一些操作

一些变量包含对可以直接执行操作的元素的引用,例如click Date_button。但是,其他人会抛出错误或无法按照您的预期执行。这是因为一些变量包含对单个对象的引用,例如Date_button,而其他变量包含对嵌套列表中的几个不同对象或对象组的引用,例如Calendar_year_list_items。

在使用这些嵌套列表之前,我们必须将它们展平为一个列表。以下函数将执行此操作,并且可以添加到脚本的最后(end tell:

    on flattened(L) -- recurse nested lists and return a one-dimensional list
        if class of L is not list then
            return [L]
        else if length of L is 0 then
            return L
        else
            return flattened(the first item of L) & ¬
                flattened(the rest of L)
        end if
    end flattened

现在我们拥有了开始让这些对象执行某些操作所需的一切。为此,我认为最好编写另一个函数。它可以在on flattened 函数声明之前:

    on Download_CSV_Data for _instrument from _date
        local _instrument, _date
        set [_day, _month, _year] to [day, month, year] of date _date
        
        global Instruments, Instrument_Abbreviations, Instrument_Descriptions, LOCAL_GMT, ¬
            Date_button, Calendar_year_button, Calendar_year_list_items, Calendar_month_button, ¬
            Calendar_month_list_items, Calendar_days, Tick_button, Tick_menu_items, ¬
            BID_ASK, Download_button, Reset_button, Save_button
        
        tell application "System Events"
            
            click 1st item of my flattened(Instrument_Abbreviations whose name is _instrument)
            -- click 1st item of my flattened(Instrument_Descriptions whose name is Instrument's |description|)
            
            click Tick_button
            click (Tick_menu_items whose name is "Second")
            click (BID_ASK whose name is "ASK")
            
            click (LOCAL_GMT whose name is "GMT")
            
            click Date_button
            click Calendar_year_button
            click 1st item of my flattened(Calendar_year_list_items whose name is _year)
            click Calendar_month_button
            click 1st item of my flattened(Calendar_month_list_items whose name is (_month as text))
            click 1st item of my flattened(Calendar_days whose name is _day)
            
            click Download_button
            
            repeat while not (exists Reset_button)
                delay 1
            end repeat
            
            click Save_button
            click Reset_button
            
        end tell
    end Download_CSV_Data

要下载与特定日期相关的数据文件,您只需调用该函数即可。您可以将该函数调用放在第一个 end tell 语句(变量声明之后)和第一个函数声明之前的广告之间,因此您的脚本将如下所示:

    property |URL| : "https://www.dukascopy.com/plugins/fxMarketWatch/detach.php?id=ct23"
    property Instrument : {|short|:"AAPL.US/USD", |description|:"APPLE INC"}
    property |month| : "December"
    property |year| : "2017"


    -- GUI object variable declarations
    tell application "System Events" to ¬
        tell application process "Safari" to ¬
            tell (window named |URL|) to ¬
                tell UI element 1 of scroll area 1 of group 1 of ¬
                    UI element 1 of scroll area 1 of group 1 of ¬
                    group 1 of tab group 1 of splitter group 1
                    .
                    .
                    .
                end tell


    (*** Insert function calls here ***)
    Download_CSV_Data for Instrument's |short| from "17/12/2017"


    on Download_CSV_Data for _instrument from _date
        .
        .
        .
    end Download_CSV_Data

    on flattened(L) -- recurse nested lists and return a one-dimensional list
        .
        .
        .
    end flattened

如果您在美国,您可能需要在短时间内调换月份和日期。所以我写了Download_CSV_Data for Instrument's |short| from "17/12/2017",你可能必须写Download_CSV_Data for Instrument's |short| from "12/17/2017"(使用你的计算机系统使用的任何短日期格式)。

【讨论】:

  • 非常感谢您对我的问题的“小说”。明天我会处理这个问题,当我有其他问题时会回复你。看来您已经找到了问题的解决方案,并以我再过一个月都找不到的方式解决了它。 :-)
  • 这真的很有帮助。当我得到脚本时,脚本的结果是:按钮“另存为.csv”的第 2 组第 2 组 UI 元素 1 滚动区域 1 第 1 组 UI 元素 1 组的滚动区域 1应用程序“系统事件”的应用程序进程“Safari”的名为“dukascopy.com/plugins/fxMarketWatch/detach.php?id=ct23”的窗口的拆分器组 1 的选项卡组 1 的组 1。我不是说该怎么做。我希望它能让我下载文件。
  • 我还没有把它做成会重复的东西,所以这只是在一次运行之后。
  • 是的,结果是正确的,因为它是最后一个要定义的变量。它至少表明它工作正常。还没有发出click 命令,所以当然不会下载任何内容。这是下一步:让对象执行您想要的操作。我会在接下来的几天里写更多关于如何做到这一点的文章。
  • 已更新我的答案。您现在应该能够使用 Download_CSV_Data 函数下载特定日期的 CSV 文件。告诉我进展如何。
【解决方案2】:

您可以使用“运行 applescript”命令在 Automator 中设置变量。通过在 automator 的搜索框中键入“applescript”来搜索命令。然后您可以在脚本中设置变量。这是一个如何完成的示例:

set dateVar to "2018-01-02"
-- Click the “2018-01-02” button.
delay 2.631525
set timeoutSeconds to 2.0
set uiScript to "click UI Element \"" & dateVar & "\" of group 7 of UI Element 1 of scroll area 1 of group 23 of UI Element 1 of scroll area 1 of group 1 of group 1 of tab group 1 of splitter group 1 of window \"Historical Data Feed\" of application process \"Safari\""
my doWithTimeout(uiScript, timeoutSeconds)

您还可以使用其他方法来设置日期。这篇文章有很多关于在 Applescript 中使用日期的信息https://macscripter.net/viewtopic.php?id=24737

UI 元素编号也可能不同,因此您需要考虑到这一点才能让您的脚本使用变量。

编辑:当您获得使用另一种方法的帮助时,我可以看到我的答案现在与您的情况无关。尽管 Applescript 会完成这项工作,但要完成下载文件的最终目标是一种相当困难的方法。我发现使用 Selenium、Firefox 和 Python 是一种更容易让浏览器自动下载文件的方法。当您了解如何使用 xpath 并偶尔执行一些 javascript 时,它的效果最好,但如果您将来会做更多的事情,您可能需要考虑这种方法。您也可以使用标签、id 或类选择器来代替 xpath。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-22
    • 2015-08-01
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 2020-11-06
    相关资源
    最近更新 更多