Журнал LinuxFormat - перейти на главную

LXF118:Greasemonkey

Материал из Linuxformat
Перейти к: навигация, поиск
Firefox Не давайте web допечь вас – Greasemonkey поможет

Содержание

Greasemonkey: Правим Сеть

Интернет – замечательная штука, но не всегда выглядит должным образом. Джульетта Кемп и Greasemonkey берутся это исправить.

Идея, лежащая в основе Greasemonkey, очень проста. Это расширение Firefox, и оно устанавливается так же, как и все остальные (найдите его с помощью меню Tools > Addons [Инструменты > Дополнения] и нажмите Install [Установить]). Однако само по себе оно ничего не делает, лишь позволяет выполнять скрипты (ваши или написанные другими пользователями), чтобы изменить внешний вид и поведение web-страниц.

Скрипты Greasemonkey – это небольшие программы, которые и делают всю работу; сам Greasemonkey только загружает их и управляет ими. Составляются они на JavaScript, но по соображениям безопасности нельзя просто написать обычный скрипт и использовать его. Нужно знать о кое-каких подводных камнях, хотя сценарии данного урока не затрагивают ни один из них.

Сразу скажу тем, кто не знаком с JavaScript, что в этой статье вы не найдете подробного описания его синтаксиса; но пусть это вас не останавливает. Приведенные примеры довольно логичны, и все объяснены.

Чтобы установить сценарий, написанный другим пользователем, откройте его страницу в Firefox и щелкните по ссылке на скрипт. Появится окно инсталлятора (как и для обычного расширения), и вы сможете просмотреть исходный код скрипта или установить его, если уверены в содержимом.

Часть 1 Мой первый скрипт Greasemonkey

LXF118 62 1.jpg Диалог создания нового скрипта во всей красе. Опишите сценарий поподробнее: это упростит вам жизнь в будущем

Чтобы максимально упростить написание скрипта, Greasemonkey предоставляет полезный диалог. Сразу после установки Greasemonkey в правом нижнем углу окна Firefox на панели инструментов появится обезьянья мордочка. Кликните на ней правой кнопкой мыши, и откроется меню, где будет пункт Новый скрипт [New User Script]. Выберите его, и появится диалог, похожий на приведенный справа.

Поле ‘name’ – это имя скрипта. Лучше выбрать имя, ясно говорящее о том, что делает сценарий – потом будет проще управлять ими. Строка ‘namespace’ (пространство имен) позволяет избежать конфликтов вашего скрипта с другими. Если вы попробуете добавить сценарий, имя которого совпадает с уже установленным, как раз пространство имен и определит, будет ли последний перезаписан (если пространства имен одинаковы) или будет существовать совместно со старым (если они разные). Здесь есть несколько вариантов: например, использовать в качестве пространства доменное имя своего web-сайта. Как альтернативу, можно взять http://localhost или, если вы собираетесь загрузить свой готовый скрипт на сайт http://userscripts.org, этот адрес. В текущей версии Greasemonkey это поле обязательно для заполнения.

Поле ‘description’ содержит описание действий скрипта. Всегда заполняйте его, даже для собственных скриптов – их может накопиться много, и если оставить информацию о том, что делает каждый сценарий, ими будет проще управлять.

Правила включения (‘include’) и исключения (‘exclude’) определяют, на каких сайтах будет выполняться скрипт, и могут содержать шаблоны. Так, www.example.com/* соответствует адресу www.example.com/ и всем страницам, начинающимся с этого адреса (тогда как www.example.com/ без звездочки соответствует только главной странице). Шаблоны могут использоваться и в доменных именах: http://*.example.com/f* соответствует всем страницам, пути к которым начинаются с f, на всех серверах домена example.com. По умолчанию поле «include» содержит адрес страницы, с которой было открыто окно создания скрипта, но его можно спокойно очистить. Если адрес страницы соответствует хотя бы одному из правил включения и не подпадает ни под одно правило исключения, то скрипт будет запущен. Если правила включения не заданы, то Greasemonkey использует @include *, что соответствует всем адресам, и скрипт будет выполняться на каждой загружаемой странице.

Скорая помощь

В правилах включения можно использовать синтаксис Magic TLD.tld, который будет соответствовать любому домену верхнего уровня (включая домены второго уровня типа .co.uk и т.д.). Например, example.tld соответствует example.com, example.co.uk, example.org и целому набору других доменов. Однако по соображениям безопасности этот синтаксис не стоит использовать, если скрипт работает с личными данными.

Наш первый скрипт сделает фон страницы белым: это спасет вас, если вы угодите на сайт, чей автор – любитель гламурно-розового или покрыл фон мозаикой из картинки, через пару секунд вызывающей ломоту в висках. Итак, выберите сайт, у которого нужно изменить цвет фона, добавьте его адрес в поле @include (здесь я использую www.example.com) и заполните другие поля подходящими значениями.

Сразу после этого будет запрошен предпочитаемый редактор (если он еще не задан), и Greasemonkey загрузит файл скрипта. Сейчас в нем содержатся только метаданные.

LXF118 63 1.jpg Документ HTML — это дерево объектов DOM: каждый дочерний узел ответвляется от родительского.

Файл выглядит примерно так:

// ==UserScript==
// @name Background Change
// @namespace http://www.example.com/~juliet/
// @description Change the background colour of a page
// @include http://www.example.com/*
// ==/UserScript==

Пора написать сам сценарий. Он лишь изменяет цвет фона всех страниц в домене include на белый. (Бывает, что цвета фона и в самом деле не смотрятся.) Для страниц без фреймов или прочих осложнений это делается всего одной строкой:

document.body.style.background = “#ffffff”;

document – это встроенный способ ссылки на текущую страницу. Это объект DOM (Document Object Model – объектная модель документа), который представляет весь HTML-документ. Представьте его себе как дерево HTML-элементов (объектов). Каждый новый элемент является «дочерним» по отношению к предыдущему (посмотрите на схему, изображающую возможную структуру тела HTML-документа).

В этой модели для ссылки на объект используется нотация главный объект.потомок.потомкпотомка. Таким образом, сначала идет элемент body, затем стиль элемента body и, наконец, атрибут background стиля элемента body. Данный атрибут устанавливается в белый цвет (#ffffff – обозначение белого цвета в шестнадцатеричной записи; это один из стандартов HTML. Можно было бы использовать и просто white)

LXF118 63 2.jpg Страница с ужасным фоном и спокойным белым фоном.

Попробуйте сценарий в деле – откройте страницу с произвольным фоном (не белым), с помощью меню Управление скриптами [Manage Scripts] добавьте ее адрес в список ‘include’ для только что созданного скрипта и обновите страницу. Помните, что меняется не сама страница, а только ее отображение: если результат вышел скверным, никто не пострадает! Скрипт можно просто отключить или отредактировать его и обновить страницу. Так что не бойтесь экспериментировать.

Greasemonkey включается и отключается щелчком левой кнопкой мыши на его значке. Можно отключить его, посмотреть, как выглядит страница, потом включить, перезагрузить страницу и увидеть, что делает скрипт.

Часть 2 Зададим стили CSS

Скорая помощь

Как было показано на схеме DOM, «дочерним» элементом HTML-элемента является тот, который в нем содержится. Представьте себе документ в виде большого дерева, каждый открывающий тэг которого (например, <p>) начинает новую ветвь, а каждый закрывающий (например, </p>) заканчивает ее. Самозакрывающиеся тэги (например, <br />) образуют ветвь, у которой не может быть дочерних. Таким образом, поиск можно ограничить внутри заданного абзаца или блока div.

Однако этот скрипт не работает с фреймами – он изменит цвет фона лишь у главного документа. Если на вашей странице с фоном «вырви глаз» есть фреймы, лучше всего одолеть их все сразу, добавив стиль CSS, который переопределит существующий. Чтобы отредактировать уже созданный файл, щелкните на обезьяньей мордочке правой кнопкой и выберите Управление скриптами. Укажите свой скрипт и нажмите на кнопку Правка [Edit], чтобы он снова появился в текстовом редакторе. Во время тестирования не нужно закрывать редактор или диалог управления скриптами – достаточно сохранить файл и попробовать обновить страницу.

 function addCss(cssString) {
   var head = document.getElementsByTagName(‘head’)[0];
   return unless head;
   var newCss = document.createElement(‘style’);
   newCss.type = “text/css”;
   newCss.innerHTML = cssString;
   head.appendChild(newCss);
 }
 addCss (* { background-color: #ffffff ! important; });

Первая функция (addCss) задает способ добавления глобальной таблицы стилей CSS. document опять-таки ссылается на текущую страницу, но в этом примере мы используем функцию getElementsByTagName («получить элементы по имени тэга» – именно это она и делает) для выбора первого элемента head. Для тех, кто совсем не знаком с CSS: стили задаются [в том числе] в секции head HTML-файла, и нам нужно добыть этот элемент, чтобы он стал родительским для нового элемента CSS. Здесь есть строка, которая отлавливает ошибочную ситуацию, когда секции head нет (производится возврат из функции без каких-либо действий), затем скрипт создает элемент style и устанавливает его атрибут type в text/css. В строке

newCss.innerHTML = cssString

функция принимает то, что ей передано, и вставляет это в элемент style. Затем полностью созданный элемент style добавляется к элементу head – вот и все.

В последних строках происходит вызов функции с аргументом, устанавливающим цвет фона – там, где строка cssString. Обратите внимание на то, что мы используем скобки (), потому что вызываем функцию, а не определяем ее. Флаг ! important гарантирует, что ваши CSS-стили переопределят указанные на странице.

Фактически этот код добавляет в заголовок HTML-страницы следующие строки:

<style type=”text/css”>
  * {background-color: #ffffff ! important;}
</style>

Точно так же можно задать собственные стили CSS для любого элемента страницы – просто задайте подходящую CSS-строку, которая будет передана функции addCss. Например, вызов

  addCss (* { background-color: #ffffff ! important;
      text-align: justify ! important;
      color: black ! important; });

установит цвет фона в белый, весь текст сделает черным и выровняет его по ширине.

Часть 3 Изменим заданные элементы

Итак, мы научились менять стиль одного элемента, переделав объект DOM, или множество стилей, добавляя собственные CSS-записи, и можем применить это к заданным сайтам с помощью правил включения/исключения Greasemonkey. А если нам нужно найти элементы определенного типа, встречающиеся на странице несколько раз, и изменить их?

Например, у вас есть форум, пользователи которого иногда используют малоприятные аватары, и вы хотите просто заменить их все на безопасную картинку из вашего собственного web-пространства. Прежде всего, найдем все картинки на странице:

 var allImgs,thisImg;
 allImgs = document.evaluate(//img[@src]’,
  document,
  null,
  XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

Полезен здесь метод document.evaluate. Его освоение дает огромные возможности. Первый параметр (’//img[@src]’) представляет собой XPath-запрос (подробнее об этом – чуть ниже); второй – область поиска. В данном случае это весь документ, но в дальнейшем ее можно ограничить только дочерними элементами. Третий параметр – функция разрешения пространства имен, которая имеет смысл только для документов типа application/xhtml+xml.

Четвертый параметр задает способ возвращения результатов. Вариант, указанный здесь, соответствует произвольному порядку, что чаще всего и нужно. Если результаты требуется вернуть в порядке их появления на странице, используйте вместо него XPathResult.ORDERED_NODE_SNAPSHOT_TYPE. Последний параметр позволяет объединить результаты запроса – передайте туда результат предыдущего вызова document.evaluate, и получите их назад вместе. Поэкспериментируйте с этим!

Запрос XPath (первый параметр) – «мотор» этой функции. XPath – мощный язык запросов для XML-документов, встроенный в Firefox [и не только, – прим. ред.], и его можно использовать в Greasemonkey. Если вы ищете определенный набор элементов, можно просто пройтись по дереву DOM, выудить наборы узлов и найти в них искомое. Но это довольно медленно и не очень красиво с точки зрения кода. XPath позволяет найти на странице все, что нужно, гораздо быстрее и элегантнее. Я воспользуюсь им в нескольких скриптах, и, надеюсь, это поможет вам понять, как он работает – если хотите узнать о нем подробнее, поищите спецификацию или онлайн-учебники в Интернете. Язык в самом деле очень гибок: если вы можете определить набор результатов, который хотите получить из HTML-документа, то сможете и написать XPath-запрос, который позволит их получить.

Вернемся к нашему скрипту: картинки мы добыли, и хотим с ними что-то сделать. Вот следующий фрагмент кода: допишите его сразу после приведенного выше:

 for (var i=0;i<allImgs.snapshotLength;i++) {
     var thisImg = allImgs.snapshotItem(i);
     var src = thisImg.src;
     var srcMatch = src.match(^http://www.example.com/forums/userpic/’);
     if (srcMatch != null) {
         thisImg.src = ‘http://www.example.com/~juliet/safepic.gif’;
     }
 }

snapshotLength и snapshotItem — методы, работающие с результатом вызова document.evaluate и возвращающие соответственно общее число результатов и заданный результат по его номеру. Вставьте оба в цикл for, как в приведенном примере, и обработайте каждый элемент (здесь – каждое изображение со страницы) результата запроса XPath.

Небольшое замечание: в обычном JavaScript пройтись по коллекции объектов можно так:

 for (var thisImg in allImgs) {
     // do stuff
 }
Скорая помощь

Первоначально в Greasemonkey было несколько серьезных дыр в безопасности, вызванных способом внедрения пользовательских скриптов непосредственно в web-страницы: так ваши сценарии оказывались доступны для сайтов страниц злоумышленников. Ныне Greasemonkey работает по-другому, на самом деле выполняя скрипты в «песочнице» и используя обертки для доступа к объектам на удаленной web-странице, которую хотят изменить ваши скрипты.

Из-за особенностей реализации безопасности в скриптах Greasemonkey такой способ работать не будет. Приходится идти окружным путем.

thisImg.src дает нам значение атрибута src изображения. Так, для тэга <img src=«foo.jpg»>, thisImg.src вернет foo.jpg. (Точно так же можно получить значение атрибутов width или height или любых других атрибутов тэга img. Полный список элементов и атрибутов объекта DOM можно найти в Интернете.)

В конце мы пытаемся сравнить src с ожидаемым значением для пользовательских аватар на этом форуме (чтобы узнать его, взгляните на исходный код страницы форума), и если результат не равен нулю (соответствие есть), значение атрибута src заменяется путем к безопасной картинке. (Можно было бы обойтись без лишней строки, вызвав src.match, но приведенный вариант более понятен.) Готово!

Часть 4 Замена текста

Теперь попробуем заменить текст, который встречается на странице в нескольких местах. Предположим, вас достало слово «аутсорсинг» [outsourcing], тут и там маячащее на главной странице сайта вашей компании, куда вам, к сожалению, приходится заходить регулярно. Заменим его словом «левак» [otherguy] (или любым другим, которое вы находите юморным, а не нудным).

 // ==UserScript==
 // @name Deoutsourcing
 // @namespace http://www.example.com/~juliet/
 // @description Replace “outsourcing” on corporate homepage
 // @include http://www.example.net/corporatehome
 // ==/UserScript==
 textNodes = document.evaluate(//text()”,
    document,
    null,
    XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
    null);
 var searchRE = new RegExp(‘outsourcing’,’gi’);
 var replace = ‘otherguy’;
 for (var i=0;i<textNodes.snapshotLength;i++) {
    var node = textNodes.snapshotItem(i);
    node.data = node.data.replace(searchRE, replace);
 }

Первый фрагмент кода мы уже видели в предыдущем скрипте. Он ищет в документе все текстовые узлы. Далее мы задаем регулярное выражение. Конструктор new RegExp() принимает два аргумента. Первый – это искомая строка, второй – модификаторы. g означает глобальное соответствие: заменяются все вхождения строки, а не только первое. (Чаще всего вам это и нужно.) i означает сравнение без учета регистра.

Есть и модификатор m для многострочного режима, в котором якоря ^ и $ (означающие начало и конец строки, соответственно) совпадают с позициями перед и после перевода строки, а не только с началом и концом текста.

Наконец, очередной цикл for проходит по результату запроса XPath, находя нашу строку и заменяя ее другой. Легко!

Greasemonkey способен на гораздо большее – просто поэкспериментируйте и увидите, что получится. Подстройте Интернет под себя! LXF

Радости отладки

В идеальном мире все, что бы вы ни написали, сразу заработает так, как задумано. Удачи!

Тем, у кого сразу не получилось, помогут некоторые средства отладки:

  1. DOM Inspector и InspectThis – доступны как дополнения к Firefox 3. Инспектор DOM (после установки его можно запустить из меню Tools [Инструменты]) позволяет взглянуть на объектную модель документа страницы – то есть ее структуру. InspectThis поможет вам исследовать отдельный элемент по щелчку на нем правой кнопкой мыши и выбору пункта “Inspect Element” [Инспектировать элемент] контекстного меню. Оба помогут получить информацию об именах и идентификаторах элементов страницы, которые вы ищете. Инспектор DOM поставляет и другую информацию, например, стили CSS и данные о JavaScript
  2. Консоль ошибок (Меню Tools в Firefox). На ней показываются все ошибки в скриптах с того момента, как вы открыли Firefox. Чтобы избавиться от них, нажмите кнопку Clear, затем обновите страницу со своим скриптом. Если он упадет, вы получите сообщение об ошибке. (Номер строки в голову не берите – из-за способа внедрения пользовательских сценариев в страницу он не будет соответствовать реальному. Разбирайтесь только с сообщением об ошибке.)
  3. Ведение журнала ошибок с помощью функции Greasemonkey GM_log. Сообщения будут появляться в консоли ошибок.

Радости прибавилось бы значительно, если бы можно было увидеть пример скрипта, который не просто добавлял бы комфорта в просмотре страниц, а выполнял бы какие то функциональные задачи, например: Сканировал последовательно html документ, натыкаясь на урл, открывал бы его страницу и ждал нажатия какой либо кнопки, приказывающей закрыть страницу и двинуться в поиске следующего урла в html документе

Персональные инструменты
купить
подписаться
Яндекс.Метрика