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

Post on 16-Jun-2015

260 Views

Category:

Software

4 Downloads

Preview:

Click to see full reader

DESCRIPTION

Web Expert Day September 20, 2014 Kazan, Russia

Transcript

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

fun-box.ru/ulsk

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

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

github.com/vassilevsky

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

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

#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();

}

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

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

QWindow

QWebView

QWidget

QWidget QWebPage

QWebFrame

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

Qt WebKit

Ghost Driver

RemoteSelenium WebDriver

(Wire Protocol)

JavaScript API Engine

WebServer

Mongoose

JavaScript Engine

$ 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

// goodbye_world.js

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

phantom.exit();

$ phantomjs goodbye_world.jsGoodbye, cruel world!

// 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

// 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

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

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();

});

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

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

PROPERTIES

canGoBackcanGoForwardclipRectcontentcookiescustomHeaderseventfocusedFrameNameframeContentframeNameframePlainTextframeTitleframeUrlframesCountframesNamelibraryPathnavigationLockedofflineStoragePathofflineStorageQuotaownsPagespagespagesWindowNamepaperSizeplainTextscrollPositionsettingstitleurlviewportSizewindowNamezoomFactor

METHODS

addCookiechildFramesCountchildFramesNameclearCookiesclosecurrentFrameNamedeleteCookieevaluateevaluateAsyncevaluateJavaScriptgetPagegogoBackgoForwardincludeJsinjectJsopenopenUrlreleasereloadrenderrenderBase64sendEventsetContentstopswitchToChildFrameswitchToFocusedFrameswitchToFrameswitchToMainFrameswitchToParentFrameuploadFile

HANDLERS

onAlertonCallbackonClosingonConfirmonConsoleMessageonErroronFilePickeronInitializedonLoadFinishedonLoadStartedonNavigationRequestedonPageCreatedonPromptonResourceErroronResourceReceivedonResourceRequestedonResourceTimeoutonUrlChanged

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 = 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)

!!! 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))

RSpec Cucumber MiniTest

Capybara

Poltergeist

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)

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

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)

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

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

top related