web-dev-qa-db-ja.com

ウェブサイトの信頼できるスクリーンショットを撮っていますか? PhantomjsとCasperjsの両方が一部のWebサイトで空のスクリーンショットを返す

Webページを開き、スクリーンショットを撮ります。

Phantomjsのみを使用:(これは単純なスクリプトですが、実際には、ドキュメントで使用されているスクリプトの例です。 http://phantomjs.org/screen-capture.html

var page = require('webpage').create();
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});

問題は、(githubのような)いくつかのWebサイトでは、おかしなことに、何らかの理由でファントムを検出してサービスを提供せず、何もレンダリングされないことです。結果はgithub.pngは空白の白いpngファイルです。

Githubをsay: "google.com"に置き換えると、意図したとおりのニース(適切な)スクリーンショットが得られます。

最初はこれがPhantomjsの問題だと思ったので、Casperjsで実行してみました:

casper.start('http://www.github.com/', function() {
    this.captureSelector('github.png', 'body');
});

casper.run();

しかし、私はPhantomjsと同じ動作をします

したがって、これはユーザーエージェントの問題である可能性が高いと考えました。のように:GithubはPhantomjsを嗅ぎ取り、ページを表示しないことを決定します。だから私は以下のようにユーザーエージェントを設定しましたが、それでもうまくいきませんでした。

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});

それで私はページを解析しようとしました、そしてどうやらいくつかのサイト(これもgithubのような)は何も送信していないようです。

Casperjsを使用して、タイトルを印刷してみました。そしてgoogle.comの場合はGoogleを返しましたが、github.comの場合はbupkisを返しました。コード例:

var casper = require('casper').create();

casper.start('http://github.com/', function() {
    this.echo(this.getTitle());
});

casper.run();  

上記と同じように、純粋にphantomjsでも同じ結果が生成されます。

更新:

これはタイミングの問題ですか? githubは非常に遅いのですか?疑わしいですが、とにかくテストしましょう。

var page = require('webpage').create();
page.open('http://github.com', function (status) {
    /* irrelevant */
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 3000);
});

そして結果はまだbupkisです。ですから、それはタイミングの問題ではありません。

  1. githubなどの一部のサイトはphantomjsをブロックしていますか?
  2. すべてのWebページのスクリーンショットを確実に撮るにはどうすればよいですか?高速でヘッドレスである必要があります。
24
fabbb

これをしばらくの間バウンスした後、私は問題を絞り込むことができました。どうやらPhantomJSはsslv3のデフォルトのsslを使用しているため、不正なsslハンドシェイクが原因でgithubが接続を拒否しています

phantomjs --debug=true github.js

次の出力を表示します。

. . .
2014-10-22T19:48:31 [DEBUG] WebPage - updateLoadingProgress: 10 
2014-10-22T19:48:32 [DEBUG] Network - Resource request error: 6 ( "SSL handshake failed" ) URL: "https://github.com/" 
2014-10-22T19:48:32 [DEBUG] WebPage - updateLoadingProgress: 100 

これから、githubが接続を拒否していたため、画面が取得されなかったと結論付けることができます。すばらしいことです。それでは、SSLフラグを--ssl-protocol=anyに設定し、--ignore-ssl-errors=trueでssl-errorsも無視してみましょう

phantomjs --ignore-ssl-errors=true --ssl-protocol=any --debug=true github.js

大成功です!スクリーンショットが適切にレンダリングおよび保存されていますが、デバッガーがTypeErrorを表示しています:

TypeError: 'undefined' is not a function (evaluating 'Array.prototype.forEach.call.bind(Array.prototype.forEach)')

  https://assets-cdn.github.com/assets/frameworks-dabc650f8a51dffd1d4376a3522cbda5536e4807e01d2a86ff7e60d8d6ee3029.js:29
  https://assets-cdn.github.com/assets/frameworks-dabc650f8a51dffd1d4376a3522cbda5536e4807e01d2a86ff7e60d8d6ee3029.js:29
2014-10-22T19:52:32 [DEBUG] WebPage - updateLoadingProgress: 72 
2014-10-22T19:52:32 [DEBUG] WebPage - updateLoadingProgress: 88 
ReferenceError: Can't find variable: $

  https://assets-cdn.github.com/assets/github-fa2f009761e3bc4750ed00845b9717b09646361cbbc3fa473ad64de9ca6ccf5b.js:1
  https://assets-cdn.github.com/assets/github-fa2f009761e3bc4750ed00845b9717b09646361cbbc3fa473ad64de9ca6ccf5b.js:1

TypeErrorが存在するかどうかを確認するために、githubホームページを手動で確認しました。

私の次の推測は、アセットが十分に速く読み込まれていないということです。Phantomjsはスピード違反の弾丸よりも高速です!

だから、それを人為的に遅くしてみて、そのTypeErrorを取り除くことができるかどうか見てみましょう...

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com', function (status) {
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 3000);
});

うまくいきませんでした...画像を詳しく調べたところ、一部の要素が欠けていることは明らかです。主にいくつかのアイコンとロゴ。

成功しましたか?部分的には、少なくとも以前はスクリーンショットを取得していたので、何も取得していませんでした。

仕事は終わりましたか?正確ではありません。 TypeErrorの原因を特定する必要があります。これにより、一部のアセットが画像を読み込んで変形するのを防ぐことができます。

追加

CasperJS --debugで再作成しようとすると、PhantomJSに比べて非常に醜く、追跡が困難です。

casper.start();
casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)');
casper.thenOpen('https://www.github.com/', function() {
    this.captureSelector('github.png', 'body');
});

casper.run();

コンソール:

casperjs test --ssl-protocol=any --debug=true github.js

さらに、画像には同じアイコンがありませんが、視覚的に歪んでいます。 CasperJsはPhantomjsに依存しているため、この特定のタスクにそれを使用することの価値はわかりません。

私の答えに追加したい場合は、発見事項を共有してください。完璧なPhantomJSソリューションに非常に興味がある

アップデート#1:TypeErrorの削除

@ArtjomBは、Phantomjsがこの更新(1.9.7)の現在のバージョンでjs bindをサポートしていないことを指摘しています。このため、彼は次のように説明しています。 ArtjomB:PhantomJs Bind Issue Answer

TypeError: 'undefined'は、PhantomJS 1.xがサポートしていないため、バインドを参照する関数ではありません。 PhantomJS 1.xは、QtWebkitの古いフォークを使用します。これは、Chrome 13またはSafari 5に相当します。新しいPhantomJS 2は、バインドをサポートする新しいエンジンを使用します。今のところ、 page.onInitializedイベントハンドラー内のシム:

わかりました。次のコードは、上からTypeErrorを処理します。 (ただし、完全には機能していません。詳細は以下を参照してください)

var page = require('webpage').create();
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36';
page.open('http://github.com', function (status) {
   window.setTimeout(function () {
            page.render('github.png');
            phantom.exit();
        }, 5000);
});
page.onInitialized = function(){
    page.evaluate(function(){
        var isFunction = function(o) {
          return typeof o == 'function';
        };

        var bind,
          slice = [].slice,
          proto = Function.prototype,
          featureMap;

        featureMap = {
          'function-bind': 'bind'
        };

        function has(feature) {
          var prop = featureMap[feature];
          return isFunction(proto[prop]);
        }

        // check for missing features
        if (!has('function-bind')) {
          // adapted from Mozilla Developer Network example at
          // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
          bind = function bind(obj) {
            var args = slice.call(arguments, 1),
              self = this,
              nop = function() {
              },
              bound = function() {
                return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
              };
            nop.prototype = this.prototype || {}; // Firefox cries sometimes if prototype is undefined
            bound.prototype = new nop();
            return bound;
          };
          proto.bind = bind;
        }
    });
}

これで、上記のコードは前と同じスクリーンショットを取得し、デバッグはTypeErrorを表示しないため、表面から見るとすべてが機能しているように見えます。進展が見られました。

残念ながら、すべての画像アイコン[ロゴなど]がまだ正しく読み込まれていません。ある種の3Wアイコンがどこから来たのかわかりません。

助けてくれてありがとう@ArtjomB

enter image description here

26
fabbb