Каждый уважающий себя бот должен уметь извлекать любую информацию с сайта, например ссылки, заголовки, любой текст, номера телефонов, адреса электронной почты, картинки. В этом уроке мы рассмотрим несколько методов сбора данных на странице при помощи iMacros и Javascript.
Исходный код страницы
Для начала, я хочу очень кратко рассказать про то, из чего состоит веб-страница. Вы можете открыть любой сайт, например мой блог и нажать Ctrl+U
(или правой кнопкой на странице и выбрать «Исходный код»). Вы увидите код, это обычный текст в формате HTML, который браузер преобразует в веб-страницу. Ключевые слова, заключенные в «<>» — называются тегами, свойства внутри них — атрибутами и значениями атрибута. Все это нам пригодится, чтобы отыскивать необходимые теги с нужной информацией.
Пример:
Что же делает браузер с этим кодом? Браузер, руководствуясь этим кодом, располагает информацию на странице в указанном порядке, подгружает таблицы стилей 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-дерева и вы увидите элемент, на который нажали.
Хоть это и неполноценный массив, но нам все равно доступно свойство 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")
Есть и другие методы для получения нужных нам тегов и извлечения из них различных свойств и атрибутов, но они не особо актуальны, потому что querySelectorAll — это метод, который поддерживают все современные браузеры, обладает куда большим функционалом и у нас нет необходимости использовать устаревшие методы, вроде window.document.getElementById()
, window.document.getElementsByClassName()
, window.document.getElementsByTagName()
и прочие.
Также, для мощного поиска по тексту веб-страницы, можно использовать регулярные выражения, инструмент невиданной силы и мощи, который заслуживает отдельной книги страниц на 600, о нем я расскажу в следующих уроках.
Пишите ваши вопросы и комментарии!
До новых встреч!
исправь опечатку в строке «а c этой окмандой мы увидим полный лог.»
Спасибо, поправил!
Не пашет нихрена. Непонять где и как и какую консоль мы должны увидеть. Непонять в какой версии FF все это должно работать. Очень нужные знания, но подача не очень. Уж извини…
Переезжал на другой сервер. Теперь polygon работает!
Консоль в данном случае — это не черное окно терминала, а панель внизу браузера для ввода команд. На скрине в статье она есть, там при вводе команд вылезает подсказка со списком команд. Консоль открывается при нажатии на F12 в FF или Chrome. Там тыкаете на вкладку Console(Консоль).
Да с консолью всё понятно. Она есть и работает. Не пашеи именно log.
Починил. В конфиге palemoon почему то было выключено.
так рассказал бы как включить..
Благодарю! Впервые встречаю так понятно, как у вас!
querySelectorAll возвращает не массив (Array), а коллекцию узлов (NodeList). У последнего отсутствуют методы массива.
ololo, спасибо за наблюдательность! В каком-то смысле получается массив узлов, но ваше замечание важное, добавил примечание в статью, чтобы не было вопросов, почему нельзя использовать стандартные методы, вроде
forEach()
в данном примере.Здрасте, подскажите как из imacros запустить файл с расширением .bat?
// ======= Запуск 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»);
Здравствуйте, почему у меня ни один пример js не работает — http://prntscr.com/efnb1f, http://prntscr.com/efncx4
Доброго времени. Я вот вытаскиваю код, который во всплывающем окне, но поскольку он изначально есть в коде страницы, то в любом случае он вытаскивается. Как именно отловить что он во всплывающем окошке?
Александр, вам нужно проверять css-свойства окна или отследить может добавляются какие-то классы к разметке окна. И по этим признакам вы можете определить видно оно или нет в данный момент.
Благодарю!
пытаюсь запустить скрипт из примера, но выдает ошибку
Error: Accessing content window is not supported in multiprocess Firefox, line 208 (Error code: -991)
что делать?
Вы используете свежую версию браузера, используйте Firefox 35.
спасибо.
а можно ли как то в новой версии использовать? я работаю с бледной луной.
Не работает! НЕ работаеТ!
Почему Вы не написали программные требования к запуску скриптов? Введя в заблуждение, ничего не работет! ДА ВСЕ НАПИСАНО У ВАС понятно! Но ничерта не работает! Очень приятно читать вашу СТАТЬЮ! Но ДА ничерта не работает!
Пожалуйста напишите в первом уроке требования по запуску скриптов! Все ухожу с сайта, на котором все понятно написано и нифига не работает!
В РОТ МНЕ НОГИ! цените время людей!
Жора, все скрипты написаны под iMacros 8.9.7. и тестируются на Firefox 35. Почему 9-я версия iMacros — говно, и не подходит для нормальной разработки — я в ближайшее время напишу статью, а заодно добавлю к каждой старой статье «требования» к версии iMacros и Firefox с ссылкой на ответы на вопрос «почему?».
И у меня просьба помочь вытащить баланс аккаунта из таблицы. Пока получилось вытащить всю строку таблицы, и затем беру вокруг точки, в балансе по 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)
Подскажите, можно ли прикрутить xmlhttprequest?
Или как получить код «соседней» страницы не загружая её?
Использую ff35, скачанный с вашего сайта.
* не загружая её в окно браузера
Можно ли вывести новое значение value элемента не обновляя всю страницу в браузере?
На странице выполняю действие EVENT TYPE=CLick, открывается всплывающее окно, подгружаемое ajax-ом, в DOM добовляется div, считываю информацию.
Далее выполняю такие же действия для следующего элемента, но всплывающее окно для предыдущего элемента остаётся, вместе с div.
Подскажите, как «уйти» с предыдущего элемента?
Здравствуйте!
Можно ли запустить исполняемый файл (.exe или .bat) из iMacros или Javascript
???
Здравствуйте!
Можно ли запустить исполняемый файл (.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»);
не спрашивайте меня что это значит. Мне дали этот код. Я его использую. Он работает.
Возможно ли выполнить функцию , которая уже загружена с
сайта с помощью макроса ?
Если нет то как с помощью макроса через консоль передать выполнить функцию которая уже есть на странице .
Ибо если я пишу в макросе winlow.console.log(funcF(X,Y)
получаю что эта функция не объявлена .если я выполняю в консоле
funcF(X,Y) — все работает
Еле конечно вариант проследить пост/гет запрос но это для меня сложно .
Пожалуйста посоветуйте что нибудь.