JavaFX webview を使用して Web スクレイパーを開発しています。スクレイピングの目的で、画像をロードする必要はありません。ページが読み込まれると、Webkit は多数の UrlLoader スレッドを生成します。したがって、イメージを無効にした方がよいと思います。そのため、多くのシステム リソースを節約できます。Webview での自動画像読み込みを無効にする方法を知っている人はいますか?
2 に答える
ソリューションアプローチ
http用に独自のプロトコルハンドラーを定義し、画像のmimeタイプまたはコンテンツを含むものをすべて除外します。
URL.setURLStreamHandlerFactory(new HandlerFactory());
サンプルコード
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.web.*;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.*;
public class LynxView extends Application {
private static final String BLANK_IMAGE_LOC =
"https://upload.wikimedia.org/wikipedia/commons/c/ce/Transparent.gif";
public static final String WEBSITE_LOC =
"http://fxexperience.com";
public static final String IMAGE_MIME_TYPE_PREFIX =
"image/";
@Override
public void start(Stage stage) throws Exception {
WebView webView = new WebView();
WebEngine engine = webView.getEngine();
engine.load(WEBSITE_LOC);
stage.setScene(new Scene(new StackPane(webView)));
stage.show();
}
public static void main(String[] args) throws IOException {
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("http".equals(protocol)) {
return new sun.net.www.protocol.http.Handler() {
@Override
protected URLConnection openConnection(URL url, Proxy proxy) throws IOException {
String[] fileParts = url.getFile().split("\\?");
String contentType = URLConnection.guessContentTypeFromName(fileParts[0]);
// this small hack is required because, weirdly, svg is not picked up by guessContentTypeFromName
// because, for Java 8, svg is not in $JAVA_HOME/lib/content-types.properties
if (fileParts[0].endsWith(".svg")) {
contentType = "image/svg";
}
System.out.println(url.getFile() + " : " + contentType);
if ((contentType != null && contentType.startsWith(IMAGE_MIME_TYPE_PREFIX))) {
return new URL(BLANK_IMAGE_LOC).openConnection();
} else {
return super.openConnection(url, proxy);
}
}
};
}
return null;
}
});
Application.launch();
}
}
サンプルノート
このサンプルでは、次の概念を使用しています。
サンプルはファイル名をプローブするだけでコンテンツタイプを判別し、URLに添付された入力ストリームは判別しません。入力ストリームをプローブすることは、URLが接続されているリソースが実際に画像であるかどうかを判断するためのより正確な方法ですが、ストリームをプローブすることはわずかに効率が低いため、提示されたソリューションは精度と効率を交換します。
提供されるソリューションは、httpプロトコルによって提供される場所のみを示し、httpsプロトコルによって提供される場所は示しません。
提供されているソリューションは、Java 9では公開されていない可能性のあるsun.net.www.protocol.http.Handlerクラスを使用しています(したがって、ソリューションはJava 9では機能しない可能性があります)。
urlStreamHandlerFactoryはJVMのグローバル設定であるため、一度設定すると、その状態が維持されます(たとえば、java.net.URL接続のすべてのイメージは無視されます)。
サンプルソリューションは、空白の(透明な)画像を返し、それをネット上にロードします。効率を上げるために、画像はネット経由ではなく、クラスパスからリソースとしてロードできます。
空白の画像への接続ではなく、null接続を返すことができます。そうすると、Webビューコードは、期待するURL接続を取得していないため、コンソールへのnullポインター例外の報告を開始し、すべての画像を置き換えます。 x画像を使用して、画像が欠落していることを示します(null接続を返すアプローチはお勧めしません)。
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("http".equals(protocol)) {
return new URLFortuneHandler();
}
else return null;
}
}
public class URLFortuneHandler extends sun.net.www.protocol.http.Handler {
protected URLConnection openConnection(URL url) throws IOException {
String file = url.getFile();
int mid= file.lastIndexOf(".");
String ext = file.substring(mid+1,file.length());
if ("jpg".equals(ext) || "png".equals(ext))
return somethinghere;
else
return super.openConnection(url);
}
}