Браузер, который сам ходит по ссылкам, открывает/закрывает табы, парсит или сохраняет весь контент на файловую систему — интересно посмотреть на такое, не так ли? Лично мне интересно было создать что-то подобное. Никакой фантастики! В общем в очередной раз во мне проснулось нечто вроде программистской лени вдохновения и вместо того, чтобы писать обычный crawler (он же spider или по-простому парсер сайта) на PHP, Perl или Ruby, я начал разбираться, как это сделать на FireFox.
Для того, чтобы все это сделать мне нужна была JavaScript консоль, из которой я имел бы доступ к XUL DOM. Я написал очень простое расширение для FireFox, которое добавляет значок в нижний правый угол окна браузера
Кликнув по этому значку откроется окно в котором можно писать JavaScript код и управлять элементами браузера. Расширение можно скачать здесь.
Чтобы запустить скрипт жмем CTRL+Enter (фокус должен быть на элементе textbox).
Так как не все программисты знакомы с JavaScript объектами в самом FireFox-е, думаю немного теории будет полезно. По аналогии к HTML «передовыми игроками» являются window и document. Чтобы обратится к контенту (HTML DOM) нужно написать так
Подготовка
Для того, чтобы все это сделать мне нужна была JavaScript консоль, из которой я имел бы доступ к XUL DOM. Я написал очень простое расширение для FireFox, которое добавляет значок в нижний правый угол окна браузера
Кликнув по этому значку откроется окно в котором можно писать JavaScript код и управлять элементами браузера. Расширение можно скачать здесь.
Чтобы запустить скрипт жмем CTRL+Enter (фокус должен быть на элементе textbox).
Для тех кто в танке
Так как не все программисты знакомы с JavaScript объектами в самом FireFox-е, думаю немного теории будет полезно. По аналогии к HTML «передовыми игроками» являются window и document. Чтобы обратится к контенту (HTML DOM) нужно написать так
var links = window.content.document.getElementsByTagName('a');
// or just
var links = content.document.querySelectorAll('a');
alert(links.length)
* This source code was highlighted with Source Code Highlighter.
Еще очень важный момент — это как отловить момент загрузки HTML DOM, а также как работать с табами и браузером. Для обращения к элементу tabbrowser можно использовать глобальную переменную gBrowser. С помощью этого элемента можно манипулировать табами. Несколько примеров
// add new tab
var tab = gBrowser.addTab('http://habrahabr.ru');
gBrowser.selectedTab = tab;
// get browser element for tab
var browser = gBrowser.getBrowserForTab(tab);
// add listeners on page load
browser.addEventListener('DOMContentLoaded', function(event){
// listener implementation
}, false);
// add listeners on HTML DOM loaded
browser.addEventListener('DOMContentLoaded', function(event){
if (event.originalTarget instanceof HTMLDocument) {
var document = event.originalTarget;
// listener implementation
}
}, false);
* This source code was highlighted with Source Code Highlighter.
Также думаю будет полезным научится сохранять веб страницу в файл
var tab = gBrowser.addTab('http://habrahabr.ru');
gBrowser.selectedTab = tab;
var browser = gBrowser.getBrowserForTab(tab);
browser.addEventListener('DOMContentLoaded', function(event){
var document = event.originalTarget;
if (document instanceof HTMLDocument && this.contentWindow.document == document) {
var basename = document.location.href.replace(/\/+$/, ''),
pos = basename.lastIndexOf('/');
if (pos != -1) {
basename = basename.substr(pos+1);
}
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath('/tmp/'+basename);
if (!file.exists()) {
var chosen = new AutoChosen(file, makeFileURI(file));
internalSave(document.location.href, document, null, null, document.contentType, false, null, chosen);
}
}
}, false)
* This source code was highlighted with Source Code Highlighter.
Дополнительное условие this.contentWindow.document == document фильтрует ситуации, когда на странице есть iframe элементы, а страницу сохранить нужно только раз и ту, которая нужна, а не из фрейма.
О функции internalSave (сохраняет файл) и классе AutoChosen (как я понял эмулирует выбор файла пользователем) можно почитать комментарии в исходном коде. Больше примеров работы с файлами здесь.
Дрессируем FireFox
Напишем скрипт, который научит FireFox входить под определенным пользователем на Хабр.
var Crawler = {
habrahabr: function(username, password) {
this.username = username;
this.password = password;
},
onHTMLLoaded: function (browser, callback) {
browser.addEventListener('DOMContentLoaded', function(event){
var document = event.originalTarget;
if (document instanceof HTMLDocument
&& this.contentWindow.document == document
) {
this.removeEventListener('DOMContentLoaded', arguments.callee, false);
callback.call(this, event, document);
}
}, false);
return browser;
}
}
Crawler.habrahabr.prototype = {
url: 'http://habrahabr.ru/',
openAndSignIn: function(inNewTab) {
var tab = gBrowser.selectedTab, browser = null;
if (inNewTab) {
tab = gBrowser.addTab(this.url);
} else {
content.document.location = this.url;
}
browser = gBrowser.getBrowserForTab(tab);
var that = this;
Crawler.onHTMLLoaded(browser, function(event, document){
document.location = document.querySelector('dl.panel-personal a').href;
Crawler.onHTMLLoaded(this, function(event, document){
var user = document.getElementById('reg-f-username');
user.value = that.username;
document.getElementById('reg-f-password').value = that.password;
user.form.querySelector('input[type="submit"]').click();
});
});
}
};
var cr = new Crawler.habrahabr('serjoga', '***');
cr.openAndSignIn(true);
* This source code was highlighted with Source Code Highlighter.
В начале создаем объект Crawler, в который потом можно будет добавлять новые парсеры. Создаем конструктор для парсера habrahabr, в который передаем имя пользователя и пароль. Добавляем метод openAndSignIn в прототип объекта habrahabr. Этот метод умеет открывать Хабр и авторизироваться под заданным юзером.
P. S.: я часто автоматизирую воспроизведение тест-кейсов багов, очень забавно и не утомительно, в том случае когда нужно нажать кучу кнопок и ходить по 10 страницам еще и на 2 сайтах.