问题描述
我需要使用JXA以编程方式从iTunes下载应用程序.我已完成以下操作:
I need to programatically download an app from iTunes using JXA. I've done the following:
var its = SystemEvents.processes.byName('iTunes');
delay(3);
its.windows[0].buttons.byName('Get').click();
未选择任何元素.我尝试单击按钮[0 ... 7],但这些都不是获取"按钮.我假设我需要的按钮在文档中,但是JXA文档清楚地指出按钮元素是Window的子级,而不是Document的子级.关于如何点击相应按钮的任何想法?
There is no element selected. I've tried clicking on buttons[0...7] and none of those are the 'Get' button. I assume the button I need is inside a document, biut the JXA documentation clearly states that button elements are children of Window, not of Document. Any ideas on how to click on the corrent button?
推荐答案
叶子" UI元素(例如按钮)将位于可能复杂的UI元素层次结构的底部对于iTunes尤其如此.
A "leaf" UI element such as a button will be at the bottom of a potentially complex hierarchy of UI elements, which is especially true in the case of iTunes.
为使您有所了解,下面是免费应用程序应用程序商店"页面上的 Get
按钮的示例对象说明符(假设您已经确保此页面处于活动状态):
To give you a sense, here's an example object specifier for the Get
button on a free app's App Store page (assuming you've already ensured that this page is active):
Application("System Events")
.applicationProcesses.byName("iTunes")
.windows.byName("iTunes")
.splitterGroups.at(0)
.scrollAreas.at(0)
.uiElements.at(0)
.groups.at(3)
.buttons.at(0)
问题在于该对象说明符在页面之间有所不同,因此理想情况下,您只需将 filter 应用于所有 UI元素(通过窗口的 entireContents
属性)以检索感兴趣的按钮:
The problem is that this object specifier differs across pages, so ideally you'd just apply a filter to all UI elements (via the window's entireContents
property) to retrieve the button of interest:
// Get an array of all UI elements in iTunes window.
uiElems = Application("System Events").applicationProcesses['iTunes']
.windows[0].entireContents()
// Find all buttons whose description contains 'Get'.
btns = uiElems.filter(function(el) {
try {
return el.role() == 'AXButton'
&&
el.description().match(/\bGet\b/)
} catch (e) {}
})
// Click on the 1st button found.
btns[0].click()
这很重要:在我最近购买的机器上,这大约需要20秒(!).
Here's the catch: on my reasonably recent machine, this takes about 20 seconds(!).
我想像一下,一个 .whoose
样式的过滤器会更快,但是在这种情况下我无法使它工作,因为必须捕获异常-如上所述-但是.whose
似乎不支持嵌入式异常处理程序.
I would image that a .whose
-style filter would be faster, but I couldn't get it to work in this instance, because exceptions must be caught - as above - but .whose
does not seem to support embedded exception handlers.
如果您愿意对可以在其子树中找到按钮的层次结构中的较低级别做出假设,则可以大大加快操作速度:
If you're willing to make assumptions about a lower level in the hierarchy in whose subtree the button can be found, you can speed things up considerably:
// Get the group UI elements in one of which the 'Get' button is located.
grps = Application("System Events").applicationProcesses['iTunes'].
windows[0].splitterGroups[0].scrollAreas[0].uiElements[0].groups
// Loop over groups
count = grps.length
for (i = 0; i < count; ++i) {
// In the group at hand, find all buttons whose description contains 'Get'.
btns = grps[i].entireContents().filter(function(el) {
try {
return el.role() == 'AXButton'
&&
el.description().match(/\bGet\b/)
} catch (e) {}
})
// Exit loop, if a 'Get' button was found.
if (btns.length > 0) break
}
if (btns.length == 0) {
console.log('ERROR: No "Get" button found.')
} else {
// Click on the 1st button found.
btns[0].click()
}
运行时间不到1秒.在我的机器上.
This runs in less than 1 sec. on my machine.
不幸的是,UI自动化(GUI脚本)是一项棘手的事情.
UI automation (GUI scripting) is tricky business, unfortunately.
对于交互式探索,Xcode附带了一个 Accessibility Inspector 开发人员工具,但是使用它并非易事,尤其是在将发现结果转换为代码时.
For interactive exploration, there's the Accessibility Inspector developer tool that comes with Xcode, but using it is non-trivial, especially when it comes to translating findings into code.
这篇关于JavaScript自动化单击iTunes中的下载按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!