[Урок 3] . Получение любой информации со страницы при помощи Javascript

Каждый уважающий себя бот должен уметь извлекать любую информацию с сайта, например ссылки, заголовки, любой текст, номера телефонов, адреса электронной почты, картинки. В этом уроке мы рассмотрим несколько методов сбора данных на странице при помощи iMacros и Javascript.

Исходный код страницы

Для начала, я хочу очень кратко рассказать про то, из чего состоит веб-страница. Вы можете открыть любой сайт, например мой блог и нажать Ctrl+U(или правой кнопкой на странице и выбрать «Исходный код»). Вы увидите код, это обычный текст в формате HTML, который браузер преобразует в веб-страницу. Ключевые слова, заключенные в «<>» — называются тегами, свойства внутри них — атрибутами и значениями атрибута. Все это нам пригодится, чтобы отыскивать необходимые теги с нужной информацией.

Пример:

schema

Что же делает браузер с этим кодом? Браузер, руководствуясь этим кодом, располагает информацию на странице в указанном порядке, подгружает таблицы стилей css, которые добавляют оформление элементам, подгружает и вставляет картинки, скачивает и выполняет различные скрипты. Правила, по которым браузер это делает — называются спецификацией, которая необходима, чтобы все браузеры отрисовывали страницы и обрабатывали скрипты одинаково.

DOM (Document Object Model) – объектная модель страницы

Основным инструментом работы и динамических изменений на странице является DOM (Document Object Model) – объектная модель, используемая для XML/HTML-документов. Согласно DOM-модели, документ является иерархией, деревом. Каждый HTML-тег образует узел дерева с типом «элемент». Вложенные в него теги становятся дочерними узлами. Для представления текста создаются узлы с типом «текст».

DOM – это представление страницы в виде дерева объектов, доступное для чтения и изменения через JavaScript.

При чтении неверного HTML браузер автоматически корректирует его для показа и при построении DOM. В частности, всегда будет верхний тег <html>. Даже если в тексте нет – в DOM он будет, браузер создаст его самостоятельно. То же самое касается и тега <body>. Например, если файл состоит из одного слова "Test", то браузер автоматически обернёт его в <html> и <body>.

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

Методы извлечения информации из тегов средствами iMacros

У iMacros есть возможности для извлечения текста и даже html-кода из тегов. Для начала я рекомендую вам установить расширение FireBug, если вы этого еще не сделали. Открывается он по нажатию клавиши F12, либо вы можете нажать в любом месте страницы правой кнопкой и тыкнуть «Инспектировать элемент при помощи Firebug».

Чтобы потренироваться и как следует разобраться, я создал для вас специальную страничку
http://polygon.nagibaka.ru/lessons/lesson3/index.htm

Давайте приступим, я рекомендую вам сразу открыть эту ссылку в Firefox. Поскольку вам предстоит писать много кода, рекомендую первым делом поставить себе какой-нибудь редактор, например весьма распространенный Notepad++ или же мой любимый и в сто раз более удобный Sublime Text 3, я писал о плагинах для него и режиме Vim для быстрого и мощного редактирования.

Давайте нажмем на «Запись» в iMacros, тыкнем по первому заголовку и остановим запись.

Мы получим вот такой скрипт(Current.iim):

VERSION BUILD=8970419 RECORDER=FX
TAB T=1
URL GOTO=http://polygon.nagibaka.ru/lessons/lesson3/index.htm
TAG POS=1 TYPE=H1 ATTR=TXT:Тестовая<SP>страница

Давайте переделаем его в JS.
Создайте новый файл, например test.js. Допустим, нам необходимо получить содержимое тега "<H1>". Переделаем макрос на js и извлечем из него содержимое тега "<H1>".

Результат(test.js):

iimPlayCode('TAG POS=1 TYPE=H1 ATTR=TXT:* EXTRACT=TXT');
iimDisplay(iimGetExtract());

Обратите внимание — я заменил "Тестовая<SP>страница" на "*" — поскольку текст заголовка может быть любым, а звездочка нам говорит, что текст может быть произвольным
TYPE=H1 — указывает что мы ищем тег «<H1>«, можно указать любой другой
POS=1 — указывает, что мы выбираем первый попавшийся тег <H1>, ведь на странице их может оказаться несколько
ATTR=TXT:* — указывает значение атрибута, в данном случае служебный атрибут, который ищет совпадение в тексте внутри тега
EXTRACT=TXT — указывает, что мы извлекаем текст, также можно указать "EXTRACT=HTM" , чтобы извлечь текст вместе со всеми тегами

Методы извлечения информации из тегов средствами Javascript

Теперь давайте перепишем код полностью на JS без использования iim-команд. Еще, вместо iimDisplay мы будем использовать window.console.log('any text and vars'); Данные, которые мы будем выводить этой командой — будут отображаться в консоли firebug. Такой вариант удобнее по многим причинам, например, можно выводить js-объекты и удобно просматривать их содержимое. А самое главное, при помощи iimDisplay единовременно можно смотреть только последнее выведенное сообщение, а c этой командой мы увидим полный лог. Небольшое примечание, в некоторых старых версиях FF(например 27), window.console.log не всегда работало, и обратите внимание, нужно писать именно window.console.log, несмотря на то, что при создании обычных сайтов, чаще пишут просто console.log, весь наш код выполняется в контексте расширения iMacros, поэтому необходимо добавлять window.

Код на JS(test.js):

var h1Text = window.document.querySelector("h1").innerHTML;
window.console.log(h1Text); // выведет в консоли "Тестовая страница"

Здесь мы использовали поиск элемента по тегу. На самом деле, метод querySelector принимает в качестве параметра любое выражение в формате css-правила. Еще важно знать, что querySelector возвращает только первый элемент из DOM-дерева, который совпал. Чтобы получить все элементы, подходящие под указанное правило, используйте querySelectorAll.

Приведу несколько примеров:

// Поиск по классу
window.document.querySelector(".styled");

// Поиск по идентификатору
window.document.querySelector("#tmp") ;

// Поиск по аттрибуту идентификатора с указанием его значения 
window.document.querySelector("[id=tmp]");

// Поиск по кастомному аттрибуту, тут только его наличие проверяется
window.document.querySelector("[data-id]");

// Поиск div в котором есть аттрибут title, в котором содержится подстрока '13'
window.document.querySelector("div[title*='13']");

// Поиск последнего и первого div, который находится внутри формы(<form>)
window.document.querySelector("form div:last-child");
window.document.querySelector("form div:first-child");

// Поиск любых элементов на странице, вернет первый попавшийся
window.document.querySelector("*"); //Вернет <html>
window.document.querySelector("html *"); //Вернет <head>

Вы можете получать список всех элементов, подходящих под заданное правила, используйте для этого querySelectorAll() — он всегда возвращает коллекцию элементов либо null.

Давайте выведем все ссылки в консоль.

window.console.log( window.document.querySelectorAll("a") );

Тут мы видим набор элементов, а если быть точнее, то коллекцию узлов DOM-дерева. Квадратные скобки могут натолкнуть  на мысль о том, что это обычный массив, но это не совсем так. Мы не сможем для такой коллекции использовать стандартные методы массива, такие, как .map(), .filter() и крайне удобный .forEach(). Поэтому для перебора и обработки элементов такой коллекции мы будем использовать классический цикл for.

В коллекции 6 элементов, вы можете нажать на любой и тогда откроется инспектор DOM-дерева и вы увидите элемент, на который нажали.

iMacros js тестовая страница

Хоть это и неполноценный массив, но нам все равно доступно свойство length. Давайте посчитаем количество ссылок в коллекции и выведем для каждой ссылки заголовок и адрес, куда она ссылается. В JS есть несколько вариантов реализации циклов, мы пока используем самый простой for.

Выводим все ссылки на странице и информацию о них:

var linkList = window.document.querySelectorAll("a");

window.console.log("Links count: ", linkList.length);

for (var i = 0; i < linkList.length; i++) {
    
    window.console.log('====' + (i + 1) + " Link ===="); // behavior

    window.console.log("Link text: ",  linkList[i].innerHTML);
    window.console.log("Link title: ", linkList[i].getAttribute('title'));
    window.console.log("Link href: ",  linkList[i].getAttribute('href'));
}

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

Помимо получения значений аттрибутов при помощи метода getAttribute(), текста внутри тега при помощи innerHTML, мы можем делать разные другие вещи. Чтобы посмотреть доступные методы, вы можете поискать в документации по JS, или воспользоваться автокомплитом из консоли, попробуйте вручную ввести window.document.querySelectorAll("a")[0].  или window.document.querySelector("a")., что будет равнозначно, и после ввода точки появится список поддерживаемых методов и свойств, более подробно о каждом свойстве или методе вы легко найдете в гугле. Подобным образом вы сможете исследовать методы и свойства любого объекта.
И еще, вы можете указывать несколько селекторов через запятую, например window.document.querySelectorAll("a, .styled")

imacros css selector

Есть и другие методы для получения нужных нам тегов и извлечения из них различных свойств и атрибутов, но они не особо актуальны, потому что querySelectorAll — это метод, который поддерживают все современные браузеры, обладает куда большим функционалом и у нас нет необходимости использовать устаревшие методы, вроде window.document.getElementById(), window.document.getElementsByClassName(), window.document.getElementsByTagName() и прочие.

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

Пишите ваши вопросы и комментарии!

До новых встреч!

32 комментариев

  1. Не пашет нихрена. Непонять где и как и какую консоль мы должны увидеть. Непонять в какой версии FF все это должно работать. Очень нужные знания, но подача не очень. Уж извини…

    Ответить
    • Переезжал на другой сервер. Теперь polygon работает!
      Консоль в данном случае — это не черное окно терминала, а панель внизу браузера для ввода команд. На скрине в статье она есть, там при вводе команд вылезает подсказка со списком команд. Консоль открывается при нажатии на F12 в FF или Chrome. Там тыкаете на вкладку Console(Консоль).

      Ответить
  2. querySelectorAll возвращает не массив (Array), а коллекцию узлов (NodeList). У последнего отсутствуют методы массива.

    Ответить
    • ololo, спасибо за наблюдательность! В каком-то смысле получается массив узлов, но ваше замечание важное, добавил примечание в статью, чтобы не было вопросов, почему нельзя использовать стандартные методы, вроде forEach() в данном примере.

      Ответить
    • // ======= Запуск bat файла из JS ============
      function GoEXE(adr){
      var fl = Components.classes[«@mozilla.org/file/local;1»].createInstance(Components.interfaces.nsILocalFile);
      fl.initWithPath(adr);
      fl.launch();
      }
      // отключить питпние компа
      GoEXE(«c:\\PowerOff.bat»);

      Ответить
  3. Доброго времени. Я вот вытаскиваю код, который во всплывающем окне, но поскольку он изначально есть в коде страницы, то в любом случае он вытаскивается. Как именно отловить что он во всплывающем окошке?

    Ответить
    • Александр, вам нужно проверять css-свойства окна или отследить может добавляются какие-то классы к разметке окна. И по этим признакам вы можете определить видно оно или нет в данный момент.

      Ответить
  4. пытаюсь запустить скрипт из примера, но выдает ошибку

    Error: Accessing content window is not supported in multiprocess Firefox, line 208 (Error code: -991)

    что делать?

    Ответить
      • спасибо.

        а можно ли как то в новой версии использовать? я работаю с бледной луной.

        Ответить
      • Не работает! НЕ работаеТ!
        Почему Вы не написали программные требования к запуску скриптов? Введя в заблуждение, ничего не работет! ДА ВСЕ НАПИСАНО У ВАС понятно! Но ничерта не работает! Очень приятно читать вашу СТАТЬЮ! Но ДА ничерта не работает!

        Пожалуйста напишите в первом уроке требования по запуску скриптов! Все ухожу с сайта, на котором все понятно написано и нифига не работает!
        В РОТ МНЕ НОГИ! цените время людей!

        Ответить
        • Жора, все скрипты написаны под iMacros 8.9.7. и тестируются на Firefox 35. Почему 9-я версия iMacros — говно, и не подходит для нормальной разработки — я в ближайшее время напишу статью, а заодно добавлю к каждой старой статье «требования» к версии iMacros и Firefox с ссылкой на ответы на вопрос «почему?».

          Ответить
  5. И у меня просьба помочь вытащить баланс аккаунта из таблицы. Пока получилось вытащить всю строку таблицы, и затем беру вокруг точки, в балансе по 2 цифры.
    При изменении количества цифр в этой и соседних колонках вытянутая сумма искажается.
    http://joxi.ru/Q2KDW8DF4dpW8A

    Ответить
    • Все, удалось, но как-то довольно интуитивно…
      var str = content.window.document.querySelectorAll(‘tr’)
      str = str[3].innerHTML
      var bal = str.match(/\d{1,2}\.\d{2}/igm)
      var bal = bal[0].replace(«.»,»,»)
      window.console.log(bal)

      Ответить
  6. Подскажите, можно ли прикрутить xmlhttprequest?
    Или как получить код «соседней» страницы не загружая её?
    Использую ff35, скачанный с вашего сайта.

    Ответить
  7. На странице выполняю действие EVENT TYPE=CLick, открывается всплывающее окно, подгружаемое ajax-ом, в DOM добовляется div, считываю информацию.
    Далее выполняю такие же действия для следующего элемента, но всплывающее окно для предыдущего элемента остаётся, вместе с div.
    Подскажите, как «уйти» с предыдущего элемента?

    Ответить
    • Здравствуйте!
      Можно ли запустить исполняемый файл (.exe или .bat) из iMacros или Javascript
      ???

      Ответить
  8. Здравствуйте!
    Можно ли запустить исполняемый файл (.exe или .bat) из iMacros или Javascript
    ???

    Ответить
    • // ======= Запуск bat файла из JS ============
      function GoEXE(adr){
      var fl = Components.classes[«@mozilla.org/file/local;1»].createInstance(Components.interfaces.nsILocalFile);
      fl.initWithPath(adr);
      fl.launch();
      }
      // отключить питпние компа
      GoEXE(«c:\\PowerOff.bat»);

      Ответить
      • не спрашивайте меня что это значит. Мне дали этот код. Я его использую. Он работает.

        Ответить
  9. Возможно ли выполнить функцию , которая уже загружена с
    сайта с помощью макроса ?
    Если нет то как с помощью макроса через консоль передать выполнить функцию которая уже есть на странице .
    Ибо если я пишу в макросе winlow.console.log(funcF(X,Y)
    получаю что эта функция не объявлена .если я выполняю в консоле
    funcF(X,Y) — все работает
    Еле конечно вариант проследить пост/гет запрос но это для меня сложно .
    Пожалуйста посоветуйте что нибудь.

    Ответить

Оставить комментарий