狠狠撸

狠狠撸Share a Scribd company logo
Perl でファントムする! 改め

Wight - Phantom's
   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 の隆盛
Wight: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012
PhantomJS
    テキスト
PhantomJS
? Ariya Hidayat 氏
? できること
- インターネット       テキスト



- ただし見えない
PhantomJS
“PhantomJS is a headless WebKit with
JavaScript API. It has fast and native
support for various web standards:
DOM handling, CSS selector, JSON,
Canvas, and SVG.”
                    — http://phantomjs.org/
PhantomJS
“PhantomJS is a headless WebKit with
JavaScript API. It has fast and native
support 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: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012
“奥颈驳丑迟”
"Wight is a Middle English word, from
Old English wiht, and used to describe a
creature or living sentient being. It is
akin to Old High German wiht, meaning
a 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
Wight: Phantom’s Perl friend - YAPC::Asia 2012
Wight: Phantom’s Perl friend - YAPC::Asia 2012
Tumblr dashboard
? “J” キーの押下をエミュレート
? img 要素の href を取得
? (ダウンロード)は Perl に任せる
IMPLEMENTATION
Uses Poltergeist
github.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 PhantomJS
page.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
SYNOPSIS
jQuery; # => '$'

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().left'

jQuery('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

More Related Content

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

Editor's Notes

  1. &amp;#x307D;&amp;#x3048;\n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. HTML&amp;#x306E;&amp;#x30EC;&amp;#x30F3;&amp;#x30C0;&amp;#x30EA;&amp;#x30F3;&amp;#x30B0;&amp;#x3084;JavaScript&amp;#x306E;&amp;#x89E3;&amp;#x91C8;&amp;#x30FB;&amp;#x5B9F;&amp;#x884C;&amp;#x306A;&amp;#x3069;&amp;#x3092;&amp;#x304A;&amp;#x3053;&amp;#x306A;&amp;#x3063;&amp;#x3066;&amp;#x304F;&amp;#x308C;&amp;#x308B;&amp;#x30AA;&amp;#x30FC;&amp;#x30D7;&amp;#x30F3;&amp;#x30BD;&amp;#x30FC;&amp;#x30B9;&amp;#x306E;&amp;#x30A8;&amp;#x30F3;&amp;#x30B8;&amp;#x30F3;&amp;#x3067;&amp;#x3059;\n
  15. \n
  16. \n
  17. &amp;#x7279;&amp;#x5FB4;&amp;#x7684;&amp;#x306A;&amp;#x70B9;&amp;#x306F;&amp;#x30D0;&amp;#x30A4;&amp;#x30CA;&amp;#x30EA;&amp;#x3072;&amp;#x3068;&amp;#x3064;&amp;#x304C;&amp;#x914D;&amp;#x3089;&amp;#x308C;&amp;#x3066;&amp;#x3044;&amp;#x308B;&amp;#x3053;&amp;#x3068;\n
  18. &amp;#x3082;&amp;#x3061;&amp;#x308D;&amp;#x3093; GUI &amp;#x306A;&amp;#x3057;\n
  19. &amp;#x3053;&amp;#x308C;&amp;#x3092; Perl &amp;#x304B;&amp;#x3089;&amp;#x4F7F;&amp;#x308F;&amp;#x306A;&amp;#x3044;&amp;#x624B;&amp;#x306F;&amp;#x306A;&amp;#x3044;&amp;#x3001;&amp;#x3068;\n
  20. \n
  21. \n
  22. \n
  23. \n
  24. &amp;#x3053;&amp;#x308C;&amp;#x306F;Google&amp;#x3092;&amp;#x691C;&amp;#x7D22;&amp;#x3059;&amp;#x308B;&amp;#x4F8B;&amp;#x3067;&amp;#x3059;\n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. &amp;#x305D;&amp;#x306E;&amp;#x4ED6;&amp;#x306E;&amp;#x3088;&amp;#x304F;&amp;#x4F7F;&amp;#x3046;&amp;#x30E1;&amp;#x30BD;&amp;#x30C3;&amp;#x30C9;&amp;#x3068;&amp;#x3057;&amp;#x3066;&amp;#x306F;&amp;#x3001;&amp;#x30B9;&amp;#x30AF;&amp;#x30EA;&amp;#x30FC;&amp;#x30F3;&amp;#x30B7;&amp;#x30E7;&amp;#x30C3;&amp;#x30C8;&amp;#x3092;&amp;#x753B;&amp;#x50CF;&amp;#x30D5;&amp;#x30A1;&amp;#x30A4;&amp;#x30EB;&amp;#x306B;&amp;#x66F8;&amp;#x304D;&amp;#x51FA;&amp;#x3059;render\n&amp;#x3053;&amp;#x3046;&amp;#x3057;&amp;#x3066;&amp;#x898B;&amp;#x308B;&amp;#x3068;&amp;#x3001;&amp;#x3061;&amp;#x3083;&amp;#x3093;&amp;#x3068;&amp;#x5185;&amp;#x90E8;&amp;#x3067;&amp;#x306F;&amp;#x8981;&amp;#x7D20;&amp;#x306E;&amp;#x914D;&amp;#x7F6E;&amp;#x306A;&amp;#x3069;&amp;#x304C;&amp;#x884C;&amp;#x308F;&amp;#x308C;&amp;#x3066;&amp;#x3044;&amp;#x308B;&amp;#x306E;&amp;#x304C;&amp;#x308F;&amp;#x304B;&amp;#x308B;\n
  31. \n
  32. \n
  33. JS &amp;#x306E;&amp;#x8981;&amp;#x308B;&amp;#x9762;&amp;#x5012;&amp;#x306A;&amp;#x3068;&amp;#x3053;&amp;#x308D;&amp;#x3060;&amp;#x3051; PhantomJS &amp;#x3092;&amp;#x4F7F;&amp;#x3063;&amp;#x3066;&amp;#x3001;Mechanize &amp;#x3042;&amp;#x3068;&amp;#x306F;&amp;#x983C;&amp;#x3093;&amp;#x3060;&amp;#x3068;&amp;#x3044;&amp;#x3046;&amp;#x3088;&amp;#x3046;&amp;#x306A;&amp;#x3053;&amp;#x3068;&amp;#x304C;&amp;#x3067;&amp;#x304D;&amp;#x307E;&amp;#x3059;\n
  34. \n
  35. \n
  36. \n
  37. &amp;#x30A4;&amp;#x30F3;&amp;#x30BF;&amp;#x30FC;&amp;#x30CD;&amp;#x30C3;&amp;#x30C8;&amp;#x4E0A;&amp;#x306E;&amp;#x30B5;&amp;#x30FC;&amp;#x30D0;&amp;#x306B;&amp;#x30A2;&amp;#x30AF;&amp;#x30BB;&amp;#x30B9;&amp;#x305B;&amp;#x305A;&amp;#x3001;&amp;#x5185;&amp;#x90E8;&amp;#x3067;&amp;#x30A2;&amp;#x30AF;&amp;#x30BB;&amp;#x30B9;&amp;#x3092;&amp;#x9589;&amp;#x3058;&amp;#x305F;&amp;#x3044;&amp;#x5834;&amp;#x5408;&amp;#x306B;\nfork &amp;#x306F; Twiggy &amp;#x4EE5;&amp;#x5916;&amp;#x306E;&amp;#x30B5;&amp;#x30FC;&amp;#x30D0;&amp;#x3092;&amp;#x4F7F;&amp;#x3044;&amp;#x305F;&amp;#x3044;&amp;#x3068;&amp;#x304D;&amp;#x306A;&amp;#x3069;\ntwiggy &amp;#x3092;&amp;#x4F7F;&amp;#x3046;&amp;#x3068;&amp;#x30EA;&amp;#x30AF;&amp;#x30A8;&amp;#x30B9;&amp;#x30C8;&amp;#x3055;&amp;#x308C;&amp;#x305F; $env &amp;#x3092;&amp;#x30C6;&amp;#x30B9;&amp;#x30C8;&amp;#x5185;&amp;#x304B;&amp;#x3089;&amp;#x305D;&amp;#x306E;&amp;#x307E;&amp;#x307E;&amp;#x53C2;&amp;#x7167;&amp;#x3067;&amp;#x304D;&amp;#x307E;&amp;#x3059;\n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. phantomjs &amp;#x3092;&amp;#x8D77;&amp;#x52D5;&amp;#x3057;&amp;#x3066; WebSocket &amp;#x63A5;&amp;#x7D9A;&amp;#x304C;&amp;#x78BA;&amp;#x7ACB;&amp;#x3059;&amp;#x308B;&amp;#x307E;&amp;#x3067; sleep &amp;#x3057;&amp;#x307E;&amp;#x3059;\n
  49. Wight &amp;#x306E;&amp;#x307B;&amp;#x3068;&amp;#x3093;&amp;#x3069;&amp;#x306E; API &amp;#x306F; &amp;#x3053;&amp;#x306E; call &amp;#x3068;&amp;#x3044;&amp;#x3046;&amp;#x306E;&amp;#x3092;&amp;#x7D4C;&amp;#x7531;&amp;#x3057;&amp;#x307E;&amp;#x3059;\n
  50. &amp;#x5F85;&amp;#x3061;&amp;#x53D7;&amp;#x3051;&amp;#x305F; poltergeist &amp;#x3067;&amp;#x306F;&amp;#x3001;phantomjs &amp;#x306E; API &amp;#x3092;&amp;#x53E9;&amp;#x3044;&amp;#x3066;&amp;#x30A6;&amp;#x30A7;&amp;#x30D6;&amp;#x30DA;&amp;#x30FC;&amp;#x30B8;&amp;#x306E;&amp;#x64CD;&amp;#x4F5C;&amp;#x3084;&amp;#x60C5;&amp;#x5831;&amp;#x53D6;&amp;#x5F97;&amp;#x3092;&amp;#x304A;&amp;#x3053;&amp;#x306A;&amp;#x3044;&amp;#x307E;&amp;#x3059;\n
  51. Perl &amp;#x5074;&amp;#x304B;&amp;#x3089;&amp;#x30A2;&amp;#x30AF;&amp;#x30B7;&amp;#x30E7;&amp;#x30F3;&amp;#x3059;&amp;#x308B;&amp;#x306E;&amp;#x3067;&amp;#x306F;&amp;#x306A;&amp;#x304F;&amp;#x30DA;&amp;#x30FC;&amp;#x30B8;&amp;#x5074;&amp;#x304B;&amp;#x3089;&amp;#x30A4;&amp;#x30D9;&amp;#x30F3;&amp;#x30C8;&amp;#x304C;&amp;#x98DB;&amp;#x3093;&amp;#x3067;&amp;#x304F;&amp;#x308B;&amp;#x3088;&amp;#x3046;&amp;#x306A;&amp;#x5834;&amp;#x5408;\n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n