2026年のためのウェブスクレイピング入門: ステップバイステップガイド
Advanced Data Extraction Specialist
TL;DR:
- Perlは、すでにデータやオペレーションスタックの一部である場合、ウェブスクレイピングにおいて実用的です。小さなリクエストには
HTTP::Tinyを使用し、豊富なHTTP制御にはLWP::UserAgentを、DOM解析にはHTML::TreeBuilderを、クッキー、リンク、フォームにはWWW::Mechanizeを使用します。 - 任意のHTMLを正規表現で解析しないでください。ドキュメントをツリーに解析し、属性によって要素を選択し、必須フィールドを検証し、実際のCSVまたはJSONエンコーダでUTF-8出力を行います。
- プレーンなPerl HTTPクライアントはJavaScriptを実行しません。ブラウザや管理されたレンダリングレイヤーを追加する前に、必要なデータが初期レスポンスに存在するか確認してください。
- プロキシはルーティングと位置の要件を解決しますが、セレクタを修正したり、ページをレンダリングしたりすることはできません。動的または強く保護された公開ページの場合、管理されたAPIが同じPerlパーサーにHTMLを返すことができます。
- このチュートリアルの主要なスクレイパーは、Perl 5.34.1、
libwww-perl6.83、HTML-Tree5.07、Text-CSV2.06、WWW::Mechanize2.22でテストされ、安全なプラクティスサイト「Books to Scrape」を対象としています。
Perlを使ったウェブスクレイピングは、組織がすでにPerlスクリプト、CPANのデプロイ、およびテキスト処理の専門知識を持っている場合に賢明な選択です。短いPerlプログラムでページを取得し、HTMLをトラバースし、レコードを検証し、クリーンなCSVまたはJSONを出力できます。
限界も同様に重要です。静的なHTTPクライアントはサーバーのレスポンスを表示しますが、ブラウザによってレンダリングされたDOMではありません。現代のサイトはページ起動後にデータを読み込み、セッションを要求し、トラフィック制御を適用することがあります。適切な設計では、ターゲットが要求されたときのみ、取得レイヤーを変更しつつ、パースをPerlで維持します。
このガイドは、その設計をステップバイステップで構築します。
ウェブスクレイピングにPerlを使用すべき時は?
Perlを使用するのは次の場合です:
- Perlがすでにインストールされ、運用環境でサポートされている;
- ソースがブラウザの実行なしに有用なHTMLまたはJSONを返す;
- タスクが成熟したテキスト処理とファイル変換に依存している;
- スクレイパーが既存のPerl ETLまたは報告ジョブと統合する必要がある;
- チームがブラウザの自動化スタックよりも小さく監査可能なスクリプトを重視する。
ソースがクライアント側のJavaScript、インタラクティブなブラウザの状態、マルチメディアAPI、またはPerlの外でより良いサポートを持つフレームワークに大きく依存している場合は、別のランタイムや管理されたAPIを検討してください。重要なのは、Perlがすべてのブラウザ機能を模倣することではなく、HTTPオーケストレーション、解析、検証、出力など、Perlがうまく処理できる部分を任せることです。
公式CPANドキュメントは、Perlがモジュールを解決し、構築し、テストし、インストールする方法を説明しています。使用する環境で検証した後、デプロイメントマニフェストまたはイメージにバージョンを固定してください。
適切なPerlスクレイピングモジュールを選ぶ
| モジュール | 最適な使用法 | JavaScript | セッションサポート | インストール元 |
|---|---|---|---|---|
HTTP::Tiny |
最小限の依存関係を持つ小さなGET/POSTクライアント | いいえ | 手動 | 多くのインストールでPerlコア |
LWP::UserAgent |
ヘッダー、クッキー、プロキシ、タイムアウト、リダイレクト | いいえ | はい、クッキージャーあり | LWP::UserAgent |
HTML::TreeBuilder |
HTMLをトラバース可能なツリーに解析 | いいえ | 該当なし | HTML::TreeBuilder |
WWW::Mechanize |
リンクをたどる、フォームを送信する、クッキーを保持する | いいえ | はい | WWW::Mechanize |
Text::CSV |
スタンダードに準拠したCSV出力 | 該当なし | 該当なし | Text::CSV |
JSON::PP |
コンパイル拡張なしでJSONをエンコードまたはデコード | 該当なし | 該当なし | Perlに含まれている |
現在のLWP::UserAgent ドキュメントはリダイレクト、タイムアウト、クッキー、認証、プロキシメソッドについて説明しています。WWW::Mechanize ドキュメントはこのモジュールがJavaScriptを実行しないことを明示しています。
再現可能なPerlプロジェクトを設定する
前提条件:
- Perl 5;
cpanまたはcpanm;- 書き込み可能なプロジェクトディレクトリ;
- アウトバウンドのHTTPSアクセス;
- ターゲットの公開データを収集する許可。
プロジェクトを作成し、フル例で使用される正確なモジュールをインストールします:
bash
mkdir perl-books-scraper
cd perl-books-scraper
cpanm LWP@6.83 HTML::Tree@5.07 Text::CSV@2.06 WWW::Mechanize@2.22
perl -MLWP -MHTML::TreeBuilder -MText::CSV -MWWW::Mechanize -e 'print "modules ready\n"'
これらのバージョンは、ドラフト作成中にパッケージレジストリで確認されました。オペレーティングシステムのパッケージマネージャが古いモジュールを提供する場合は、システムのPerlコンポーネントを置き換えるのではなく、プロジェクトローカルライブラリを使用してください。
このチュートリアル用のファイルは次のとおりです:
perl-books-scraper/
├── scrape_books.pl
├── books.csv
└── books.json
HTTP::Tinyを使って小さなリクエストを行う
HTTP::Tinyは「1つのリクエストを送信し、レスポンスを検査する」タスクに十分です。status、reason、headers、contentを含むハッシュを返します。
perl
use strict;
use warnings;
use HTTP::Tiny;
my $url = 'https://books.toscrape.com/';
私の$response = HTTP::Tiny->new(
agent => 'PublicCatalogResearch/1.0',
timeout => 20,
)->get($url);
die "リクエスト失敗: $response->{status} $response->{reason}\n"
unless $response->{success};
print "受信したバイト数: " . length($response->{content}) . " バイト\n";
これはエンドポイントチェックやJSONフィードに役立ちます。クッキー、プロキシ認証情報、詳細な応答オブジェクト、または豊富なリダイレクト処理が必要な場合は、`LWP::UserAgent`を使用してください。
## 完全なLWPとHTML::TreeBuilderスクレイパーを構築する
負荷に耐えるサンプルは、Books to Scrapeのホームページ上の可視の製品カードを収集し、各記録を検証し、CSVおよびJSONの両方に書き込みます。
このブロックは、`books.toscrape.com`へのネットワークアクセスと、上記にリストされた4つのインストール済みモジュールを必要とします。認証情報は必要ありません。
```perl
use strict;
use warnings;
use utf8;
use HTML::TreeBuilder;
use JSON::PP qw(encode_json);
use LWP::UserAgent;
use Text::CSV;
binmode STDOUT, ':encoding(UTF-8)';
binmode STDERR, ':encoding(UTF-8)';
my $url = $ENV{TARGET_URL} || 'https://books.toscrape.com/';
my $ua = LWP::UserAgent->new(
agent => 'PublicCatalogResearch/1.0',
timeout => 20,
max_size => 2_000_000,
);
$ua->protocols_allowed(['https']);
my $response = $ua->get($url);
die "HTTPエラー: " . $response->status_line . "\n"
unless $response->is_success;
my $content_type = $response->header('Content-Type') || '';
die "期待されるHTML、受信したのは$content_typeです\n"
unless $content_type =~ m{text/html}i;
my $tree = HTML::TreeBuilder->new;
$tree->ignore_unknown(0);
$tree->parse_content($response->decoded_content);
my @records;
for my $card ($tree->look_down(_tag => 'article', class => qr/\bproduct_pod\b/)) {
my $link = $card->look_down(_tag => 'h3')->look_down(_tag => 'a');
my $price = $card->look_down(_tag => 'p', class => qr/\bprice_color\b/);
my $stock = $card->look_down(_tag => 'p', class => qr/\binstock\b/);
next unless $link && $price && $stock;
my $title = $link->attr('title') || $link->as_trimmed_text;
my $href = $link->attr('href') || '';
push @records, {
title => $title,
price => $price->as_trimmed_text,
stock => $stock->as_trimmed_text,
url => $href,
};
}
$tree->delete;
die "受け入れチェック失敗: 完全な製品記録がありません\n" unless @records;
my $csv = Text::CSV->new({ binary => 1, eol => "\n" })
or die "CSVエンコーダの初期化に失敗しました\n";
open my $csv_fh, '>:encoding(UTF-8)', 'books.csv'
or die "books.csvに書き込めません: $!\n";
$csv->print($csv_fh, [qw(title price stock url)]);
for my $record (@records) {
$csv->print($csv_fh, [@{$record}{qw(title price stock url)}]);
}
close $csv_fh;
open my $json_fh, '>:encoding(UTF-8)', 'books.json'
or die "books.jsonに書き込めません: $!\n";
print {$json_fh} JSON::PP->new->utf8(0)->canonical->pretty->encode(\@records);
close $json_fh;
print "受け入れた製品記録の数: " . scalar(@records) . "\n";
実行方法:
bash
perl scrape_books.pl
head -n 4 books.csv
perl -MJSON::PP -0777 -e 'decode_json(<STDIN>); print "JSONは有効です\n"' < books.json
受け入れチェックは重要です。HTTP 200のページでも、ログイン画面、課題ページ、メンテナンスメッセージ、またはテンプレートの変更である可能性があります。生産環境のコレクターは、期待されるフィールドを検証し、主データセットに書き込むのではなく、予期しない出力を隔離するべきです。
なぜ正規表現でHTMLを解析しないのか?
Perlには素晴らしい正規表現エンジンがありますが、HTMLはネストされた要素を持つツリーであり、オプション属性、文字エンティティ、スクリプト、コメント、そして不正なマークアップがあります。1つのスナップショットで機能するパターンは、ホワイトスペースや属性の順序が変わると壊れることがよくあります。
選択後の値に対して正規表現を使用します—たとえば、価格文字列の正規化などです。要素を見つけるためにはHTMLパーサーを使用します。
HTML::TreeBuilderリファレンスには、look_down、要素の属性、テキスト抽出、および明示的なツリーのクリーンアップが文書化されています。$tree->deleteを呼び出すことで、解析後の循環参照を解放します。
セレクタの堅牢性は意味的アンカーから生まれます:
- 安定した要素タイプとクラスのトークン;
- アプリケーション状態を意図した
data-*属性; - スキーマでマークされたフィールド;
- 値の近くにあるラベル;
- 必要なフィールドのための受け入れチェック。
「3番目のdivに価格が含まれている」といった位置に基づく仮定は避けてください。
セッションを保持し、WWW::Mechanizeでフォームを送信する
WWW::Mechanizeは、リンク、フォーム、クッキー、履歴のヘルパー機能を追加したLWP::UserAgentを拡張します。これは、サイトが通常のHTMLを返す際の認可されたフォームワークフローやアプリケーションテストに便利です。
この例では、サイトによってフォームが異なるため、前提条件としてURLとフォームフィールド名を使用します。これは、所有しているアプリケーションまたはテストを許可されたアプリケーションに対してのみ使用してください。
perl
use strict;
use warnings;
use WWW::Mechanize;
my $mech = WWW::Mechanize->new(
agent => 'AuthorizedFormTest/1.0',
autocheck => 1,
timeout => 20,
);
perl
$mech->get($ENV{AUTHORIZED_FORM_URL});
$mech->submit_form(
form_name => 'search',
fields => { query => 'documentation' },
);
print $mech->title . "\n";
## ユーザー名やパスワードを公開されたスクリプトに記載しないでください。保護された環境や秘密マネージャーから秘密を読み取り、アカウントデータを含む可能性のあるレスポンスボディをログから除外してください。
## LWP::UserAgentでプロキシを設定する
プロキシは、特定の地域、安定した承認済みの出口、またはコレクションジョブ間の分離が必要な場合に適切です。無許可のターゲットを受け入れるものではありません。
以下のブロックは、読者所有のプロキシ資格情報を必要とする設定の例です:
```perl
use strict;
use warnings;
use LWP::UserAgent;
for my $name (qw(PROXY_HOST PROXY_PORT PROXY_USER PROXY_PASSWORD)) {
die "$nameを設定してください\n" unless defined $ENV{$name} && length $ENV{$name};
}
my $proxy = sprintf(
'%s://%s:%s@%s:%s',
'http',
$ENV{PROXY_USER},
$ENV{PROXY_PASSWORD},
$ENV{PROXY_HOST},
$ENV{PROXY_PORT},
);
my $ua = LWP::UserAgent->new(timeout => 20);
$ua->proxy([qw(http https)], $proxy);
my $response = $ua->get('https://example.com/');
die $response->status_line unless $response->is_success;
print $response->decoded_content;
プロキシ資格情報を環境に保持し、それらを例外レポートから削除してください。Scrapeless Proxy Solutionsページは、トラフィック要件に合わせて住宅、データセンター、静的ISP、およびIPv6オプションをマッピングするのに役立ちます。
データを破損させずに失敗を処理する
堅牢性は、制約された明示的な結果から始まります:
- 成功以外のHTTPステータスコードを拒否する。
- レスポンスサイズとリクエスト時間を制限する。
Content-Typeを確認する。- 予想されるページのアイデンティティを検証する。
- 完全なレコードを定義するフィールドを要求する。
- 新しい出力を一時パスに書き込み、検証後にのみ名前を変更する。
- 予期しないページを安全なメタデータを持つ隔離ディレクトリに送信する。
- 資格情報やレスポンスボディなしで構造化されたログを発出する。
403、429、および予期しないHTMLを、ポリシー、ペーシング、ターゲットの変更、または取得の適合を調査するための信号として扱います。無制限の失敗ループを作成しないでください。
また、ロボット排除プロトコル、ターゲット条件、プライバシー法、ソース特有のリクエスト予算を尊重してください。大規模なクロールの場合、同じページが二度処理されないように、正規のURLとコンテンツハッシュを保存します。
ページがJavaScriptを必要とする場合を知る
ブラウザのレンダリングが必要であると仮定する前に、生のレスポンスを確認してください:
- ブラウザの開発者ツールを開く。
- ページを再読み込みし、必要なデータを含むネットワークレスポンスを特定する。
- そのレスポンスを
LWP::UserAgentの出力と比較する。 - HTML内で既知の製品名またはレコード識別子を検索する。
- データが公開JSONエンドポイントから到着する場合は、その承認されたエンドポイントを直接使用する。
- データがブラウザの実行後にのみ存在する場合は、取得をレンダリングレイヤーに移動する。
WWW::MechanizeはJavaScriptエンジンではありません。ブラウザを操作するPerlモジュールは存在しますが、ブラウザバイナリ、ドライバの互換性、プロセスの分離、およびより大きなリソース要件を追加します。これは小さな内部システムには合理的かもしれませんが、静的なスクレイパーにとってはほとんどドロップインアップグレードとはなりません。
ブラウザ操作が主要なプロジェクトになっている場合、Universal Scraping APIを介して1つの代表的なURLをテストし、受け入れられた出力、レイテンシー、および運用の労力を比較してください。
PerlからUniversal Scraping APIを呼び出す
管理されたパスは、下流のパーサーをPerl内に保持します。APIはページの取得を実行し、結果を返します。Perlはそれを検証し、変換します。
この事前条件ギャップブロックは、SCRAPELESS_API_KEYと承認されたTARGET_URLを必要とします。製品使用の前に、Universal Scraping APIのクイックスタートで現在のリクエストフィールドを確認してください。
perl
use strict;
use warnings;
use HTTP::Tiny;
use JSON::PP qw(encode_json decode_json);
my $token = $ENV{SCRAPELESS_API_KEY} or die "$ENV{SCRAPELESS_API_KEY}を設定してください\n";
my $target = $ENV{TARGET_URL} or die "$ENV{TARGET_URL}を設定してください\n";
my $response = HTTP::Tiny->new(timeout => 60)->post(
'https://api.scrapeless.com/api/v1/scraper/request',
{
headers => {
'Content-Type' => 'application/json',
'x-api-token' => $token,
},
content => encode_json({
actor => 'unlocker.webunlocker',
input => { url => $target },
}),
},
);
die "APIの失敗: $response->{status} $response->{reason}\n";
以下のコードは、Perlのスクリプトの一部です。APIレスポンスの成功をチェックし、その内容をJSON形式でデコードして処理します。この境界は意図的にシンプルに設計されています。Scrapelessはページ取得とネットワーク操作を所有し、Perlはターゲットスコープ、レスポンス検証、解析、保存を担当します。組織は認証、保存、データ利用を所有します。
クリーンなCSVおよびJSONのエクスポート
CSVとJSONは異なる下流システムに対応します。
結果がフラットでExcel、データベースインポート、または分析ツールに送信される場合はCSVを選択します。Text::CSVを使用すると、カンマ、改行、及び引用符を正しく引用します。
配信されるレコードに配列、ネストされたオブジェクト、またはソースURL、キャプチャ日時、検証状態などのメタデータが含まれる場合はJSONを選択します。JSON::PPはポータブルで、標準準拠のJSONを生成します。
アナリストにウェブデータを提供するワークフローについては、Power QueryとAPIを使用したExcelでのウェブスクレイピングを参照してください。API出力の選択肢については、Scrapelessレスポンスフォーマットガイドをお読みください。
すべてのレコードには、監査のために十分な出所情報を含めるべきです:
- ソースURL
- キャプチャ時間
- パーサーまたはスキーマバージョン
- 関連する場合のロケールまたは地域
- コンテンツハッシュ
- 受け入れ状況
Perlスクレイパーのための生産チェックリスト
スクリプトをスケジュールする前に:
- ソースとフィールドが承認されている。
- ターゲットのロボット指令と規約が確認された。
- モジュールのバージョンが固定され、テストされている。
- シークレットは保護された環境変数から取得される。
- パーサーは構造的セレクターを使用し、任意のHTML正規表現を使用していない。
- レスポンスのサイズ、時間、コンテンツタイプ、および必要なフィールドが制約されている。
- 予期しないページは隔離される。
- ログは資格情報および機密情報を除外している。
- CSVおよびJSON出力はエンコーディングに安全である。
- 動的ページの要件には明示的な取得決定がある。
- メトリクスは受け入れられたレコードをカウントし、リクエストのみではない。
Perlをデータ契約に集中させる
Perlは、スクレーパーが明確な契約を持つときに最も強力です。承認されたソースを取得し、既知の構造を解析し、完全なレコードを検証し、決定論的な出力を書き出します。これは、HTMLがLWP::UserAgentから直接来る場合でも、プロキシを介する場合でも、管理されたレンダリングAPIから来る場合でも役立ちます。
最小限の作業方法から始めます。ページが動的または強固に保護されている場合は、検証済みのPerlパーサーを維持し、取得部分だけを置き換えます。現在のScrapeless価格オプションを比較し、その後Scrapelessアカウントを作成して、より大規模な移行をする前に代表的な公開URLのテストを行います。
よくある質問
2026年にPerlはウェブスクレイピングにまだ優れていますか?
はい、特に既存のPerl環境を持ち、便利なHTMLまたはJSONを返すターゲットを持つチームには最適です。Perlは成熟したHTTP、HTML解析、セッション、CSV、およびJSONのモジュールを提供します。ブラウザ重視の作業は、管理された取得レイヤーや他のサポートされている自動化スタックを通じて行う方が簡単かもしれません。
ウェブスクレイピングに最適なPerlモジュールはどれですか?
最小限のクライアントにはHTTP::Tinyを使用し、リッチなリクエスト制御にはLWP::UserAgentを使用します。HTML解析にはHTML::TreeBuilderを、リンク、フォーム、クッキー、セッション履歴にはWWW::Mechanizeを使用します。ほとんどの実際のプロジェクトでは、HTTPクライアントをパーサーと出力エンコーダーと組み合わせて使用します。
LWP::UserAgentはJavaScriptを実行できますか?
いいえ。HTTPレスポンスを取得しますが、ページのJavaScriptは実行しません。必要なデータがレスポンスに含まれていない場合は、承認されたJSONエンドポイント、ブラウザドライビングツール、または管理されたレンダリングAPIを使用してください。
Perlの正規表現を使用してHTMLを解析すべきですか?
いいえ、ドキュメント構造には使用すべきではありません。要素を見つけるためにはHTMLパーサーを使用し、選択されたテキストを標準化する必要がある場合には正規表現を利用します。
Perlでプロキシを使用するには?
LWP::UserAgentを作成し、必要なプロトコル用のproxyメソッドを呼び出します。プロキシのホスト、ポート、ユーザー名、パスワードは保護された環境変数から読み取ります。
ウェブスクレイピングは合法ですか?
合法性は管轄、アクセス方法、ターゲットの規約、データタイプ、及び意図した使用に依存します。承認された公開データの収集に制限を設け、ロボット指令やソース制限を尊重し、個人データを最小限にし、高リスクプログラムには法的アドバイスを取得するべきです。
Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。



