質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

表示しているページのサイズ(画面キャプチャのサイズ、もしくは類似のサイズ)をselenumの何かしらのクラスで取得する方法

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 3,596

tasuku

score 9

seleniumで、巨大なページの画面キャプチャを取得するとOutOfMemoryが発生してしまいます。
短時間で大量のJavaヒープを消費するためOutOfMemoryErrorになっているようなので、
巨大なページであればキャプチャを取らないように条件分岐させたいと思っています。

 そこで表示したページのサイズ(画面キャプチャのサイズ、もしくは類似のサイズ)をselenumの何かしらのクラスで取得する方法
をご存知な方いらっしゃいましたらお教え頂きたいです。

▼具体的な問題▼
具体的には、
http://backyard.imjp.co.jp/static/feed/atom.xml
を以下のコードで画面キャプチャを採取しようとするとOutOfMemoryが発生します。


▼キャプチャ採取のコード▼
                //取得したURLのスクリーンショット作成
                File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
                FileUtils.copyFile(scrFile, new File(scrFileName));

▼発生している例外▼
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.StringCoding.decode(StringCoding.java:215)
    at java.lang.String.<init>(String.java:451)
    at java.lang.String.<init>(String.java:503)
    at org.openqa.selenium.remote.http.HttpMessage.getContentString(HttpMessage.java:110)
    at org.openqa.selenium.remote.http.HttpResponse.getContentString(HttpResponse.java:1)
    at org.openqa.selenium.remote.http.JsonHttpResponseCodec.decode(JsonHttpResponseCodec.java:76)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:137)
    at org.openqa.selenium.firefox.internal.NewProfileExtensionConnection.execute(NewProfileExtensionConnection.java:170)
    at org.openqa.selenium.firefox.FirefoxDriver$LazyCommandExecutor.execute(FirefoxDriver.java:393)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:568)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:618)
    at org.openqa.selenium.firefox.FirefoxDriver.getScreenshotAs(FirefoxDriver.java:354)
    at sample.SandBox.main(SandBox.java:168)

▼試してみたけどダメだったこと▼
  1.  JVMの起動パラメータで、-Xms1024m、-Xmx1024mにした。
  2.  ファイルコピーをせずに一時ディレクトリでのキャプチャ採取のみにした。(FileUtils.copyFile(scrFile, new File(scrFileName)); をコメントアウト)

▼やりたいこと。質問▼
短時間で大量のJavaヒープを消費するためOutOfMemoryErrorになっているようなので、
巨大なページの画面キャプチャ採取をあきらめ、
巨大なページであればキャプチャを取らないように条件分岐させたいと思っています。

 そこで表示したページのサイズ(画面キャプチャのサイズ、もしくは類似のサイズ)をselenumの何かしらのクラスで取得する方法
をご存知の方はお教え頂きたいです。


  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

skyfishさんに伺った以下の方法でJSを動かしてスクロールするサイズを取得することで、
サイズの大きいページを判定することができました。
(実際には若干お教え頂いたコードとは異なってましたがそこは推測できる範囲なので大丈夫でしたw)
//skyfishさんに伺った方法
int scrollLength = Integer.parseInt(((JavascriptExecutor) driver).executeScript("return document.body.scrollHeight").toString());


ですが、JSを実行しなくても、selenium自体(org.openqa.selenium.Dimension)でスクロールした時のサイズが以下取れることがわかりました。
//selenium自体(org.openqa.selenium.Dimension)を使う方法
Dimension rootDomSize = driver.findElement(By.tagName("body")).getSize();
int height = rootDomSize.height;
int width = rootDomSize.width;

skyfishさんにお教え頂いた方法とorg.openqa.selenium.Dimensionを使う方法と値を比較してみましたが以下で一緒でした。

//2つの方法の値比較
    int scrollLength = Integer.parseInt(((JavascriptExecutor) driver).executeScript("return document.body.scrollHeight").toString());
    Dimension rootDomSize = driver.findElement(By.tagName("body")).getSize();
    System.out.println("height:"+rootDomSize.height+" width:"+rootDomSize.width+" scrollLength:"+scrollLength);

結果:
height:38780 width:1407 scrollLength:38780

中身は同じことしてるのかもしれませんが、一応JS呼び出すよりもJava内で実行できたほうがいいかなと思い、後者を使って以下のようにすることにしました。

                if (driver instanceof JavascriptExecutor) {
                    Dimension rootDomSize = driver.findElement(By.tagName("body")).getSize();
                    //長さが2万px以下の時はそのままスクリーンショットを撮る
                    if(rootDomSize.height  >= 20000){

                        //取得したURLのスクリーンショット作成
                        File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
                        FileUtils.copyFile(scrFile, new File(scrFileName));

                    }
                }

ただ、ちょっとこれだと逃げてる感があるので、
サイズの大きい画面では、画面サイズを小さくしてキャプチャを採取することにしました。

        //ウィンドウサイズを小さくする
        driver.manage().window().setSize(new Dimension(100,100));

結果は、成功しました!
ですが、画面サイズを元に戻さないと次のキャプチャ採取の時に、
小さいままになってしまうので、その辺りがちょっと面倒。。。

今度は、サイズの大きい画面では、
スクロールしないで表示されているところだけキャプチャするようにできないか試したく、
また質問しちゃってます↓
FirefoxDriverでスクロールさせないでキャプチャする方法

ということでアドバイスありがとうございました!!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

SeleniumというよりWebDriver側の機能ですが、
WebDriverに向けてjavascriptのコードを叩いて値を返してもらう事で実装できます。

int scrollLength = Integer.parseInt(webdriver.execute_script("return document.body.scrollHeight"));
System.out.println(scrollLength);
if(scrollLength < 100000){
 //長さが10万以下の時はスクリーンショットを撮る
}

上記のようにして得られたscrollLengthの値がいくら以下の時はSSを取る。
みたいに実装すると良いのではないでしょうか。

面白い内容だったので動くコードをgithubに残しました。rubySeleniumですが参考までに
https://github.com/Lyptica/seleniumScrollTest/blob/master/seleniumScroll.rb

参考:
Efficient method to scroll though pages using Selenium
http://stackoverflow.com/questions/19803963/efficient-method-to-scroll-though-pages-using-selenium

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/09 10:30

    おー。
    webdriverにjsを実行させるメソッドがあるんですね(webdriver.execute_script)
    本題とはちがったことが学べて得した気分です。

    早速試してみます。

    PS:Rubyも勉強しなくては。。。w

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • トップ
  • Javaに関する質問
  • 表示しているページのサイズ(画面キャプチャのサイズ、もしくは類似のサイズ)をselenumの何かしらのクラスで取得する方法