Top Banner
PhantomJS Автоматизация WebKit на JavaScript
31

Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Jun 16, 2015

Download

Software

Provectus

Web Expert Day
September 20, 2014

Kazan, Russia
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

PhantomJSАвтоматизация WebKit на JavaScript

Page 2: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

fun-box.ru/ulsk

Илья Василевский

Разработчик на Ruby и CoffeeScript

github.com/vassilevsky

Page 3: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Page 4: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

1995 — 2014 (19 лет)

Trolltech → Nokia → Digia

C++

Android, Embedded Linux, iOS, OS X, QNX / BlackBerry 10, Sailfish OS, VxWorks,

Wayland, Windows, Windows CE, X11 (GNU/Linux, FreeBSD, HP-UX, Solaris, AIX)

http://qt-project.org

Page 5: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Qt CoreQt GUIQt WidgetsQt QML and JavaScriptQt QuickQt Quick ControlsQt Quick LayoutsQt NetworkQt MultimediaQt Multimedia WidgetsQt SQLQt WebKitQt WebKit WidgetsQt Test

Page 6: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

#include <QApplication>

#include <QMenu>

#include <QPixmap>

#include <QWidget>

#include <qmacfunctions.h>

int main(int argc, char **argv)

{

QApplication app(argc, argv);

QWidget widget;

widget.show();

// Pixmap <-> CGImage conversion

QPixmap pixmap(":qtlogo.png");

CGImageRef cgImage = QtMac::toCGImageRef(pixmap);

QPixmap pixmap2 = QtMac::fromCGImageRef(cgImage);

return app.exec();

}

Page 7: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

require 'Qt'

require './qrc_systray.rb'

require './window.rb'

app = Qt::Application.new(ARGV)

if !Qt::SystemTrayIcon.isSystemTrayAvailable

Qt::MessageBox.critical(

nil,

Qt::Object.tr("Systray"),

Qt::Object.tr("I couldn't detect any system tray on this system.")

)

exit 1

end

window = Window.new

window.show

app.exec

Page 8: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Page 9: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Qt CoreQt GUIQt WidgetsQt QML and JavaScriptQt QuickQt Quick ControlsQt Quick LayoutsQt NetworkQt MultimediaQt Multimedia WidgetsQt SQLQt WebKitQt WebKit WidgetsQt Test

Page 10: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

QWindow

QWebView

QWidget

QWidget QWebPage

QWebFrame

Page 11: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Ariya HidayatVP of Engineering at @ShapeSecurity

Doctorate degree (with great honor) in Electrical Engineeringfrom University of Paderborn (Germany)

Master degree from Institute of Technology Bandung (Indonesia)with an exchange program with Technical University Munich (Germany)

Bachelor degree (with honor) from Institute of Technology Bandung (Indonesia)

Indonesian, English, GermanIndonesia → Mountain View, California

@AriyaHidayat

Page 12: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Qt WebKit

Ghost Driver

RemoteSelenium WebDriver

(Wire Protocol)

JavaScript API Engine

WebServer

Mongoose

JavaScript Engine

Page 13: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"
Page 14: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

$ ls -l phantomjs-1.9.7-linux-x86_64/bintotal 74896-rwxr-xr-x@ 1 vassilevsky staff 38346752 26 янв 2014 phantomjs

X11 (v1.5+)

freetypefontconfig

Page 15: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

// goodbye_world.js

console.log('Goodbye, cruel world!');

phantom.exit();

$ phantomjs goodbye_world.jsGoodbye, cruel world!

Page 16: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

// screenshot.js

var page = require('webpage').create();

page.open('http://www.therestartpage.com', function(status) {

if (status == 'success') {

page.render('restart.png');

}

phantom.exit();

});

$ phantomjs screenshot.js

$ open restart.png

Page 17: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

// stealing.js

var page = require('webpage').create();

page.open('http://victim.com', function(status) {

if (status == 'success') {

var usefulValue = page.evaluate(function() {

return document.getElementById('secretId').textContent; // runs on page

});

console.log('Stolen: ' + usefulValue);

}

phantom.exit();

});

$ phantomjs stealing.js

Stolen: uid123456789

Page 18: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Qt WebKit

JavaScript API Engine

JavaScript Engine

function() {

return document.getElementById('secretId').textContent;

}

var page = require('webpage').create();

page.open('http://victim.com', function(status) {

if (status == 'success') {

var usefulValue = page.evaluate( );

console.log('Stolen: ' + usefulValue);

}

phantom.exit();

});

Qt WebKit

Page 19: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

var page = require('webpage').create();

doSomeWork = function(param1, param2, param3) {

doSomethingWith(param1); // runs on page

useSomehow(param2); // runs on page

disregard(param3); // runs on page

}

page.open('http://example.com', function() {

page.evaluate(doSomeWork, value1, value2, value3);

phantom.exit();

});

Page 20: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Qt WebKit

JavaScript API Engine

JavaScript Engine

function(param1, param2, param3) {

doSomethingWith(param1);

useSomehow(param2);

disregard(param3);

}

var page = require('webpage').create();

page.open('http://example.com', function() {

page.evaluate(doSomeWork, value1, value2, value3);

phantom.exit();

});

Qt WebKit

Page 21: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Qt WebKit

JavaScript API Engine

JavaScript Engine

function(param1, param2, param3) {

doSomethingWith(param1);

useSomehow(param2);

disregard(param3);

}

var page = require('webpage').create();

page.open('http://example.com', function() {

page.evaluate(doSomeWork, value1, value2, value3);

phantom.exit();

});

Qt WebKit

J S O N

Page 22: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

PROPERTIES

canGoBackcanGoForwardclipRectcontentcookiescustomHeaderseventfocusedFrameNameframeContentframeNameframePlainTextframeTitleframeUrlframesCountframesNamelibraryPathnavigationLockedofflineStoragePathofflineStorageQuotaownsPagespagespagesWindowNamepaperSizeplainTextscrollPositionsettingstitleurlviewportSizewindowNamezoomFactor

METHODS

addCookiechildFramesCountchildFramesNameclearCookiesclosecurrentFrameNamedeleteCookieevaluateevaluateAsyncevaluateJavaScriptgetPagegogoBackgoForwardincludeJsinjectJsopenopenUrlreleasereloadrenderrenderBase64sendEventsetContentstopswitchToChildFrameswitchToFocusedFrameswitchToFrameswitchToMainFrameswitchToParentFrameuploadFile

HANDLERS

onAlertonCallbackonClosingonConfirmonConsoleMessageonErroronFilePickeronInitializedonLoadFinishedonLoadStartedonNavigationRequestedonPageCreatedonPromptonResourceErroronResourceReceivedonResourceRequestedonResourceTimeoutonUrlChanged

Page 23: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

require 'childprocess'

def phantomjs(script, timeout)

output, input = IO.pipe

phantomjs = ChildProcess.new("/usr/local/bin/phantomjs", "--disk-cache=true", script)

phantomjs.io.stdout = input

phantomjs.io.stderr = input

Timeout.timeout(timeout) do

phantomjs.start

input.close

logger.info("Attaching to PhantomJS's STDOUT and STDERR...")

output.each_line{|line| logger.info("[PhantomJS] #{line}") }

end

rescue Timeout::Error

logger.warn("PhantomJS is running longer than expected. Shutting it down...")

phantomjs.stop

end

Page 24: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

page = require('webpage').create()

page.viewportSize = {width, height}

prepareTrack = (i) ->

track = tracks[i]

page.evaluate(drawTrack, track.bounds, track.locations)

setTimeout(renderTrack, MAP_LOADING_TIME, i)

renderTrack = (i) ->

track = tracks[i]

page.render(track.imagePath)

if i + 1 == tracks.length

phantom.exit()

else

prepareTrack(i + 1)

drawTrack = (bounds, locations) ->

setBounds(bounds)

drawTrackLine(locations)

page.open(hostPage)

setTimeout(renderTrack, MAP_LOADING_TIME, 0)

Page 25: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

!!! 5

%html

%head

%meta{charset: "utf-8"}

:css

#map_container { position: absolute; left: 0; right: 0; top: 0; bottom: 0 }

%body

#map_container

%script{src: "http://api-maps.yandex.ru/2.1/?lang=ru_RU"}

:coffeescript

@map = null

ymaps.ready =>

@map = new ymaps.Map 'map_container'

@setBounds = (bounds) ->

@map.setBounds(bounds)

@drawTrackLine = (locations) ->

points = (location.point for location in locations)

@map.geoObjects.add(new ymaps.Polyline(points))

Page 26: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

RSpec Cucumber MiniTest

Capybara

Poltergeist

PhantomJS

Page 27: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

require 'capybara/poltergeist'

Capybara.javascript_driver = :poltergeist

Capybara.methods +=

page.evaluate_scriptpage.execute_scriptpage.within_framepage.within_windowpage.status_codepage.response_headerspage.save_screenshotpage.driver.render_base64(format, options)page.driver.scroll_to(left, top)page.driver.basic_authorize(user, password)element.native.send_keys(*keys)

Page 28: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

JS API

class Poltergeist.Connection

constructor: (@owner, @port) ->

@socket = new WebSocket "ws://127.0.0.1:#{@port}/"

@socket.onmessage = this.commandReceived

@socket.onclose = -> phantom.exit()

WebKit

module Capybara::Poltergeist

class Server

attr_reader :socket, :fixed_port, :timeout

def start

@socket = WebSocketServer.new(fixed_port, timeout)

end

def send(message)

@socket.send(message) or raise DeadClient.new(message)

end

end

end

Page 29: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

class Poltergeist.WebPage

onErrorNative: (message, stack) ->

stackString = message

stack.forEach (frame) ->

stackString += "\n"

stackString += " at #{frame.file}:#{frame.line}"

stackString += " in #{frame.function}" if frame.function && frame.function != ''

@errors.push(message: message, stack: stackString)

class Poltergeist.Browser

sendResponse: (response) ->

errors = @currentPage.errors

@currentPage.clearErrors()

if errors.length > 0 && @js_errors

@owner.sendError(new Poltergeist.JavascriptError(errors))

else

@owner.sendResponse(response)

Page 30: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

Casper.jsChutzpahGhostbusterGhostDriverLottePoltergeistCapybarapjscrapeWebSpecterconjurePhantomJS Google Chartscapturejspageresphantomjs-screenshotsscreenshot-appscreenshot-as-a-service

screenshot-servicescreenshotscreenshot-webservicepyshotxnode-webshotpageresdjango-screamshotPHP ScreengrabshotbassetCompass MagickConfessGhostStoryGroverGruntGuard PhantomJS

phridgephantomjs-nodenode-phantomphantom-proxyphantomasPhantomCSSPhantomFlowphantomjs-maven-plugingrunt-lib-phantomjsgrunt-contrib-qunitPhantomLintPhantomXHRshortcut.ioSlippySpookyJSYeoman

Page 31: Василевский Илья (Fun-box): "автоматизация браузера при помощи PhantomJS"

За внимание спасибо