Wight: Phantom’s Perl friend - YAPC::Asia 2012
Upcoming SlideShare
Loading in...5
×
 

Wight: Phantom’s Perl friend - YAPC::Asia 2012

on

  • 5,673 views

A Perl implementation which manipulates phantomjs from Perl's side.

A Perl implementation which manipulates phantomjs from Perl's side.

Statistics

Views

Total Views
5,673
Views on SlideShare
4,222
Embed Views
1,451

Actions

Likes
10
Downloads
10
Comments
0

9 Embeds 1,451

http://subtech.g.hatena.ne.jp 1178
http://yapcasia.org 252
https://twitter.com 10
http://webcache.googleusercontent.com 3
http://twitter.com 2
https://si0.twimg.com 2
http://subtech.gstable.hatena.ne.jp 2
https://www.google.co.jp 1
http://party4r.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • ぽえ\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • HTMLのレンダリングやJavaScriptの解釈・実行などをおこなってくれるオープンソースのエンジンです\n
  • \n
  • \n
  • 特徴的な点はバイナリひとつが配られていること\n
  • もちろん GUI なし\n
  • これを Perl から使わない手はない、と\n
  • \n
  • \n
  • \n
  • \n
  • これはGoogleを検索する例です\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • その他のよく使うメソッドとしては、スクリーンショットを画像ファイルに書き出すrender\nこうして見ると、ちゃんと内部では要素の配置などが行われているのがわかる\n
  • \n
  • \n
  • JS の要る面倒なところだけ PhantomJS を使って、Mechanize あとは頼んだというようなことができます\n
  • \n
  • \n
  • \n
  • インターネット上のサーバにアクセスせず、内部でアクセスを閉じたい場合に\nfork は Twiggy 以外のサーバを使いたいときなど\ntwiggy を使うとリクエストされた $env をテスト内からそのまま参照できます\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • phantomjs を起動して WebSocket 接続が確立するまで sleep します\n
  • Wight のほとんどの API は この call というのを経由します\n
  • 待ち受けた poltergeist では、phantomjs の API を叩いてウェブページの操作や情報取得をおこないます\n
  • Perl 側からアクションするのではなくページ側からイベントが飛んでくるような場合\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Wight: Phantom’s Perl friend - YAPC::Asia 2012 Wight: Phantom’s Perl friend - YAPC::Asia 2012 Presentation Transcript

  • Perl でファントムする! 改めWight - Phantoms new friend YAPC::Asia 2012 motemen
  • About myself• 株式会社はてな• id:motemen • github:motemen • cpan:MOTEMEN  - App::htmlcat - AnyEvent::DAAP::Server • twitter:美顔器
  • Perl で楽しいこと1.スクレイピングする2.ウェブサービスを作る3.その他
  • スクレイピングはみんな好き• WWW::Mechanize• Web::Scraper• Web::Query• Plagger
  • 近年の JavaScript の隆盛
  • PhantomJS テキスト
  • PhantomJS• Ariya Hidayat 氏• できること- インターネット テキスト- ただし見えない
  • PhantomJS“PhantomJS is a headless WebKit withJavaScript API. It has fast and nativesupport for various web standards:DOM handling, CSS selector, JSON,Canvas, and SVG.” — http://phantomjs.org/
  • PhantomJS“PhantomJS is a headless WebKit withJavaScript API. It has fast and nativesupport for various web standards:DOM handling, CSS selector, JSON,Canvas, and SVG.” — http://phantomjs.org/
  • WebKit• Web レンダリングエンジン - HTML, JavaScript, … • Safari / Chrome
  • Headless• ユーザ向けの(目に見える)インター フェースなし
  • JavaScript API var page = require(webpage).create(); var url = http://www.phantomjs.org/; page.open(url, function (status) { //Page is loaded! phantom.exit(); });• PhantomJS の JS API でブラウジング - new WebPage() • Web ページとは別のコンテキストで実行
  • インストール    _   (  ・ω・) _(__つ/ ̄ ̄ ̄/   \/   /      ̄ ̄ ̄\          \┗(^o^ )┛┗(^o^ )┛┗(^o^ )┛  ┗( ^o^)┛           \┏┗   ┏┗   ┏┗      ┛┓             ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄• バイナリ- phantomjs.org/download.html • brew install phantomjs
  • 使う
  • PhantomJS is for…• Scraping• JavaScript testing• Network monitorning
  • “Wight”
  • “Wight”"Wight is a Middle English word, fromOld English wiht, and used to describe acreature or living sentient being. It isakin to Old High German wiht, meaninga creature or thing."
  • キラキラネームの理由(わけ)• CasperJS (JavaScript)• Poltergeist (Ruby)• GhostDriver (JavaScript)• …etc
  • SYNOPSIS use Wight; my $w = Wight->new; $w->visit(https://www.google.com/); $w->find(//input[@name="q"])->set(motemen); $w->find(//input[@type="submit"])->click(); foreach ($w->find(//h3[@class="r"]/a)) { say * , $_->text; }
  • Wight->new use Wight; my $w = Wight->new; $w->visit(https://www.google.com/);•PhantomJS を起動 $w->find(//input[@name="q"])->set(motemen); $w->find(//input[@type="submit"])->click();•通信を確立 foreach ($w->find(//h3[@class="r"]/a)) { say * , $_->text; }
  • $w->visit($url) use Wight; my $w = Wight->new; $w->visit(https://www.google.com/); $w->find(//input[@name="q"])->set(motemen); $w->find(//input[@type="submit"])->click();•URL を開く foreach ($w->find(//h3[@class="r"]/a)) { say * , $_->text; }
  • $node = $w->find($xpath)@nodes = $w->find($xpath) use Wight;•XPathWight->new; my $w = でページ内の要素へアクセス $w->visit(https://www.google.com/); $w->find(//input[@name="q"])->set(motemen); $w->find(//input[@type="submit"])->click(); foreach ($w->find(//h3[@class="r"]/a)) { say * , $_->text; }
  • $node->set($value)•要素の値を設定 use Wight;•あわせてキーイベントも発生(!) my $w = Wight->new; $w->visit(https://www.google.com/); $w->find(//input[@name="q"])->set(motemen); $w->find(//input[@type="submit"])->click(); foreach ($w->find(//h3[@class="r"]/a)) { say * , $_->text; }
  • $node->click()•要素をクリック use Wight; my $w = Wight->new;•クリックできない場所にあったらエラー $w->visit(https://www.google.com/); $w->find(//input[@name="q"])->set(motemen); $w->find(//input[@type="submit"])->click(); foreach ($w->find(//h3[@class="r"]/a)) { say * , $_->text; }
  • $w->render($filename)
  • $w->evaluate($JavaScript) $w->evaluate(document.title); # => "はてな" $w->evaluate(document.body.getBoundingClientRect()) # { # bottom => 1363, # height => 1363, # left => 0, # right => 1024, # top => 0, # width => 1024 # }
  • $w->execute($JavaScript) $w->execute(<<JAVASCRIPT); var nodes = document.querySelectorAll(img); [].slice.call(nodes).forEach(function () { … }); JAVASCRIPT # => JSON::XS::true
  • $w->cookie_jar• PhantomJS Perl でクッキー受け渡し• HTTP::Cookies my $w = Wight->new(cookie => 1); some_complicated_authentication(); my $cookie_jar = $w->reload_cookie_jar; my $ua = LWP::UserAgent->new( cookie_jar => $cookie_jar ); usual_downloading_routine();
  • •$w->body•$w->source•$w->current_url•$node->visible•$node->attribute($name)•$node->value•etc…
  • Testing
  • Test::Wight my $w = Test::Wight->new; my $port = $w->spawn_psgi($app); $w->visit(/); is $w->evaluate(document.title), title; my $link = $wight->find(//p/a) $link->click; is $w->current_url->path, /foo;
  • Test::Wight• 内部でアクセスを閉じたい場合に• $port = $w->spawn_psgi($app)  - ‘fork’ or ‘twiggy’
  • Why Perl?• コールバックのない平坦なコードに• CPAN モジュールの再利用 - LWP family  - Coro による並列化• Perl アプリケーションからの利用• prove したい
  • Example
  • Tumblr dashboard• “J” キーの押下をエミュレート• img 要素の href を取得• (ダウンロード)は Perl に任せる
  • IMPLEMENTATION
  • Uses Poltergeistgithub.com/jonleighton/poltergeist
  • Poltergeist• “A PhantomJS driver for Capybara” • Jon Leighton 氏• これの JavaScript を流用• ルビースト最高!
  • 出演者• ( ╹◡╹) Perl• (´⊙ω⊙) PhantomJS• ( ˘ω˘) Page Content
  • Perl PhantomJS• Wight->new  - Twiggy を起動 - PhantomJS を起動 - WebSocket 接続を待つ• connection.js this.socket = new WebSocket("ws://127.0.0.1:" + this.port + "/"); this.socket.onmessage = this.commandReceived;
  • Perl PhantomJS• $w->call($method, @args)  - WebSocket メッセージを送信 - $cv->recv してじっと待つ• main.js / browser.js  - 結果 (エラー) が出しだい返答 - リンクのクリックの場合 URL が変わるまで
  • PhantomJS Page Content• browser.js, web_page.js  - Perl 側から来た要求を実行• agent.js をページ内に埋め込み- 要素の発見- イベントの発生
  • コールバック// in PhantomJSpage.onPrompt = function () { return answer;};• 関数の返り値がユーザの返答代わり
  • コールバック• 非同期な通信は使えない - WebSocket × - Ajax × - Synchronous XMLHttpRequest ○ • ふつうに HTTP リクエストをさばく$w->on_confirm(sub { my ($w, @args) = @_; return rand() < 0.5;});
  • TODO• Mechanize 等との連携• フレーム対応 - PhantomJS 1.7 ∼• poltergeist に pull-req- (ルビーストになりたい)
  • おまけ
  • jQuery (☝◞‸◟)☝…$w->evaluate($("img").attr("src"));
  • jQuery └( ^ω^ )」♪$w->evaluate(jQuery(img)->attr(src));
  • Wight::jQuery
  • SYNOPSISjQuery; # => $jQuery(#foo); # => $("#foo")jQuery(#foo)->val(); # => $("#foo").val()jQuery(#foo)->val(23); # => $("#foo").val(23)jQuery(document); # => $(document)jQuery->ajax({ method => POST });# => $.ajax({"method":"POST"})• 文字列化すると jQuery の式に• それっぽいメソッドチェーン
  • プロパティ/コールバックjQuery(body)->position().left;# => $("body").position().leftjQuery(body)->click(sub { e => console.log(e); return false});# => $("body").click(function (e){ console.log(e); return false })
  • まとめ• PhantomJS • Wight - スクレイピングやテストに使えます- API と実装の紹介
  • github.com/motemen/Wight