JavaでのWebスクレイピング:Jsoup、Playwright、およびクラウドブラウザワークフロー
Expert in Web Scraping Technologies
要約:
- Jsoup は与えられた HTML をパースするだけであり、欠けているレコードを作成するためにページの JavaScript を実行したりはしません。
- Playwright Java はブラウザによる取得経路を提供するため、レンダリング後の HTML に対しても静的ページと同じ Jsoup 抽出契約を適用できます。
- Agent Browser はブラウザ実行をクラウド側に移動させます。セレクタ、レコード検証、ページネーションの範囲、エクスポートは引き続き Java が保持します。
- CSV ファイルは、そのレコードが意図したソースを特定できる場合にのみ有用です。安定したレコード ID と解決済み URL を保持し、必須項目が欠けているレコードは拒否します。
Java での Web スクレイピングは実務的な問いから始まります。サーバーが返す HTML にすでにレコードが含まれているのか、それともブラウザがそれらを生成する必要があるのか、という点です。取得経路を正しく選ぶことで、そもそもデータを含んでいないドキュメントに対するセレクタを書くことを避けられます。
このワークフローでは、抽出に Jsoup を用い、レンダリング済みページの取得に Playwright Java を用います。どちらの経路も同じレコード構造を生成します。ブラウザのワークロードをアプリケーションホストの外で実行したい場合には、専用の Scrapeless Agent Browser 接続がクラウド側の選択肢になります。
例では、安定した属性を持つ制御された記事一覧を対象としています。この契約を差し替えるのは、許可されたソースを検査した後にしてください。Java のコンパイルとブラウザ実行には、下記のランタイムと認証情報が必要です。このガイドではライブの Java キャプチャは行いません。
ページの実際の内容から Jsoup かブラウザかを選ぶ
取得した HTML に必要なレコードが存在する場合は Jsoup を選びます。許可されたページが、レコードが存在する前に JavaScript やインタラクションを必要とする場合はブラウザを選びます。
| パス | パーサーに渡される HTML | 適した開始タスク | 維持する責任範囲 |
|---|---|---|---|
| Jsoup HTTP フェッチ | サーバーが返したドキュメント | 静的な記事やカタログの一覧 | ソースの検査と抽出 |
| ローカル Playwright Java | ブラウザがレンダリングしたドキュメント | 制御された動的ページ開発 | ブラウザランタイムとリソース管理 |
| Playwright Java と Agent Browser | クラウドブラウザのドキュメント | 専用のリモートブラウザワークフロー | 接続ライフサイクル、セレクタ、出力チェック |
サイト構築に使われたフレームワークから経路を選ばないでください。JavaScript アプリケーションでも有用な HTML を返すことがありますし、一見単純な一覧ページがロード後にレコードを挿入する場合もあります。特定のページと必要なフィールドを検査してください。
HTTP representation semantics では、クライアントが受け取るレスポンスについて説明しています。後にブラウザが生成するページ状態は、それとは異なる取得上の観測となります。
前提条件と依存関係
このプロジェクトには JDK と Maven に加え、Jsoup と Playwright Java の依存関係が必要です。ここで示すプロジェクトは JDK 17 を対象とし、古いチュートリアルからバージョンを流用するのではなく、Jsoup 1.23.2 と Playwright 1.63.0 を固定しています。
ローカルレンダリングの場合は、自身のプロジェクト環境で使用する Playwright バージョンに必要なブラウザランタイムをインストールしてください。リモートレンダリングの場合は、現在のアカウント設定を通じて専用の Agent Browser 接続を取得し、その完全なエンドポイントを SCRAPELESS_CDP_URL に保持してください。
対象は公開されているか、あるいは適切に認可されていなければなりません。TARGET_URL は、その構造を検査済みの、許可された記事一覧の URL です。例でのセレクタ契約は main article[data-id] であり、各記事内に見出しとリンクを持ちます。
注: Java ツールチェーン、依存関係のインストール、およびブラウザランタイムは実行の前提条件です。スニペットは最新のライブラリインターフェースに照らして確認済みですが、利用可能な検証環境ではコンパイルや実行は行っていません。リモート経路には実際の専用 Scrapeless 接続も必要です。
この Maven 設定を pom.xml として保存し、以下のクラスを src/main/java/ArticleCollector.java として保存します:
xml
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>article-collector</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.23.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.63.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
</plugins>
</build>
</project>
このプロジェクトではコンパイラのターゲットと依存関係バージョンを維持し、他の環境でも、いかなる収集ジョブを有効化する前に同じセットアップを再現できるようにしてください。
両方の経路に対して 1 つの抽出契約を構成する
抽出契約は、輸送経路とは独立して、受け入れ可能な記事レコードを定義します。この例では、空でない data-id、h2 見出し、および HTTP もしくは HTTPS の URL に解決されるリンクを必須としています。
これらは制御された例における属性であり、公的サイトの現在のセレクタについての主張ではありません。自身のソースでは、可能であれば安定したレコード属性や耐久性のある URL パターンを優先してください。単に一度のキャプチャでマッチしたという理由だけで、装飾用クラスを再利用してはいけません。
必須フィールドと任意フィールドは分けておきます。識別子が欠けている場合、この例のレコードは拒否されます。一方、任意の概要は、レコードの同一性を変えずに欠落したままでも構いません。エクスポート前にその方針を明示してください。
基本実装: フェッチ、抽出、エクスポート
以下のクラスは、選択した経路を通じて HTML を取得し、Jsoup で記事レコードを抽出し、UTF-8 の CSV ファイルを書き出します。リモート側のブランチでは、Java 向けの Scrapeless SDK メソッドを創作するのではなく、アカウントから提供される CDP エンドポイントを使用します。
注意: この完全な Java の例には、固定された依存関係、JDK、Maven のセットアップ、および許可されたターゲットが必要です。
localブランチにはブラウザーランタイムが必要で、remoteブランチにはSCRAPELESS_CDP_URLが必要です。以下の出力はライブ実行のキャプチャとして提示されていません。
java
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.WaitUntilState;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.net.URI;
public class ArticleCollector {
private static String csv(String value) {
return "\"" + value.replace("\"", "\"\"") + "\"";
}
public static void main(String[] args) throws Exception {
if (args.length != 2) throw new IllegalArgumentException("mode and URL required");
String mode = args[0];
String target = args[1];
Document doc;
if (mode.equals("static")) {
doc = Jsoup.connect(target).get();
} else {
if (!mode.equals("local") && !mode.equals("remote"))
throw new IllegalArgumentException("Unsupported acquisition mode");
try (Playwright playwright = Playwright.create()) {
String endpoint = System.getenv("SCRAPELESS_CDP_URL");
if (mode.equals("remote") && (endpoint == null || endpoint.isBlank()))
throw new IllegalArgumentException("Dedicated CDP endpoint required");
Browser browser = mode.equals("remote")
? playwright.chromium().connectOverCDP(endpoint)
: playwright.chromium().launch();
try {
Page page = browser.newPage();
page.navigate(target, new Page.NavigateOptions()
.setWaitUntil(WaitUntilState.DOMCONTENTLOADED));
page.locator("main article[data-id] a[href]").first().waitFor();
doc = Jsoup.parse(page.content(), page.url());
} finally {
browser.close();
}
}
}
StringBuilder output = new StringBuilder("id,title,url\r\n");
int accepted = 0;
for (Element article : doc.select("main article[data-id]")) {
Element heading = article.selectFirst("h2");
Element link = article.selectFirst("a[href]");
String id = article.attr("data-id").strip();
if (id.isEmpty() || heading == null || link == null) continue;
String title = heading.text().strip();
String url = link.attr("abs:href");
URI resolved = URI.create(url);
if (title.isEmpty() || resolved.getHost() == null ||
!("https".equals(resolved.getScheme()) || "http".equals(resolved.getScheme())))
continue;
output.append(csv(id)).append(',').append(csv(title)).append(',')
.append(csv(url)).append("\r\n");
accepted++;
}
if (accepted == 0) throw new IllegalStateException("Content contract not satisfied");
Files.writeString(Path.of("articles.csv"), output, StandardCharsets.UTF_8);
System.out.println("Accepted article records: " + accepted);
}
}
Maven でプロジェクトをコンパイルし依存関係をコピーしてから、target/classes と依存ディレクトリを含むクラスパスで ArticleCollector を実行します。static、local、または remote を選択し、検査済みのターゲット URL を指定します。
注意: これらの POSIX シェルコマンドには、上記の Java ツールチェーンと依存関係が必要です。
TARGET_URLを許可されたソースに設定してください。この例では、コンパイルと依存関係の収集が実行の前提条件のままです。
bash
mvn -q dependency:copy-dependencies compile
java -cp 'target/classes:target/dependency/*' ArticleCollector static "$TARGET_URL"
Windows 環境では、クラスパスのセパレーターとしてセミコロンを使用します。ブラウザーランタイムまたは専用セッションのセットアップを完了した後にのみ local または remote モードを選択してください。
このコードは abs:href を使用しているため、相対リンクは取得したドキュメントのベース URL に対して解釈されます。relative URI resolution は、パス単体では完全なソース識別子にならない理由を説明しています。取得したページ URL は、アプリケーションのキャプチャマニフェスト内で、発見された各記事 URL とは別に保持してください。
Playwright Java で動的ページをレンダリングする
ブラウザーパスは、ページ HTML を収集する前にタスク固有の要素を待機します。domcontentloaded がナビゲーションのマイルストーンであり、記事ロケーターが、この例のレコードが存在するという別個の条件を確立します。
どちらの条件も、すべてのレコードが到着した証拠として扱ってはいけません。リストは、明示的な操作を行った後にのみ、さらに多くの行を読み込む場合があります。要求されたタスクに対して最初のバッチが完全かどうかを、受け入れる前に確認してください。
Playwright browser connection methods は、そのネイティブプロトコルを CDP と区別しています。CDP 接続は Chromium ベースのブラウザー向けであり、ネイティブの Playwright プロトコル接続とは異なる機能を持ちます。
実際のコレクターを開発する際は、タイムアウトとソースの準備条件をプロジェクト設定に保持してください。無関係なアナリティクス通信がアイドル状態になるのを待つよりも、ソース固有の可視マーカーのほうが有用です。
Scrapeless でスクレイピングを始めよう
Scrapeless で Web スクレイピングと自動化ワークフローを強化しましょう。
いますぐサインアップして、5 ドル分の無料クレジットを獲得 — クレジットカードは不要です。今すぐ Scrapeless ダッシュボード で無料クレジットを受け取りましょう。
ローカル Java スクレイパーが止まる場所
ローカルの Java パーサーは、レンダリングされていない欠落コンテンツを提供できず、ローカルブラウザーがあってもブラウザーリソースと取得状態を管理する必要性はなくなりません。こうした制約によって、ワークフローがクラウドブラウザーを必要とするタイミングが決まります。
Scrapeless Agent Browser は、この Java ワークフローにリモートブラウザーレイヤーを提供します。Agent Browser Playwright セットアップ を通じて専用接続を取得し、その完全な接続エンドポイントを remote ブランチに渡してください。
接続 URL には認証情報が含まれる場合があります。これを実行時環境に保持し、ログに記録せず、このジョブのために割り当てられた専用セッションのみを閉じてください。共有ブラウザーに接続してそれを閉じると、そのセッションを使用している他の作業に影響します。
クラウドパスは、取得が行われる場所を変更します。Java での HTML 解析とレコード検証は同じままです。チャレンジドキュメントや不正なページ状態は、成功したエクスポートを生成するのではなく、依然としてコンテンツ契約に失敗すべきです。
リンクの発見と制約付きページネーション
ページネーションは、ソースで検査したナビゲーション契約と、制約された収集範囲に従うべきです。ページ番号パラメーターを推測するのではなく、実際のソースから次ページ URL または許可された操作を発見してください。
現在のページ識別子、発見された次リンク、訪問済みページ集合を保持します。ナビゲーションする前に、そのリンクが承認されたソーススコープに属していることを確認してください。タスクのページ予算に達したとき、URL が重複したとき、またはソースがこれ以上ページが存在しないことを示したときに停止します。
次リンクが存在しない場合、それは一覧が終了したこと、またはソースがナビゲーションのレンダリングに失敗したことを意味する可能性があります。ページのコンテンツと空状態の証拠を使用して、それらの結果を区別してください。上記の単一ページクラスは、普遍的なページネーションループを暗示するのではなく、その判断をアプリケーションに意図的に委ねています。
レコードのエクスポートと検証
エクスポート手順では、受理されたレコードの同一性を保持し、選択した形式を正しくエンコードする必要があります。CSV フィールドのクオート規則は、区切り文字と引用符の扱いを規定しています。この例では、埋め込まれた引用符を二重にし、各フィールドを引用符で囲みます。
CSV の構文は、内容の検証とは別です。出力を意図した下流のパーサーで再度開き、必須フィールド、一意の識別子、ソースリンクを確認します。ワークブックがコンシューマーとなる場合は、信頼できないテキストをデータとして保持するスプレッドシートのインポートポリシーを使用してください。
CSV ヘッダーは契約を表現します: id、title、url。これは取得済みデータセットではなく、規範的な例示スキーマです。一致するレコードがないソースでは、この例は処理を停止し、その結果を有効な空リストとして黙ってラベル付けすることはありません。
取得境界のトラブルシューティング
欠落レコードは、取得されたドキュメントと抽出契約に対して診断する必要があります。空の CSV だけでは原因は特定できません。
| 症状 | 確認対象 | 想定されるエンジニアリング対応 |
|---|---|---|
| 静的 HTML に必要なレコードが存在しない | 生レスポンスとソースの準備状況 | 許可されたブラウザーパスを選択する |
| ブラウザーが無関係なコンテンツをレンダリングする | 最終ページとページ状態 | 開始 URL またはインタラクションを修正する |
| 一部のレコードに ID またはタイトルがない | ソースのマークアップと必須フィールド | 契約を更新するか範囲を絞る |
| 相対リンクが誤ってエクスポートされる | 取得されたベース URL とリンク属性 | 正しいドキュメントに対してリンクを解決する |
| リモート接続を確立できない | エンドポイント種別と専用セッション | アカウントおよび接続設定を修正する |
既存のJsoup に焦点を当てた Java ワークフローでは、パーサー指向の取得アプローチを扱っています。本記事は、その公開ページを置き換えることなく、静的・ローカルブラウザー・クラウドブラウザーに共通の契約を追加します。
結論
Java による Web スクレイピングは、取得と抽出を別個の判断として扱うと最も有効に機能します。実際に手元にあるドキュメントには Jsoup を用い、ソースが要求する場合はレンダリング済み HTML を取得し、エクスポート前に同じレコード契約を検証してください。
ツールチェーンと専用セッションの前提条件を満たし、許可された単一ページでテストしたうえで、範囲を制限したソース固有のページネーションを追加します。
Java コレクターをクラウドブラウザーに接続する準備はできましたか?
Scrapelessでブラウザーパスを構築し、そのリソース要件を現在の料金と照らして評価してください。Java ワークフローに関する質問は Telegram で議論できます。
FAQ
Q: Jsoup はサイトの JavaScript を実行できますか?
Jsoup は与えられた HTML をパースするだけで、ページの JavaScript は実行しません。必要なレコードがレンダリング後にのみ存在する場合は、ブラウザー取得パスを使用してください。
Q: Java による Web スクレイピングは公開ページならどこでも許可されますか?
公開されていること自体は、あらゆる収集や利用の許可を意味しません。収集前に、ソースの利用規約、robots 排除ルール、適用される要件、およびプロジェクトの認可を確認してください。
Q: この Java ワークフローには別個のプロキシが必要ですか?
静的またはローカルブラウザークライアントには、ソースが要求する範囲で許可されたルーティングが必要です。クラウドパスでは、割り当てられた Agent Browser 設定を使用します。現在のアカウント設定に従って、その出口経路を構成してください。
Q: チャレンジページやアクセス拒否ドキュメントをコレクターはどう扱うべきですか?
コレクターは不適切なコンテンツを拒否し、取得理由を保持すべきです。クラウドブラウザー接続は、ソースコンテンツのチェックを代替するものではありません。
Q: 同じセレクターがページ更新後に行を返さなくなるのはなぜですか?
ソース側でマークアップ、レンダリング動作、またはページの同一性が変更された可能性があります。セレクターを変更したり空結果を受け入れたりする前に、それらの観察結果と最終 URL を再点検してください。
Q: Java のパイロットではどれくらいの並行実行数を使うべきですか?
この例のポリシーであれば、ホストごと 3 ワーカーのような保守的な上限を持つ有界なパイロットを使用してください。拡大の判断は、ソースの収集ルールと観測されたリソース使用状況に従います。
Q: このコレクターは AI エージェントなしで動作できますか、または Selenium と併用できますか?
Java ワークフローは、AI エージェントなしの決定論的なコードとして実行できます。既存の Selenium プロジェクトは、既存のブラウザー取得レイヤーを維持したまま、キャプチャした HTML を同じ検証およびエクスポート契約に渡すことができます。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



