applescript 中的文本格式问题

Problem with text formating in applescript

我一直在尝试解决从网站中提取文本并对其进行过滤以获取所需信息的问题。我已经到了从如下所示的网站创建 TextEdit 文件的地步:

7:00
Name of Meeting: Location Bad
Address
Area
8:00
Name of Meeting: Location Good
Address
Area
Noon
Name of Meeting: Location Good 2
Address
Area
3:00 pm
Name of Meeting: Location Bad 2
Area

我的目标是提取特定位置(位置良好和位置良好 2)的所有会议。理想情况下只过滤这些信息 --> Time @ Location Good, Time @ Location Good 2.

我不知道如何设置文本格式才能完成此操作。我试过过滤它,但由于信息都在不同的行上分开,过滤器返回只是我正在过滤的关键字(使用 Automator)。为了解决这个问题,我只是手动完成它并设置一个 applescript 向我发送一条包含我已经 hand-filtered 的信息的短信。这暂时有效,但当网站上的信息发生变化时,我的信息将过时。

这是网站: https://loukyaa.org/meetings/?tsml-day=6&tsml-region=louisville

问题是:如何操作文本以过滤我想要的信息?我有兴趣过滤 "Icehouse" 和 "Token 3 Club." 的所有会议 谢谢!

由于您的问题中提供的信息不完整,让我为 SafariGoogle Chrome[= 提供一个解决方案119=] 在 new window 中打开 target URL , 使用 JavaScript 获取 内文 table 会议,关闭window,过滤成Time @ Location的形式,例如7:00 am @ Token 3 Club 包含会议 timelocation for IcehouseToken 3 Club.

使用JavaScript,在这个用例中,returns制表符分隔文本的段落 variable foo 将在 do shell script command 中使用 awk 进行过滤,最终输出为存储在名为 bar 变量 中,然后您可以随心所欲

以下示例 AppleScript 代码 用于Safari:

set theURL to "https://loukyaa.org/meetings/?tsml-day=6&tsml-region=louisville"

tell application "Safari" to make new document with properties {URL:theURL}

tell application "System Events"
    repeat until exists ¬
        (buttons of UI elements of groups of toolbar 1 of window 1 of ¬
            application process "Safari" whose name = "Reload this page")
        delay 0.5
    end repeat
end tell

tell application "Safari"
    set foo to do JavaScript ¬
        "document.getElementById('meetings_tbody').innerText;" in document 1
    close its front window
end tell

set awkCommand to ¬
    "awk 'BEGIN{FS=\"\t\"; OFS=\" @ \"}/Icehouse|Token 3 Club/{print ,}'"

set bar to do shell script awkCommand & " <<< " & foo's quoted form
  • 注意:代码已在macOS High Sierra下测试, 但是,对于 macOS Mojave 及更高版本,从 repeat until exists ¬ ... 代码中删除 words buttons of .

  • 注意: do JavaScript 仅适用 if 允许 JavaScript 来自 Apple EventsSafari > Develop 菜单上选中,该菜单默认隐藏,可以通过选中 [√] 在菜单栏 中显示开发菜单:Safari > 首选项… > 高级


以下示例 AppleScript code 用于Google Chrome:

set theURL to "https://loukyaa.org/meetings/?tsml-day=6&tsml-region=louisville"

tell application "Google Chrome"
    set URL of active tab of (make new window) to theURL
    repeat until (loading of tab 1 of window 1 is false)
        delay 0.5
    end repeat
    tell active tab of front window to set foo to ¬
        execute javascript ¬
            "document.getElementById('meetings_tbody').innerText;"
    close its front window
end tell

set awkCommand to ¬
    "awk 'BEGIN{FS=\"\t\"; OFS=\" @ \"}/Icehouse|Token 3 Club/{print ,}'"

set bar to do shell script awkCommand & " <<< " & foo's quoted form

注意:默认情况下这应该有效,因为GoogleChrome 允许执行 JavaScript.


在任何一种情况下,变量 bar 包含例如:

7:00 am @ Token 3 Club
8:00 am @ Token 3 Club
8:30 am @ Icehouse
8:30 am @ Icehouse
10:30 am @ Icehouse
2:00 pm @ Token 3 Club
4:00 pm @ Token 3 Club
6:00 pm @ Icehouse
6:00 pm @ Icehouse
6:00 pm @ Token 3 Club
8:00 pm @ Icehouse
8:00 pm @ Token 3 Club
10:30 pm @ Token 3 Club

然后您就可以随心所欲地使用它了。

还要注意 awk commandFS=\"\t\"; 部分将扩展为正常的 tab 字符在例如 Script Editor 中编译。在本站发布代码时必须使用\t,否则会显示为,例如FS=\" \";,然后复制 code 它不会是一个正常的 tab 字符一旦编译。


注意:示例 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,适当设置延迟

@user3439894 的回答非常好,他向您展示了一些用于确定网页是否已加载的好用、可靠的技术;一些初级 JavaScript;以及 awk.

的力量

我决定换一种方式。我使用 JavaScript 来完成所有繁重的处理,主要是因为我的最终目标是获得 record 对象的列表,每个对象代表网页上列出的单个事件,我从中提取名称、位置和每个事件的时间。

tell application id "com.apple.Safari" to tell ¬
    document 1 to set allEvents to do JavaScript ¬
    "Array.from(document
               .querySelectorAll('tbody#meetings_tbody '+
                                'tr '+
                                'td.name,'+
                                'td.time,'+
                                'td.location'))
               .reduce((ξ,x,i,L) => { 
                        ξ=Array.from(ξ);
                        i%3==1 && ξ.push({
                                'name': L[i].innerText,
                                'time': L[i-1].innerText,
                                'location': L[i+1].innerText
                        }); 
                        return ξ;
               });"

变量 allEvents 应该包含如下内容:

{{|name|:"Saturday @ 7", |time|:"7:00 am", location:"Token 3 Club"},
 {|name|:"Early Bird Meeting", |time|:"8:00 am", location:"Token 3 Club"},
 {|name|:"Saturday Morning Meditation Group", |time|:"8:30 am", location:"Christ Church United Methodist"},
 {|name|:"Saturday Morning Gratitude Group", |time|:"8:30 am", location:"Icehouse"},
 ...,
 {|name|:"Agape", |time|:"10:30 pm", location:"Token 3 Club"}}

我不确定您对 AppleScript listrecord 对象的熟悉程度。如果仔细检查内容,您会发现每个事件都由一个如下所示的对象表示:

{|name|:"...", |time|:"...", location:"..."}

也就是一个record,里面包含三个properties|name||time|,以及 location。每个 property 都有一个值,您可以通过引用 <property> of <record> 来检索该值。因此,如果创建一个记录对象并将其分配给一个变量:

set R to {a:1, b:"two", c:pi}

然后:

set myvar to b of R

将检索属于记录 R 的 属性 b 的值并将其存储在变量 myvar 中。所以 myvar 现在将计算为 "two".

allEvents 不仅仅是一个 record 对象;这是很多。这是其中 list 个。这是一个列表示例:

set L to {1, "two", pi, 2^2, "5.0"}

包含属性;它只包含值,这些值被称为 itemslist 是严格遵守顺序的,而 record 则不是。因此,值 "two" 始终 显示为该列表中的第二个 item,但在记录中,它可以出现在开头、中间或结尾, 但将始终附加到 属性 b。从列表中检索项目:

set myvar to item 2 of L

因此,如果您想要该列表中第 4 个事件的位置,请稍微跳到最后:

return the location of item 4 in allEvents --> "Icehouse"

您仍然需要遵循@user3439894 的示例,并实施测试以确定页面何时加载(除非您打算仅在自己加载页面后手动触发脚本)。 @user3439894 还向您展示了如何使代码适应基于 Chromium 的浏览器(Google Chrome、Vivaldi、Brave)。