Пользователь
0,0
рейтинг
28 сентября 2011 в 16:18

Разработка → Учимся писать userscript'ы из песочницы tutorial

Доброго времени суток всем желающим приобщиться к миру пользовательских скриптов (они же userscript, userJS, юзерскрипты).

В этой статье я хочу поведать о том, что такое юзерскрипты, c чем их едят и, главное, как их готовят!

Внимание: предполагается минимальное знание javascript.
На практике доказано: юзерскрипты может писать человек, не знакомый с программированием, но обладающий усидчивостью и желанием изучить javascript!
О том, что такое javascript и как с ним обращаться, можно узнать на javascript.ru.


Что такое юзерскрипты?


Кратко: юзерскрипт — это программа, написанная на языке JavaScript, хранящаяся на компьютере пользователя и подключаемая браузером на определенных страницах. Юзерскрипт представляет собой файл с расширением .user.js (именно по расширению браузеры понимают, что файл является юзерскриптом), содержащий метаданные и непосредственно javascript-код.

При подключении к странице юзерскрипт выполняется так же, как и обычные javascript-сценарии.
У юзерскрипта есть доступ к DOM-дереву страницы, в контексте которой он выполняется.
В современных браузерах у юзерскрипта есть доступ к localStorage и прочим HTML5 API.

Юзерскрипты поддерживаются всеми основными современными браузерами (и даже кое-как поддерживаются IE7 и выше).

Самый известный портал юзерскриптов — userscripts.org. Тут можно найти хранилище скриптов, инструменты управления своими скриптами на портале и, что не маловажно, отзывчивый форум (всё на английском).

Немного общей теории


Самыми распространенными являются скрипты под расширение GreaseMonkey для браузера Firefox.
Подробную информацию по GreaseMonkey и написанию юзерскриптов под GreaseMonkey можно узнать на http://wiki.greasespot.net.
Так сложилось исторически, что данный браузер был (и остаётся по сей день) первым, в котором поддержка юзерскриптов была выполнена на высоком уровне.

Не все скрипты, написанные для GreaseMonkey, могут запускаться в других браузерах. Причина в криворукости том, что во многих скриптах используется GM API — набор javascript-функций, специфичных для GreaseMonkey.

Однако, проще всего писать юзерскрипты под браузер Google Chrome.
На это есть ряд причин:
  1. Простым скриптам не нужна поддержка GM API (библиотека, доступная в GreaseMonkey)
  2. Google Chrome, в отличие от Firefox+GreaseMonkey, имеет отличнейший дебаггер.
  3. Сообщения об ошибках юзерскрипта в Firefox ужасны! Если вы не обладаете даром телепатиитвердыми знаниями GreaseMonkey и javascript, написание юзерскрипта может превратится в муки!
  4. Google Chrome не требует расширений для поддержки юзерскриптов. Интерфейс для удаления/отключения юзерскриптов доступен «из коробки».

Очевидные минусы Google Chrome:
  1. Нет доступа к «родному» window.
  2. Не поддерживается директива @ include метаданных. Директива @ match глючит, можно сказать, что она тоже не поддерживается.

Особенности юзерскриптов


Код юзерскриптов может посмотреть любой желающий, вооруженный блокнотом.
Базовые знания javascript позволяют отсечь угрозу установки шпионских и вредоносных скриптов простым анализом кода скрипта (придётся задействовать мозг).

Важно:Если вы не доверяете автору скрипта, главное удостовериться, что скрипт не отсылает пользовательские данные (куки, вводимый текст) на сторонние сервисы!

Все юзерскрипты запускаются после того, как загрузились все основные элементы страницы, но ещё не загрузились картинки. Можно сказать, что юзерскрипты грузятся по событию DOMContentLoaded.
В любом случае, проверки на window.onload не нужны.

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

Анатомия юзерскриптов


Юзерскрипт — это текстовый файл с расширением user.js. В начале файла располагается блок метаданных — описание самого скрипта. После блока метаданных следует javascript-код, который и будет исполняться браузером.

Рассмотрим тестовый скрипт, который показывает alert с текстом на определенной странице.
// ==UserScript==
// @name myUserJS
// @description Мой самый первый юзерскрипт 
// @author Vasya Pupkin
// @license MIT
// @version 1.0
// @include http://userscripts.org/*
// ==/UserScript==
// [1] Оборачиваем скрипт в замыкание, для кроссбраузерности (opera, ie)
(function (window, undefined) {  // [2] нормализуем window
    var w;
    if (typeof unsafeWindow != undefined) {
        w = unsafeWindow
    } else {
        w = window;
    }
    // В юзерскрипты можно вставлять практически любые javascript-библиотеки.
    // Код библиотеки копируется прямо в юзерскрипт.
    // При подключении библиотеки нужно передать w в качестве параметра окна window
    // Пример: подключение jquery.min.js
    // (function(a,b){function ci(a) ... a.jQuery=a.$=d})(w);

    // [3] не запускаем скрипт во фреймах
    // без этого условия скрипт будет запускаться несколько раз на странице с фреймами
    if (w.self != w.top) {
        return;
    }
    // [4] дополнительная проверка наряду с @include
    if (/http:\/\/userscripts.org/.test(w.location.href)) {
        //Ниже идёт непосредственно код скрипта
        alert("Userscripts приветствует вас навязчивым окном.");
    }
})(window);


Важно: данный скрипт представляет собой оболочку для кроссбраузерных юзерскриптов. Этот же скрипт, но с английскими комментариями, можно стянуть с pastebin.com и использовать безнаказанно.

В самом начале располагается блок метаданных (в виде комментария).
// ==UserScript==
// ...
// ==/UserScript==

Этот блок состоит из директив описания юзерскрипта. Ниже в таблице представлены основные директивы и их назначение.

Важно:Все директивы, как и сам блок метаданных, могут отсутствовать.

Директива Назначение
@ name Название юзерскрипта.
Это название будет отображаться в интерфейсе управления
юзерскриптами. Если директива отсутствует, то название
юзерскрипта будет таким же, как и название файла.
@ description Описание юзерскрипта.
Это описание будет отображаться в интерфейсе управления
юзерскриптами.
@ namespace Пространство имён.
Определяет уникальность набора скриптов.
Сюда можно вписать имя домена, принадлежащего вам. Или любую другую строку.
Считайте, что это второе название скрипта. Обязательная директива для Trixie!
@ author Имя автора.
@ license Название лицензии, по которой распространяется юзерскрипт.
@ version Номер версии юзерскрипта.
К сожалению, механизма автообновления нету ни в одном браузере,
поэтому номер версии — это просто цифры, которые отображаются в интерфейсе.
@ include Директива описания url страницы,
на которой нужно запускать юзерскрипт.
Поддерживает вайлдкард *(применимо в GreaseMoneky, Opera, IE).
Для каждого отдельного url нужно использовать отдельную директиву @ include.
@ exclude Директива описания url страницы,
на которой не нужно запускать юзерскрипт.
Поддерживает вайлдкард *(применимо в GreaseMonkey, Opera, IE).
Для каждого отдельного url нужно использовать отдельную директиву @ exclude.
@ match Аналогично @ include, но с более жесткими ограничениями
(применимо в GreaseMonkey старше 0.9.8, Google Chrome).
Подробнее об ограничениях и формате директивы можно
прочитать на этой странице.
Для каждого отдельного url нужно использовать отдельную директиву @ match.


Важно: Как показала практика, полагаться на директиву @ match в юзерскриптах не стоит.
Google Chrome периодически отказывается учитывать @ match
и запускает юзерскрипты на всех страницах.
Для предотвращения такой ситуации в юзерскрипты,
которые будут запускаться не только в Firefox,
нужно добавлять код проверки адреса страницы (см. ссылку [4] в коде юзерскрипта).


Важно: При отсутствии директив @ include или @ match, юзерскрипты будут запускаться на всех страницах.

В нашем юзерскрипте использован ряд хитростей:
  1. Для того, чтобы юзерскрипты имели одинаковое поведение и не загрязняли глобальную область видимости, код оборачивается в замыкание (см. [1] в коде скрипта).
  2. Для правильного подключения библиотек внутри юзерскрипта и для обхода некоторых хитрых особеннойстей GreaseMonkey, необходимо «нормализовать» ссылку на глобальную область видимости window (см. [2] в коде скрипта).
  3. Для того, чтобы юзерскрипт не запускался несколько раз на одной и той же странице, необходимо останавливать работу при запуске юзерскрипта во фреймах (см. [3] в коде скрипта).
  4. Для того, чтобы юзерскрипт запускался только на нужных нам страницах, необходимо явно проверять url страницы (см. [4] в коде скрипта).
  5. Благодаря такой структуре, юзерскрипт может быть относительно просто преобразован в букмарклет.

Результат


Наш юзерскрипт готов к использованию!
Нет, серьёзно, вы можете скопировать код юзерскрипта в файл, назвать его my.user.js, и закинуть полученный файл в браузер (используйте Chrome или Firefox с установленным GreaseMonkey).

Конечно, наш юзерскрипт не обладает серьезными функциями, код выглядит страшным и малопривлекательным (для непосвященного человека). Но в итоге мы получили заготовку для кроссбраузерных юзерскриптов.
Это значит, что юзерскрипт можно запустить практически в любом современном браузере!
И это замечательно!

Остаётся вопрос: как «раздать» наш скрипт пользователям (ведь мы писали скрипт не только для себя)?
Варианты:
  • Зарегестрироваться на портале userscripts.org и загружать скрипты туда.
  • Завести репозиторий на code.google.com или github.com.
  • Создать свой простой сервис/сайт/страничку.
    Важно:Если хотите, чтобы у пользователей GreaseMonkey автоматически открывался диалог установки юзерскрипта, отдавайте файл прямиком с файловой системы (url файла должен заканчиваться на .user.js). В противном случае пользователь увидит исходный код скрипта и панель с кнопкой «установить». Эта кнопка не работает!

Рецепт для непрограммистов (похожими методами пишется ~70% скриптов):
  1. Придумываем, что будет делать наш юзерскрипт (перекрашивать ссылки, например)
  2. Берём шаблон из статьи
  3. Сохраняем в файл my.user.js
  4. Удаляем строку с alert(...).
  5. Идём на форум (userscripts.org или любой форум по javascript).
  6. Спамим, флудим и достаём людей вопросами «как перекрашивать ссылки», «дайте код» и т.д.
  7. Изменяем метаданные и проверку url страницы на нужные нам.
  8. Вставляем полученный на форуме код в юзерскрипт.
  9. Сохраняем файл.
  10. ...
  11. PROFIT!!1!

Полезные ссылки:




Список статей:
  1. » Учимся писать userscript'ы
  2. Userscripts. Углубляемся.
  3. Userscripts. Упаковываем юзерскрипт для Chrome
  4. Usersctripts. Кроссдоменные запросы


P.S. Хотелось бы увидеть блог Userscripts на хабре. Ибо не одним GreaseMonkey едины.
Алексей Мигутский @MrMig
карма
69,0
рейтинг 0,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (43)

  • +18
    > P.S. Хотелось бы увидеть блог Userscripts на хабре. Ибо не одним GreaseMonkey едины.

    надо GreaseMonkey переименовать в Userscripts, т.к. это будет правильней, ведь GM лишь дополнение для лисы, добавляющая поддержку и управление юзерскриптами, но во-первых эти скрипты работают не только в лисе, а и в других браузерах, а во-вторых — для лисы есть более хорошее дополнение Scriptish (https://addons.mozilla.org/ru/firefox/addon/scriptish/ ), который наследует все фичи GM, но имеет перед ним некоторые преимущества (за счёт удаления обратной совместимость со старыми версиями лисы, например).
    • +4
      Поддерживаю — переименовать на userscripts или Пользовательские скрипты, потому что даже в Firefox есть более быстро развивающийся клон Scriptish, а остальное описал автор — в каждом браузере есть ворох способов подключения юзерскриптов. При этом различия разработчики стремятся минимизировать.
    • 0
      Удаление само по себе — не преимущество. А какие ещё?
  • +3
    Спасибо за статью. Кстати, увидел недавно новость, что кроссбраузерный фреймворк для создания расширений Kango, о котором ранее писали на хабре, начал на днях поддерживать юзерскрипты (статья в блоге). Было бы классно увидеть больше постов на хабре по использованию этой технологии.
  • +6
    Спасибо за интересную статью. Кстати, на днях узнал, что кроссбраузерный фреймворк Kango, о котором ранее писали на хабре, начал поддерживать юзерскрипты (статья в блоге). Интересно было бы почитать и об этой технологии.
    • +2
      Да что же комментарии появляются только через 10 минут после того, как запостишь.
      • 0
        хабраэффект на хабре…
    • +2
      От юзерскрипта до расширения в некоторых случая «рукой подать».

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

      Так вот, для того, чтобы решить большую часть «продвинутых» проблем (к примеру, не доступный document.frames[i].parent) в Google Chrome, скрипт приходится упаковывать в простейшее расширение.

      Спасибо за наводку на Kango, я этот фреймворк как-то упустил. Потестирую на новых проектах.
      • 0
        arantius.com/misc/greasemonkey/script-compiler вот простой конвертатор js-скриптов в Firefox дополнения, например.
        • 0
          Спасибо, ссылка на компилятор есть в статье.

          Простой способ упаковывания юзерскриптов в расширения для хрома я обещаю осветить в следующей статье (шаблон опять одинаковый и может быть использован во всех последующих юзерскриптах).
          • 0
            упс, не заметил её в статье
  • 0
    А вообще — я вот в JS пока ни бум-бум, а вот CSS знаю достаточно хорошо, для моих целей.
    И вот иногда хочется на страничку какой-нибудь объект добавить (а это уже нельзя сделать с помощью CSS) и не знаю как. Возможно ли создать какой-то готовый юзерскрипт, исполняя который (вызвав его по хоткею, например, или через команды скрипта, о которых вы, кстати, в статье почему-то промолчали), вылезала бы штука, которая просила бы навести куда-нибудь на странице, чтобы там создать объект, а после подтверждения создания — создавался бы новый юзерскрипт, добавляющий этот объект на ту страницу.

    Т.е. не могли бы вы (или, может, кто-то другой) создать юзерскрипт для простого создания юзерскриптов?

    В моём понимании он должен работать по такому сценарию:
    1. Спросить юзера куда на странице добавить объект(ы).
    2. Спросить какой тип объекта должен быть (картинка (кликабельная ли?), таблица или блок (со смешанными данными (текст+картинки)).
    3. Создать новый юзерскрипт с соответствующим кодом.

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

    Многим юзерам просто не требуются какие-то сверхумные вещи приделывать, им обычно надо что-нибудь простенькое, типа добавить кликабельную картинку на страницу, которая будет вести на такую-то страницу (актуально для многих форумов, у которых логотип либо не является ссылкой куда-то вообще, либо ведёт на главную страницу сайта, а не в корень форума, или наоборот).
    • 0
      Если вы «не бум-бум» в JS, то самое время начать его изучать. Как показал мой небогатый опыт, человек, не знакомый с javascript и программированием (нулевой уровень), может освоить javascript и написание юзерскриптов за пол года.

      Если у вас есть знакомый javascript-порграммист (или веб-программист в общем случае), начните осаждать его вопросами (в умеренном количестве). Любой грамотный программист поможет вам советом.

      Если такого знакомого нет — начните с форумов. На userscripts.org на самом деле отзывчивый и дружелюбный к новичкам форум. Одна проблема — он на английском.
      Русскоязычных аналогов мне, к сожалению, не известно.

      Что касается «конструктора», то рецепт для «непрограммистов» есть в статье.

      Вам осталось найти адекватного программиста, который «вправит вам мозги» и направит на путь постижения javascript :)
      • 0
        Начать писать, всё же, лучше обычные скрипты, одновременно постигая, что в юзерскриптах трудно сделать, а что — нельзя. (Например, многократно упоминаемая недоступность window в Хроме, решается парой различных способов — исполнением скриптов через eval() (фактически) текста в объекте DOM или загрузкой скрипта как файла в элемент script.)
        • 0
          Согласен с вами, но частично.

          Я считаю, что на скриптах лучше учиться программисту, у которого скрипты связаны с работой.

          А на юзерскриптах лучше учиться «продвинутым» пользователям и начинающим программистам. Потому что в большинстве случаев юзерскрипты пишутся под себя и результат виден и юзабелен. А ощутимый результат — очень хороший мотиватор.
  • 0
    Я в хроме для написания скриптов и управления ими использую расширение:

    chrome.google.com/webstore/detail/dhdgffkkebhmkfjojejmpbldmpobfkfo

    Поддерживаются GM функции некоторые.
    • 0
      На самом деле это хорошая идея — использовать TamperMonkey.

      Но проблемы начинаются тогда, когда вам нужно привлекать пользователей.

      Предположим, у вас есть сайт. И на этом сайте вы активно пропогандируете некий полезнейший скрипт.
      Как показывает статистика, только 10% пользователей, посетивших вашу целевую страницу, установят скрипт.

      Проблем несколько, но самых важных, на мой взгляд, две:
      1. Пользователи не доверяют «непонятным» скриптам и программам.
      2. Пользователи не умеют устанавливать скрипты в свои браузеры.

      Если первую проблему решить в локальном масштабе довольно сложно, то вторая проблема может быть уменьшена следующими способами:
      1. Пакуем скрипт в расширение и добавляем на официальные страницы расширений. (Этот способ я лично не проверял, но отзывы слышал очень лестные.)
      2. Уменьшаем число необходимых расширений для запуска скрипта. (Этот способ даёт около +5% установок пользователями Google Chrome).

      Статистические данные анализировались на нескольких средних проектов (до 5000 пользователей юзерскриптов).
  • 0
    кстати, вот бы хотелось возможность стартовать скрипт до загрузки всего и вся, например, чтобы подменить User-Agent.
    • +2
      Такое можно делать только из расширения, да и то, далеко не во всех браузерах.
      • 0
        установи User Agent Switcher
        и подменяй на какой тебе надо
    • 0
      Обычно одним из немаловажных плюсов юзерскриптов является наличие «правильного» User-Agent.
      Это делает запросы скрипта «неотличимыми» от запросов, сделанных пользователем.

      Вообще, используя юзерскрипты удобно писать ботов для различных сайтов.
      При правильном подходе можно добиться того, что бота можно вычислить только по нечеловеческому поведению (у среднестатистического бота просматривается чёткий паттерн поведения, отличный от человеческого).
  • 0
    var w = unsafeWindow || window;
    • 0
      Возможно, я вас удивлю, но ваш способ не будет работать как минимум в Opera.
      Правильным является вариант, указанный в шаблоне.
      • 0
        Конечно удивит, потому что это не способ, а обычный синтаксис js. Почему не будет?
        • 0
          Условности окружения.

          Юзерскрипты в GreaseMonkey запускаются в песочнице, где unsafeWindow определено изначально.
          В Google Chrome юзерскрипты запускаются в замыкании, в котором есть параметр unsafeWindow, но как показала практика он не несёт особого смысла.
          В Opera переменной unsafeWindow не существует — ссылка не определена. Интерпретатор выдаст
          Undefined variable: unsafeWindow
          .

          Вы можете проверить это сами, создайте юзерскрипт со следующим содержанием и проверьте его исполнение в опера (заодно посмотрите, через какую ж как неудобно в опере устанавливать юзерскрипты):
          // ==UserScript==
          // @name SugarTest 
          // @author Me
          // @license none
          // @version 1.0
          // @include http://habrahabr.ru/
          // ==/UserScript==
          (function(window, undefined ) {
          var w = unsafeWindow || window;
           alert(w);
          })(window);


          После установки скрипта зайдите на хабр и посмотрите в консоль ошибок (Shift+Ctrl+O).
          • 0
            Oops… писал с телефона, поторопился.

            var w = window.unsafeWindow || window;
            конечно же.
            • 0
              Тут вы, конечно же, правы. Данный кусок кода будет работать.
              К тому же, его можно переписать как
              window.unsafeWindow = window.unsafeWindow || window;

              В этом случае у нас будет объект unsafeWindow, привычный разработчикам под GreaseMonkey :)

              Но я считаю, что это дело вкуса.
              • –1
                window.unsafeWindow ||= window;
                тогда уж.
                • +2
                  Вы ерунду на ходу сочиняете, путаете людей. Проверяйте свой код в консоли хотя бы.
                  • –6
                    Макароны.
                  • –3
                    Вы слишком агрессивны. Да, я ошибся, что теперь?
  • 0
    GM может отключить анимацию гифок на странице? Если может то какой функцией?
    • 0
      Насколько я знаю — не может.

      Есть скрипты, в которых гифка преобразуется в data:uri, и в ней подменяются байты, отвечающие за скорость анимации.
      Я не проверял, работает ли такой подход, и не знаю, насколько он оправдан.
    • +1
      Посмотрите эту реализацию:
      userscripts.org/scripts/review/80588
      • 0
        Оно! Подредактировав делает то что нужно — отключение анимации на указанных сайтах.
        Спасибо!
    • +1
      В ff кнопкой Esc останавливается анимация.
  • 0
    давно пишу юзерскрипты, только без ГМ.
    таким способом
    javascript:(function(){document.getElementsByTagName('head')[0].appendChild(document.createElement('SCRIPT')).src='http://127.0.0.1/user.js';})();

    сервачёк правда нужен
    • 0
      Это не совсем юзерскрипт, а скорее аналог прокси-инъекции, инъекция скрипта через букмарклет :)

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

  • 0
    В статье написано много и по делу, но не озвучен самый главный вопрос: как устанавливать юзер-скрипты в браузер?
    • 0
      Да, за этот промах каюсь.

      Если бы я включил в статью детальную информацию о браузерах — получилось бы большое полотно.
      Поэтому я решил разделить статью на две части: самые основы написания юзерскриптов и более подробный побраузерный разбор.

      Ждите, вторая статья на подходе :)
    • 0
      это же гуглится элементарно для своего браузера, пусть лучше статьи будут про интересное.
  • +2
    Побуду занудой: «unsafeWindow» — он не спроста так называется. GM дает пользовательским скриптам доступ к допольнительному (небезопасному) API и если вы не специалист в JS и не имеете четкого понимания концепции безопасности в GM, то при использовании unsafeWindow вы скорее всего выстрелите себе в ногу. Лучше вместо этого по-возможности использовать window (безопасную обертку, специально для вас сделанную).

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.