Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

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

13.156 Aufrufe

Veröffentlicht am

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

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

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

×