У меня есть следующий код, который должен работать. Я просто пытаюсь получить все элементы «img» со страницы в список в AS, чтобы я мог работать с этим списком.
tell application "Safari"
set theWindow to front window
set theTab to current tab of theWindow
set theURL to URL of theTab
set asImages to (do JavaScript "theSearch = document.getElementsByTagName(\"img\");
theImages = [].slice.call(theSearch);
theImages" in theTab)
end tell
Если я войду в
theSearch = document.getElementsByTagName("img");
theImages = [].slice.call(theSearch);
theImages
в консоль в сафари работает. Но когда я запускаю тот же код, что и выше, из команды «do javascript» в Safari, я вообще ничего не получаю, переменная asImages вообще не создается. Я перепробовал все, что мог придумать, но безрезультатно. Я надеюсь, что кто-то со свежим взглядом сможет довольно быстро заметить, что я делаю неправильно. ТИА
И простите меня, вы можете игнорировать мой первый пункт, так как я только что заметил, что вы вызываете slice на HTMLCollection, так что у вас уже есть массив. Так что это только второй вопрос, который стоит.
@CJK, к чему я хотел бы вернуться в AppleScript, так это ко всем элементам коллекции HTML в виде списка строк. Это отвечает на ваш вопрос? Как только строки будут в AS, я буду искать в них определенные биты информации. Я понимаю, что это может быть проще сделать непосредственно в JS, но я просто чувствую себя более комфортно в AS. Спасибо!
Извините за мой медленный ответ. Понятно, что вы больше привыкли к AS, чем к JS. Поскольку AS физически не может обрабатывать определенные типы данных, возвращаемые JS, есть минимум, который должен быть в JS, прежде чем отправлять его в AS. До сих пор не ясно, какую информацию вам нужно, чтобы список содержал, поскольку вы просто сказали «список строк» — это атрибут src элементов img (т. е. "https://...") или буквальный HTML, который определяет каждый элемент img (т. е. ) ? Я расскажу об обеих ситуациях в кратком ответе ниже, так как это будет проще, чем комментировать.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


TL;DR:To jump straight to the solution, scroll down to the section marked "ADDENDUM" at the bottom.
Подводя итог тому, что обсуждалось в комментариях:
getElementsByTagName() возвращает объект HTMLCollection, который похож на массив, но это не массив. AppleScript не будет знать, что это такое и что с ним делать. Вы уже позаботились об этом, преобразовав его в массив, используя довольно старый метод:
theSearch = document.getElementsByTagName("img"); theImages = [].slice.call(theSearch);
Однако каждый элемент массива представляет собой объект Node, представляющий элемент в HTML DOM. Опять же, это тип данных, полностью чуждый AppleScript, поэтому нам нужно преобразовать каждый элемент списка во что-то более подходящее.
Вы заявили, что вам нужен список строк. Это может означать список атрибутов src для каждого элемента img, который будет списком URL-адресов (например, "https://..."), или может быть вам нужен буквальный HTML, который определяет каждый элемент img (например, <img src = "...">)? Я рассмотрю обе ситуации ниже.
Я собираюсь использовать другой метод для преобразования HTMLCollection в стандартный массив JavaScript, а именно Array.from(). Для этого требуется как минимум один аргумент — объект, который вы хотите преобразовать в массив, — и необязательный второй аргумент, представляющий собой функцию обратного вызова, которая применяется к каждому элементу результирующего массива. В нашем случае это очень удобно, так как мы можем определить эту функцию так, чтобы она преобразовывала для нас элементы Node в строки.
Чтобы получить список атрибутов src:
Array.from( document.getElementsByTagName('img'),
img => img.src );
Запуск на этой странице возвращает:
['data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAvAA...',
'https://cdn.sstatic.net/Img/teams/teams-illo-free-...',
'https://www.gravatar.com/avatar/6ecd4d9aedf87d99e7...',
'https://www.gravatar.com/avatar/6ecd4d9aedf87d99e7...',
'https://graph.facebook.com/1261291368/picture?type...',
'https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAA...']
Я обрезал значения для облегчения чтения, но возвращаемые значения являются полными URL-адресами.
Чтобы получить список объявлений HTML <img>:
Array.from( document.getElementsByTagName('img'),
img => img.outerHTML );
который возвращает:
['<img src = "data:image/png;base64,iVBORw0KGgoAAAANSU...',
'<img class = "wmx100 mx-auto my8 h-auto d-block" wid...',
'<img src = "https://www.gravatar.com/avatar/6ecd4d9a...',
'<img src = "https://www.gravatar.com/avatar/6ecd4d9a...',
'<img src = "https://graph.facebook.com/1261291368/pi...',
'<img src = "https://lh3.googleusercontent.com/-XdUIq...']
Опять же, возвращаемые значения заполнены. В качестве примера, вот последний элемент в массиве полностью, отформатированный в две строки для удобочитаемости:
'<img src = "https://lh3.googleusercontent.com/-XdUIq…er avatar"
width = "32" height = "32" class = "bar-sm">'
Используя второй случай сверху, это можно реализовать в AppleScript в одной строке:
tell application id "com.apple.Safari" to tell document 1 ¬
to set images to do JavaScript "Array.from( document
.getElementsByTagName(
'img', i=>i.outerHTML)
);"
Операторы JavaScript могут быть разделены на несколько строк по своей природе, и они всегда должны заканчиваться точкой с запятой. Я также использовал другой идентификатор в коде JS для функции обратного вызова, а именно "i", просто чтобы продемонстрировать, что используемый идентификатор не имеет значения.
В macOS 12.6 (Монтерей) с использованием Safari 16.0 (17614.1.25.9.10, 17614) метод Array.from() не применяет функцию обратного вызова к массиву, а просто возвращает список объектов JS класса HTMLImageElement, что не будет жизнеспособным. к AppleScript.
Я проверил, чтобы убедиться, что виноват Safari, а не я, и, похоже, это так.
Аргумент обратного вызова Array.from() на самом деле является просто синтаксическим сахаром для вызова метода Array.map() для массива, что мы можем сделать сами довольно легко, так что вместо этого:
Array.from(document.getElementsByTagName('img'),
img => img.outerHTML);
мы делаем это:
Array.from(document.getElementsByTagName('img')
).map(img => img.outerHTML);
который работает в моей версии Safari. Вот AppleScript:
tell application id ("com.apple.Safari") ¬
to tell the front document to if ¬
it exists then set images to the ¬
do JavaScript "Array.from(document
.getElementsByTagName('img')).map(
i => i.outerHTML);"
который при запуске на домашней странице StackExchange возвращает для меня:
{"<img src=\"/Content/Img/hero/close.png\" alt=\"close\">", ¬
"<img src=\"/Content/Img/hero/bubble.png\" alt=\"Speech bubbles\">", ¬
"<img src=\"/Content/Img/hero/vote.png\" alt=\"Voting arrows\">", ¬
"<img src=\"/Content/Img/hero/check.png\" alt=\"checkmark\">", ¬
"<img src=\"https://...\" alt=\"Mathematics Stack Exchange\">", ¬
"<img src=\"https://...\" alt=\"Code Golf Stack Exchange\">", ¬
"<img src=\"https://...\" alt=\"Retrocomputing Stack Exchange\">", ¬
"<img src=\"https://...\" alt=\"Politics Stack Exchange\">", ¬
"<img src=\"https://...\" alt=\"Mathematica Stack Exchange\">", ...}
Замените ".outerHTML" на ".src", чтобы получить список URL-адресов изображений.
Две проблемы:
getElementsByTagName()возвращает объектHTMLCollection, который похож на массив, но это не массив. Так что AppleScript не будет иметь ни малейшего представления, что с ним делать. Теперь вы можете сделать из него массив, выполнив что-то вродеArray.from( document.getElementsByTagName('img') );, но каждый элемент массива являетсяNodeобъектом, представляющим элемент в HTML DOM. Так что, опять же, AppleScript сделает это жестко. Вы должны предоставить ему данные, которые он может обработать. Итак, вопрос: каким образом вы хотите работать над списком?