Upload
provectus
View
282
Download
4
Tags:
Embed Size (px)
DESCRIPTION
Web Expert Day September 20, 2014 Kazan, Russia
Citation preview
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
За внимание спасибо