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

11,962
-1

Published on

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

Published in: Technology
0 Comments
10 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
11,962
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
14
Comments
0
Likes
10
Embeds 0
No embeds

No notes for slide
  • ぽえ\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

    1. 1. Perl でファントムする! 改めWight - Phantoms new friend YAPC::Asia 2012 motemen
    2. 2. About myself• 株式会社はてな• id:motemen • github:motemen • cpan:MOTEMEN  - App::htmlcat - AnyEvent::DAAP::Server • twitter:美顔器
    3. 3. Perl で楽しいこと1.スクレイピングする2.ウェブサービスを作る3.その他
    4. 4. スクレイピングはみんな好き• WWW::Mechanize• Web::Scraper• Web::Query• Plagger
    5. 5. 近年の JavaScript の隆盛
    6. 6. PhantomJS テキスト
    7. 7. PhantomJS• Ariya Hidayat 氏• できること- インターネット テキスト- ただし見えない
    8. 8. 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/
    9. 9. 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/
    10. 10. WebKit• Web レンダリングエンジン - HTML, JavaScript, … • Safari / Chrome
    11. 11. Headless• ユーザ向けの(目に見える)インター フェースなし
    12. 12. 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 ページとは別のコンテキストで実行
    13. 13. インストール    _   (  ・ω・) _(__つ/ ̄ ̄ ̄/   \/   /      ̄ ̄ ̄\          \┗(^o^ )┛┗(^o^ )┛┗(^o^ )┛  ┗( ^o^)┛           \┏┗   ┏┗   ┏┗      ┛┓             ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄• バイナリ- phantomjs.org/download.html • brew install phantomjs
    14. 14. 使う
    15. 15. PhantomJS is for…• Scraping• JavaScript testing• Network monitorning
    16. 16. “Wight”
    17. 17. “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."
    18. 18. キラキラネームの理由(わけ)• CasperJS (JavaScript)• Poltergeist (Ruby)• GhostDriver (JavaScript)• …etc
    19. 19. 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; }
    20. 20. 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; }
    21. 21. $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; }
    22. 22. $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; }
    23. 23. $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; }
    24. 24. $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; }
    25. 25. $w->render($filename)
    26. 26. $w->evaluate($JavaScript) $w->evaluate(document.title); # => "はてな" $w->evaluate(document.body.getBoundingClientRect()) # { # bottom => 1363, # height => 1363, # left => 0, # right => 1024, # top => 0, # width => 1024 # }
    27. 27. $w->execute($JavaScript) $w->execute(<<JAVASCRIPT); var nodes = document.querySelectorAll(img); [].slice.call(nodes).forEach(function () { … }); JAVASCRIPT # => JSON::XS::true
    28. 28. $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();
    29. 29. •$w->body•$w->source•$w->current_url•$node->visible•$node->attribute($name)•$node->value•etc…
    30. 30. Testing
    31. 31. 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;
    32. 32. Test::Wight• 内部でアクセスを閉じたい場合に• $port = $w->spawn_psgi($app)  - ‘fork’ or ‘twiggy’
    33. 33. Why Perl?• コールバックのない平坦なコードに• CPAN モジュールの再利用 - LWP family  - Coro による並列化• Perl アプリケーションからの利用• prove したい
    34. 34. Example
    35. 35. Tumblr dashboard• “J” キーの押下をエミュレート• img 要素の href を取得• (ダウンロード)は Perl に任せる
    36. 36. IMPLEMENTATION
    37. 37. Uses Poltergeistgithub.com/jonleighton/poltergeist
    38. 38. Poltergeist• “A PhantomJS driver for Capybara” • Jon Leighton 氏• これの JavaScript を流用• ルビースト最高!
    39. 39. 出演者• ( ╹◡╹) Perl• (´⊙ω⊙) PhantomJS• ( ˘ω˘) Page Content
    40. 40. 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;
    41. 41. Perl PhantomJS• $w->call($method, @args)  - WebSocket メッセージを送信 - $cv->recv してじっと待つ• main.js / browser.js  - 結果 (エラー) が出しだい返答 - リンクのクリックの場合 URL が変わるまで
    42. 42. PhantomJS Page Content• browser.js, web_page.js  - Perl 側から来た要求を実行• agent.js をページ内に埋め込み- 要素の発見- イベントの発生
    43. 43. コールバック// in PhantomJSpage.onPrompt = function () { return answer;};• 関数の返り値がユーザの返答代わり
    44. 44. コールバック• 非同期な通信は使えない - WebSocket × - Ajax × - Synchronous XMLHttpRequest ○ • ふつうに HTTP リクエストをさばく$w->on_confirm(sub { my ($w, @args) = @_; return rand() < 0.5;});
    45. 45. TODO• Mechanize 等との連携• フレーム対応 - PhantomJS 1.7 ∼• poltergeist に pull-req- (ルビーストになりたい)
    46. 46. おまけ
    47. 47. jQuery (☝◞‸◟)☝…$w->evaluate($("img").attr("src"));
    48. 48. jQuery └( ^ω^ )」♪$w->evaluate(jQuery(img)->attr(src));
    49. 49. Wight::jQuery
    50. 50. 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 の式に• それっぽいメソッドチェーン
    51. 51. プロパティ/コールバック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 })
    52. 52. まとめ• PhantomJS • Wight - スクレイピングやテストに使えます- API と実装の紹介
    53. 53. github.com/motemen/Wight
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×