Crawler4jのガイド

  • Java

  • link:/category/programming/ [プログラミング]

1. 前書き

お気に入りの検索エンジンを使用するたびに、Webクローラーが使用されていることがわかります。 また、Webサイトからデータをスクレイピングおよび分析するためにもよく使用されます。
このチュートリアルでは、https://github.com/yasserg/crawler4j [crawler4j]を使用して独自のWebクローラーを設定および実行する方法を学習します。 crawler4jは、これを簡単に行うことができるオープンソースのJavaプロジェクトです。

2. セットアップ

https://search.maven.org/search?q=a:crawler4j%20AND%20g:edu.uci.ics[Maven Central]を使用して最新バージョンを見つけ、Maven依存関係を取り込みましょう。
<dependency>
    <groupId>edu.uci.ics</groupId>
    <artifactId>crawler4j</artifactId>
    <version>4.4.0</version>
</dependency>

3. クローラーの作成

3.1. シンプルなHTMLクローラー

まず、https://baeldung.com [_https://baeldung.com_]のHTMLページをクロールする基本的なクローラーを作成することから始めます。
クローラークラスで_WebCrawler_を拡張し、特定のファイルタイプを除外するパターンを定義して、クローラーを作成しましょう。
public class HtmlCrawler extends WebCrawler {

    private final static Pattern EXCLUSIONS
      = Pattern.compile(".*(\\.(css|js|xml|gif|jpg|png|mp3|mp4|zip|gz|pdf))$");

    // more code
}
各クローラークラスで、2つのメソッドoverride_shouldVisit_および_visit _。*をオーバーライドおよび実装する必要があります。
作成した_EXCLUSIONS_パターンを使用して、今すぐ_shouldVisit_メソッドを作成しましょう。
@Override
public boolean shouldVisit(Page referringPage, WebURL url) {
    String urlString = url.getURL().toLowerCase();
    return !EXCLUSIONS.matcher(urlString).matches()
      && urlString.startsWith("link:/");
}
次に、訪問したページに対して_visit_メソッドで処理を行うことができます。
@Override
public void visit(Page page) {
    String url = page.getWebURL().getURL();

    if (page.getParseData() instanceof HtmlParseData) {
        HtmlParseData htmlParseData = (HtmlParseData) page.getParseData();
        String title = htmlParseData.getTitle();
        String text = htmlParseData.getText();
        String html = htmlParseData.getHtml();
        Set<WebURL> links = htmlParseData.getOutgoingUrls();

        // do something with the collected data
    }
}
クローラーを作成したら、構成して実行する必要があります。
File crawlStorage = new File("src/test/resources/crawler4j");
CrawlConfig config = new CrawlConfig();
config.setCrawlStorageFolder(crawlStorage.getAbsolutePath());

int numCrawlers = 12;

PageFetcher pageFetcher = new PageFetcher(config);
RobotstxtConfig robotstxtConfig = new RobotstxtConfig();
RobotstxtServer robotstxtServer= new RobotstxtServer(robotstxtConfig, pageFetcher);
CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer);

controller.addSeed("link:/");

CrawlController.WebCrawlerFactory<HtmlCrawler> factory = HtmlCrawler::new;

controller.start(factory, numCrawlers);
一時記憶ディレクトリを構成し、クロールスレッドの数を指定し、クローラーに開始URLをシードしました。
また、* CrawlController.start()_メソッドはブロッキング操作*であることに注意する必要があります。 その呼び出しの後のコードは、クローラーの実行が完了した後にのみ実行されます。

3.2. ImageCrawler

デフォルトでは、crawler4jはバイナリデータをクロールしません。 この次の例では、その機能をオンにして、* BaledungですべてのJPEGをクロールします*。
まず、画像を保存するディレクトリを取得するコンストラクターで_ImageCrawler_クラスを定義することから始めましょう。
public class ImageCrawler extends WebCrawler {
    private final static Pattern EXCLUSIONS
      = Pattern.compile(".*(\\.(css|js|xml|gif|png|mp3|mp4|zip|gz|pdf))$");

    private static final Pattern IMG_PATTERNS = Pattern.compile(".*(\\.(jpg|jpeg))$");

    private File saveDir;

    public ImageCrawler(File saveDir) {
        this.saveDir = saveDir;
    }

    // more code

}
次に、_shouldVisit_メソッドを実装しましょう。
@Override
public boolean shouldVisit(Page referringPage, WebURL url) {
    String urlString = url.getURL().toLowerCase();
    if (EXCLUSIONS.matcher(urlString).matches()) {
        return false;
    }

    if (IMG_PATTERNS.matcher(urlString).matches()
        || urlString.startsWith("link:/")) {
        return true;
    }

    return false;
}
これで、_visit_メソッドを実装する準備ができました。
@Override
public void visit(Page page) {
    String url = page.getWebURL().getURL();
    if (IMG_PATTERNS.matcher(url).matches()
        && page.getParseData() instanceof BinaryParseData) {
        String extension = url.substring(url.lastIndexOf("."));
        int contentLength = page.getContentData().length;

        // write the content data to a file in the save directory
    }
}
_ImageCrawler_の実行は_HttpCrawler_の実行に似ていますが、バイナリコンテンツを含めるように構成する必要があります。
CrawlConfig config = new CrawlConfig();
config.setIncludeBinaryContentInCrawling(true);

// ... same as before

CrawlController.WebCrawlerFactory<ImageCrawler> factory = () -> new ImageCrawler(saveDir);

controller.start(factory, numCrawlers);

3.3. データの収集

いくつかの基本的な例を見てきたので、クロール中にいくつかの基本的な統計を収集するために_HtmlCrawler_を拡張しましょう。
最初に、いくつかの統計を保持する単純なクラスを定義しましょう。
public class CrawlerStatistics {
    private int processedPageCount = 0;
    private int totalLinksCount = 0;

    public void incrementProcessedPageCount() {
        processedPageCount++;
    }

    public void incrementTotalLinksCount(int linksCount) {
        totalLinksCount += linksCount;
    }

    // standard getters
}
次に、_HtmlCrawler_を変更して、コンストラクターを介して_CrawlerStatistics_インスタンスを受け入れます。
private CrawlerStatistics stats;

public HtmlCrawler(CrawlerStatistics stats) {
    this.stats = stats;
}
新しい_CrawlerStatistics_オブジェクトを使用して、必要なものを収集するために_visit_メソッドを変更しましょう。
@Override
public void visit(Page page) {
    String url = page.getWebURL().getURL();
    stats.incrementProcessedPageCount();

    if (page.getParseData() instanceof HtmlParseData) {
        HtmlParseData htmlParseData = (HtmlParseData) page.getParseData();
        String title = htmlParseData.getTitle();
        String text = htmlParseData.getText();
        String html = htmlParseData.getHtml();
        Set<WebURL> links = htmlParseData.getOutgoingUrls();
        stats.incrementTotalLinksCount(links.size());

        // do something with collected data
    }
}
それでは、コントローラーに戻り、_HtmlCrawler_に_CrawlerStatistics_のインスタンスを提供しましょう。
CrawlerStatistics stats = new CrawlerStatistics();
CrawlController.WebCrawlerFactory<HtmlCrawler> factory = () -> new HtmlCrawler(stats);

3.4. 複数のクローラー

前の例に基づいて、*同じコントローラーから複数のクローラーを実行する方法*を見てみましょう。
*各クローラーが独自の一時記憶ディレクトリ*を使用することをお勧めします。したがって、実行する各クローラーごとに個別の構成を作成する必要があります。
_CrawlControllers_は単一の_RobotstxtServer_を共有できますが、それ以外の場合は基本的にすべてのコピーが必要です。
これまで、_CrawlController.start_メソッドを使用してクローラーを実行し、ブロックメソッドであることに注意しました。 *複数を実行するには、_CrawlController.waitUntilFinish_と組み合わせて_CrawlerControlller.startNonBlocking_を使用します。*
それでは、_HtmlCrawler_と_ImageCrawler_を同時に実行するコントローラーを作成しましょう。
File crawlStorageBase = new File("src/test/resources/crawler4j");
CrawlConfig htmlConfig = new CrawlConfig();
CrawlConfig imageConfig = new CrawlConfig();

// Configure storage folders and other configurations

PageFetcher pageFetcherHtml = new PageFetcher(htmlConfig);
PageFetcher pageFetcherImage = new PageFetcher(imageConfig);

RobotstxtConfig robotstxtConfig = new RobotstxtConfig();
RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcherHtml);

CrawlController htmlController
  = new CrawlController(htmlConfig, pageFetcherHtml, robotstxtServer);
CrawlController imageController
  = new CrawlController(imageConfig, pageFetcherImage, robotstxtServer);

// add seed URLs

CrawlerStatistics stats = new CrawlerStatistics();
CrawlController.WebCrawlerFactory<HtmlCrawler> htmlFactory = () -> new HtmlCrawler(stats);

File saveDir = new File("src/test/resources/crawler4j");
CrawlController.WebCrawlerFactory<ImageCrawler> imageFactory
  = () -> new ImageCrawler(saveDir);

imageController.startNonBlocking(imageFactory, 7);
htmlController.startNonBlocking(htmlFactory, 10);

htmlController.waitUntilFinish();
imageController.waitUntilFinish();

4. 設定

構成可能なものの一部は既に見ました。 それでは、他の一般的な設定について見ていきましょう。
設定は、コントローラーで指定した_CrawlConfig_インスタンスに適用されます。

4.1. クロールの深さを制限する

デフォルトでは、クローラーは可能な限り深くクロールします。 それらの深さを制限するために、クロールの深さを設定できます。
crawlConfig.setMaxDepthOfCrawling(2);
シードURLは深さ0であると見なされるため、クロールの深さ2はシードURLの2層先になります。

4.2. 取得する最大ページ

クローラーがカバーするページ数を制限する別の方法は、クロールするページの最大数を設定することです。
crawlConfig.setMaxPagesToFetch(500);

4.3. 最大送信リンク

各ページをたどる発信リンクの数を制限することもできます。
crawlConfig.setMaxOutgoingLinksToFollow(2000);

4.4. ポライトネス遅延

非常に効率的なクローラーはWebサーバーに負担をかけやすいため、crawler4jにはポライトネス遅延と呼ばれるものがあります。 デフォルトでは、200ミリ秒に設定されています。 必要な場合は、この値を調整できます。
crawlConfig.setPolitenessDelay(300);

4.5. バイナリコンテンツを含める

_ImageCrawler_にバイナリコンテンツを含めるオプションを既に使用しました。
crawlConfig.setIncludeBinaryContentInCrawling(true);

4.6. HTTPSを含める

デフォルトでは、クローラーにはHTTPSページが含まれますが、これをオフにすることができます。
crawlConfig.setIncludeHttpsPages(false);

4.7. 再開可能なクロール

長時間実行されているクローラーがあり、それを自動的に再開する場合、再開可能なクロールを設定できます。 オンにすると、実行が遅くなる場合があります。
crawlConfig.setResumableCrawling(true);

4.8. ユーザーエージェント文字列

crawler4jのデフォルトのユーザーエージェント文字列は、_https://github.com/yasserg/crawler4j/ [crawler4j] _です。 それをカスタマイズしましょう:
crawlConfig.setUserAgentString("baeldung demo (https://github.com/yasserg/crawler4j/)");
ここでは、基本的な構成の一部について説明しました。 _https://github.com/yasserg/crawler4j/blob/master/crawler4j/src/main/java/edu/uci/ics/crawler4j/crawler/CrawlConfig.java [CrawConfig] _クラスを見ることができますより高度なまたはあいまいな構成オプションのいくつかに興味があります。

5. 結論

この記事では、crawler4jを使用して独自のWebクローラーを作成しました。 HTMLと画像をクロールする2つの簡単な例から始めました。 次に、これらの例に基づいて、統計を収集し、複数のクローラーを同時に実行する方法を確認しました。
完全なコード例は、https://github.com/eugenp/tutorials/tree/master/libraries-2 [over on GitHub]で入手できます。