Чрезвычайно простой код не работает в HtmlUnit

Я работаю с HtmlUnit 2.9 (стабильная версия, выпущенная в этом месяце). У вас есть идеи, почему следующий код не работает?

public class Main {

    public static void main(String[] args) {
        WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3_6);
        webClient.setCssEnabled(true);
        webClient.setCssErrorHandler(new SilentCssErrorHandler());
        webClient.setThrowExceptionOnFailingStatusCode(false);
        webClient.setThrowExceptionOnScriptError(false);
        webClient.setRedirectEnabled(false);
        webClient.setAppletEnabled(false);
        webClient.setJavaScriptEnabled(false);
        webClient.setPopupBlockerEnabled(true);
        webClient.setTimeout(60000);
        webClient.setPrintContentOnFailingStatusCode(false);

        System.out.println("This is printed on screen");
        try {
            webClient.getPage("http://www.2cash.info/index.php");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("This is NEVER printed on screen");
    }
}

Я также добавляю результат jstack. Обратите внимание, что я отметил раздел, который постоянно повторяется:

2011-08-26 03:15:45
Full thread dump Java HotSpot(TM) Server VM (20.1-b02 mixed mode):

"Attach Listener" daemon prio=10 tid=0x09520400 nid=0x5363 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"JS executor for com.gargoylesoftware.htmlunit.WebClient@a7c45e" daemon prio=10 tid=0x6feb7400 nid=0x5356 waiting on condition [0x6fcfe000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at com.gargoylesoftware.htmlunit.javascript.background.JavaScriptExecutor.run(JavaScriptExecutor.java:166)
    at java.lang.Thread.run(Thread.java:662)

"Low Memory Detector" daemon prio=10 tid=0x70204c00 nid=0x5352 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=10 tid=0x70202800 nid=0x5351 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=10 tid=0x70200800 nid=0x5350 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x09514c00 nid=0x534f runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x09503400 nid=0x534e in Object.wait() [0x70798000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x76af2ff0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x76af2ff0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x09501c00 nid=0x534d in Object.wait() [0x707e9000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x7675cc58> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x7675cc58> (a java.lang.ref.Reference$Lock)

"main" prio=10 tid=0x09482400 nid=0x5349 runnable [0xb6c34000]
   java.lang.Thread.State: RUNNABLE
    at net.sourceforge.htmlunit.corejs.javascript.ScriptableObject.getSlot(ScriptableObject.java:2603)
    at net.sourceforge.htmlunit.corejs.javascript.ScriptableObject.defineProperty(ScriptableObject.java:1699)
    at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.configureConstantsPropertiesAndFunctions(JavaScriptEngine.java:350)
    at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.configureClass(JavaScriptEngine.java:330)
    at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.init(JavaScriptEngine.java:199)
    at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.access$000(JavaScriptEngine.java:79)
    at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine$1.run(JavaScriptEngine.java:146)
    at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:537)
    at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:538)
    at com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine.initialize(JavaScriptEngine.java:157)
    at com.gargoylesoftware.htmlunit.WebClient.initialize(WebClient.java:1141)
    at com.gargoylesoftware.htmlunit.WebWindowImpl.setEnclosedPage(WebWindowImpl.java:109)
    at com.gargoylesoftware.htmlunit.html.FrameWindow.setEnclosedPage(FrameWindow.java:102)
    at com.gargoylesoftware.htmlunit.html.HTMLParser.parse(HTMLParser.java:200)
    at com.gargoylesoftware.htmlunit.html.HTMLParser.parseHtml(HTMLParser.java:179)
    at com.gargoylesoftware.htmlunit.DefaultPageCreator.createHtmlPage(DefaultPageCreator.java:221)
    at com.gargoylesoftware.htmlunit.DefaultPageCreator.createPage(DefaultPageCreator.java:106)
    at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseInto(WebClient.java:433)
    at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:311)
    at com.gargoylesoftware.htmlunit.html.BaseFrame.<init>(BaseFrame.java:73)
    at com.gargoylesoftware.htmlunit.html.HtmlInlineFrame.<init>(HtmlInlineFrame.java:46)
    at com.gargoylesoftware.htmlunit.html.DefaultElementFactory.createElementNS(DefaultElementFactory.java:288)
    at com.gargoylesoftware.htmlunit.html.HTMLParser$HtmlUnitDOMBuilder.startElement(HTMLParser.java:506)
    at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
    at org.cyberneko.html.HTMLTagBalancer.callStartElement(HTMLTagBalancer.java:1136)
    at org.cyberneko.html.HTMLTagBalancer.startElement(HTMLTagBalancer.java:742)
    at org.cyberneko.html.filters.DefaultFilter.startElement(DefaultFilter.java:136)
    at org.cyberneko.html.filters.NamespaceBinder.startElement(NamespaceBinder.java:278)
    at org.cyberneko.html.HTMLScanner$ContentScanner.scanStartElement(HTMLScanner.java:2652)
    at org.cyberneko.html.HTMLScanner$ContentScanner.scan(HTMLScanner.java:2022)
    at org.cyberneko.html.HTMLScanner.scanDocument(HTMLScanner.java:908)
    at org.cyberneko.html.HTMLConfiguration.parse(HTMLConfiguration.java:499)
    at org.cyberneko.html.HTMLConfiguration.parse(HTMLConfiguration.java:452)
    at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
    at com.gargoylesoftware.htmlunit.html.HTMLParser$HtmlUnitDOMBuilder.parse(HTMLParser.java:789)
    at com.gargoylesoftware.htmlunit.html.HTMLParser.parse(HTMLParser.java:225)
    at com.gargoylesoftware.htmlunit.html.HTMLParser.parseHtml(HTMLParser.java:179)
    at com.gargoylesoftware.htmlunit.DefaultPageCreator.createHtmlPage(DefaultPageCreator.java:221)
    at com.gargoylesoftware.htmlunit.DefaultPageCreator.createPage(DefaultPageCreator.java:106)
    at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseInto(WebClient.java:433)
    at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:311)

    <THIS_SECTION_IS_PRINTED_AS_IF_IT_WERE_IN_A_LOOP>
    at com.gargoylesoftware.htmlunit.html.BaseFrame.loadInnerPageIfPossible(BaseFrame.java:149)
    at com.gargoylesoftware.htmlunit.html.BaseFrame.loadInnerPage(BaseFrame.java:99)
    at com.gargoylesoftware.htmlunit.html.HtmlPage.loadFrames(HtmlPage.java:1760)
    at com.gargoylesoftware.htmlunit.html.HtmlPage.initialize(HtmlPage.java:194)
    at com.gargoylesoftware.htmlunit.WebClient.loadWebResponseInto(WebClient.java:440)
    at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:311)
    </THIS_SECTION_IS_PRINTED_AS_IF_IT_WERE_IN_A_LOOP>

    at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:311)
    at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:373)
    at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:358)
    at main.Main.<init>(Main.java:42)
    at main.Main.main(Main.java:23)

"VM Thread" prio=10 tid=0x094fe000 nid=0x534c runnable 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x09489800 nid=0x534a runnable 

"GC task thread#1 (ParallelGC)" prio=10 tid=0x0948ac00 nid=0x534b runnable 

"VM Periodic Task Thread" prio=10 tid=0x70207000 nid=0x5353 waiting on condition 

JNI global references: 1234

Я думаю, что есть какой-то цикл, касающийся автоматической загрузки кадров. Если это так, есть ли способ отключить это поведение, чтобы разорвать цикл?

Заранее спасибо!


person Mosty Mostacho    schedule 26.08.2011    source источник
comment
Вы используете Java7? Когда да, пробовали с Java6?   -  person Fabian Barney    schedule 26.08.2011
comment
Да: $ java -version версия java 1.6.0_26 Java(TM) SE Runtime Environment (сборка 1.6.0_26-b03) Java HotSpot(TM) Server VM (сборка 20.1-b02, смешанный режим)   -  person Mosty Mostacho    schedule 26.08.2011


Ответы (2)


Когда я открываю этот сайт в своем браузере, он никогда не заканчивает загрузку страницы. Это может быть причиной сбоя HtmlUnit. Протестировано с Chrome и FF.

Попробуйте вместо этого загрузить более простой сайт, и вы можете узнать, зависит ли этот сбой от сайта.

person Fabian Barney    schedule 26.08.2011
comment
Проверял только на ФФ 3.6. Как вы говорите, сайт почти зависает при загрузке моего компьютера. Однако учтите, что в моей конфигурации HtmlUnit отключен Javascript. Отключите его в своем браузере, и сайт загрузится. Кроме того, веб-страницы, которые я загружаю, являются динамическими, я имею в виду, что я получаю неизвестные ссылки с известной веб-страницы. Мне нужно иметь возможность перемещаться по любой ссылке без человеческого знания о том, какие из них не следует нажимать - person Mosty Mostacho; 26.08.2011
comment
Я запускаю NoScript (поэтому JavaScript не включен), и сайт загружается вечно... На самом деле он не зависает, но загрузка страницы никогда не заканчивается. Остановил после 30 секунд загрузки... - person Fabian Barney; 26.08.2011
comment
Я заметил, что страница загружается через 62 секунды на FF 3.6 и выполняет около 700 http-запросов. HtmlUnit должен справиться с этим, но это не так. Мне нужно только вернуть XML главной страницы без IFRAMES или даже выдать исключение или тайм-аут или что-то в этом роде. Но не текущее поведение: повесить процесс Java, съесть мой процессор и расплавить мое оборудование :) Я думаю, что такой метод, как webClient.getPageWithoutFrames(URL), будет решением. - person Mosty Mostacho; 26.08.2011

Что ж, хотя это ужасное решение (на самом деле обходной путь...), я наконец решил отключить автоматическую загрузку фреймов в HtmlUnit, как посоветовал один из разработчиков HtmlUnit. Вот что я сделал подробно:

  1. Скачал исходный код HtmlUnit
  2. Скачанный maven из здесь
  3. Прокомментировано содержимое (тело метода, а не объявление) метода loadFrames() класса HtmlPage, расположенного в htmlunit-2.9/src/main/java/com/gargoylesoftware/htmlunit/html.
  4. Скомпилировал этот пользовательский код, пропуская тесты с: mvn -Dmaven.test.skip=true clean compile package
  5. Получил новый htmlunit-2.9.jar, расположенный в htmlunit-2.9/artifacts, и заменил текущий файл библиотеки htmlunit-2.9.jar
  6. Этот шаг может быть самым деликатным, поскольку он будет зависеть от каждого приложения. Однако я покажу вам изменения, которые мне нужно было внести в мое приложение.

Вы знаете, каким был мой исходный код (посмотрите на вопрос). Это загрузило бы все фреймы и фреймы со страницы. Я добавляю пример того, как получить страницу с фреймами, просто загружая нужные фреймы:

try {
    HtmlPage page = webClient.getPage("http://www.w3schools.com/HTML/tryit.asp?filename=tryhtml_noframes");
    HtmlInlineFrame frame = page.getFirstByXPath("//iframe[@name='view']");
    page = webClient.getPage(page.getFullyQualifiedUrl(frame.getSrcAttribute()));
    System.out.println(page.asXml());
} catch (Exception e) {
    e.printStackTrace();
}

После этого изменения библиотеки содержимое фрейма будет пустым после завершения метода getPage(). Обратите внимание, что он не будет нулевым, похоже, он просто возвращает пустой кадр. Что нам нужно сделать, так это загрузить содержимое интересующих нас кадров вручную, поэтому я снова выполняю getPage().

Вот как мне удалось выборочно загружать фреймы и фреймы с помощью HtmlUnit. Любые идеи о том, как улучшить это, будут оценены. В любом случае, я надеюсь, что в будущем будет добавлен какой-то способ отключить загрузку фреймов в самом HtmlUnit, возможно, добавление метода, такого как getPage(URL url, boolean downloadFrames) или что-то в этом роде.

Надеюсь, это поможет кому-то там!

person Mosty Mostacho    schedule 27.08.2011
comment
Обновление: этот обходной путь также работает в HtmlUnit 2.10, 2.11 и 2.12. - person Mosty Mostacho; 16.03.2013