带有 do Javascript 的 Applescript 并传递了 Applescript 变量

Applescript with do Javascript and passed Applescript Variable

我编写了一个脚本,可以在我管理的网站上自动创建产品。在我的过程中,我上传了产品的 JPEG 图片,并提取了 JPEG 中标记的关键字以添加到产品信息中。在此过程中,我使用 Applescript 激活 Safari 并处理 Javascript 行代码。该行代码包含一个派生自 Applescript Shell 脚本的变量。

下面的代码

tell application "Finder"
set sourceFolder to folder POSIX file "/Users/<username>/Desktop/Upload/Temp/HighRes/"
set theFiles to files of sourceFolder
set inputPath to "/Users/<username>/Desktop/Upload/Temp/"

end tell

repeat with afile in theFiles

set filename to name of afile

set fname to text 1 thru ((offset of "." in filename) - 1) of filename

--INPUT CODE TO BE LOOPED OVER BELOW--


--Add Image Keywords from Metadata--
try
    set pathVAR1 to "/Users/<username>/Desktop/Upload/Temp/HighRes/"

    set pathVAR2 to pathVAR1 & filename

    set myvar to do shell script "mdls -name kMDItemKeywords " & quoted form of pathVAR2

    set var1 to ((offset of "(" in myvar) + 1)

    set var2 to ((length of myvar) - 1)

    set myKeywords to ((characters var1 thru var2 of myvar) as string)

    --Inputs the Keywords from the Image Metadata--
    tell application "Safari"
        activate
        do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = \"" & myKeywords & "\";" in current tab of window 1
    end tell
end try

--END OF CODE TO BE LOOPED OVER--


end repeat

==结束代码==

问题:

下面的代码没有将变量 myKeywords 传递给 Safari,但是如果我 运行 一个对话框,它将出现在对话框中。

do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = \"" & myKeywords & "\";" in current tab of window 1

我没有一定能解决您问题的特定解决方案,但我确实对您的脚本有很多观察,并就如何更改脚本以提高其速度、稳健性和遵守原则提出了建议最佳实践。

  1. 去掉那个 try 块。 如果你屏蔽不必要的错误 error-catching。唯一需要包含在 try...end try 中的行是 do shell script,但只有在您知道您的代码正在运行时才将其放入。一般来说,只应使用 try 个块:

    • 当您的脚本有可能抛出完全 可预测的 的错误时explainable,并且你了解错误发生的原因和条件,让你实施有效的error-handling方法;
    • 尽可能少的行代码中出现错误,留下所有不存在的代码行取决于 error-prone 语句的结果;
    • 在您的脚本编写、测试和调试后,放置 try 块不再用于强制脚本在出现未知来源的不便错误后继续执行,但有一个明确的 well-defined 功能可以与您的代码协调一致,而不是违背它。
  2. 作为 AppleScript 中的一般规则,如果可以避免,请不要使用 Finder 执行文件系统操作:它很慢,并且在运行时会阻塞执行操作,这意味着您在此期间无法与 GUI 交互。请改用 系统事件 。它是一个匿名应用程序,在执行任务时不会停止其他操作;它很快,特别是在 AppleScript 和 Finder 的上下文中,并且不像 Finder 那样容易超时;它本机处理 posix 路径( 包括波浪号的 扩展),无需使用 POSIX file 进行任何强制转换; it returns alias 对象,它们是每个其他可编写脚本的应用程序都能理解的通用 class 文件对象。

    有几个实例仍然需要 Finder系统事件 不能reveal 一个文件;它也无法为您提供 Finder 中当前选定的文件。但是让 Finder 检索 selection 作为 alias list,然后切换到 System Events 来做此列表中的实际文件处理。

  3. 这很奇怪:

    set filename to name of afile
    set fname to text 1 thru ((offset of "." in filename) - 1) of filename
    

    我是否认为 fname 仅打算保留文件名的基本文件名部分,而此操作旨在去除扩展名?这是一个很好的第一次尝试,并且在此处使用 text 而不是 characters 来逐项列出字符串的组成部分,做得很好。但是,当然,如果文件名中有多个 ".",那么最终砍掉的不仅仅是文件扩展名,这并不少见。

    安全阉割文件名末尾的一种方法是使用text item delimiters:

    set filename to the name of afile
    set fname to the filename
    
    set my text item delimiters to "."
    if "." is in the filename then set fname to text items 1 thru -2 of the filename as text
    

    然后您应该注意或在之后重置 text item delimiters,否则稍后当您尝试将字符串连接在一起时会产生后果。

    另一种不使用 text item delimiters 截断扩展名的方法是字符串扫描,您可以在其中遍历字符串中的字符,边执行操作或测试边进行操作,并获得所需的结果。它比听起来更快,并且是一种用于非常复杂的字符串搜索和操作的强大技术:

    set filename to the name of afile
    set fname to the filename
    
    repeat while the last character of fname ≠ "."
        set fname to text 1 thru -2 of fname
    end
    
    set fname to text 1 thru -2 of fname
    

    您还可以检索文件的 name extension 属性,获取其长度,并从文件名末尾删除 (1 + that) 个字符。有无数种方法可以达到相同的结果。

  4. 在此特定实例中这是错误的:

    set myKeywords to ((characters var1 thru var2 of myvar) as string)
    

    characters 生成 list,然后您必须将其连接回 string,如果您不确定 text item delimiters 是什么,这是不安全的被设置为。因为您没有在脚本中引用它,所以它 应该 设置为空字符串,这将导致将字符连接回单词产生预期的结果。然而,情况很可能并非如此,例如,如果您执行了第一种文件扩展名阉割技术而忽略了将 text item limiters 设置回去——那么生成的字符串将在每个字母之间有一个句点。

    作为 AppleScript 中的一项政策(您可以个人选择遵守或忽略),如果您先执行列表到字符串的强制操作 而不先 ,它会被一些人认为是糟糕的形式将 text item delimiters 设置为确定值。

    但是你不需要在这里这样做,因为不用 characters,而是用text:

    set myKeywords to text var1 thru var2 of myvar
    
  5. 你正在执行一个看起来像这样的 shell 命令:mdls -name kMDItemKeywords <file>,然后后面的两行 AppleScript 笨​​拙地 try and trim off bash 数组的文本表示前后的括号。相反,您可以为 mdls 打开 -raw 标志,它通过为您剥离密钥名称来简化输出。然后将括号作为第一个和最后一个字符;但是,由于输出中也有大量空白,您不妨让 bash 为您执行所有清理工作:

    mdls -raw -name kMDItemContentTypeTree <file> | grep -E -io '[^()",[:blank:]]+'
    

    这忽略了括号、双引号、逗号和空格,因此您得到的只是一个关键字列表,每行一个,没有任何额外的负担。如果您需要逐项列出它们,您可以将变量设置为 the paragraphs of do shell script 命令的输出,该命令将文本分成几行,将每个关键字放入一个列表中。但是这里似乎您需要文本并且不介意它是多线性的。


当我开始写这个答案时,我对导致您来到这里的具体问题的原因一无所知。在详细了解 mdls 如何格式化其输出后,我现在看到问题在于 myKeywords 字符串将包含一堆双引号,并且您已经包围了myKeywords 实体在您的 JavaScript 表达式中用双引号引起来。所有这些引号仅在 AppleScript 环境中被平等地转义一次,而不是在 JavaScript 环境中,这导致每个相邻的双引号充当 open-close 对。我 运行 在 bash 中使用类似的命令来获取值数组 (kMDContentTreeType),然后按照 AppleScript 的方式处理文本,然后在中打开 JavaScript 控制台我的浏览器并将其粘贴以说明发生了什么:

任何红色的东西都包含在一个字符串中;因此,其他所有内容都被视为 JavaScript 标识符或对象(或者如果弄乱的引号也没有弄乱语法,然后导致未终止的字符串仍然期望最后一个引号与之配对.

我认为解决方案是使用连续符 "\" 来向后兼容旧版浏览器:因此您需要在每一行(最后一行除外)后附加一个反斜杠, 您需要将 JavaScript 表达式中 myKeywords 值周围的一对双引号更改为一对单引号。在较新的浏览器中,您可以放弃为每一行添加连续标记的麻烦,而是将一对外部双引号替换为一对反引号 (`):


❌'This line throws 
an EOF error in
JavaScript';


✅'This line is \
processed successfully \
in JavaScript';


✅`This line is also
processed successfully
in JavaScript`;

我试过 CJK 建议的反引号 ( ` ),但这对我不起作用。提出的主要问题是 kMDItemKeywords 返回转义字符。

Heart,
Studio,
Red,
\"RF126-10.tif\",
Tree,
\"Heart Tree\",
occasion,
Farm,
birds,
\"Red Farm Studio\",
\"all occasion\",
all

我能够使用以下方法摆脱转义字符:

新代码

set myKeywords to do shell script "echo " & quoted form of myKeywords & " | tr -d '[:cntrl:]'| tr '[:upper:]' '[:lower:]' | tr -d '\"'"


JAVASCRIPT

的更新代码
--Inputs the Keywords from the Image Metadata--
tell application "Safari"
    activate
    do JavaScript "document.getElementById('ctl00_cphMainContent_txtKeyWords').value = '" & myKeywords & "';" in current tab of window 1
end tell


结果

--> "    heart,    studio,    red,    rf126-10.tif,    tree,    heart tree,    occasion,    farm,    birds,    red farm studio,    all occasion,    all"