Featured image of post 第1回-ニュースサイトから見出しを取得しよう - PerlとMooでWebスクレイパーを作ってみよう

第1回-ニュースサイトから見出しを取得しよう - PerlとMooでWebスクレイパーを作ってみよう

PerlとMojo::UserAgentを使ってニュースサイトから見出しを取得する基本的なWebスクレイパーを作成します。Mojo::DOMでHTMLから要素を抽出する方法を学び、Webスクレイピングの基礎を身につけます。

@nqounetです。

「Mooで覚えるオブジェクト指向プログラミング」シリーズを読み終えた皆さん、お待たせしました!今回から始まる新シリーズでは、実践的なWebスクレイパーを一緒に作っていきます。

「Webスクレイピング」とは、プログラムを使ってWebサイトから自動的にデータを収集する技術のことです。ニュースサイトから見出しを集めたり、ECサイトから商品情報を取得したり、天気予報を自動で取得したり…Webスクレイピングができると、日々のデータ収集作業を自動化できるようになります。

このシリーズでは、Perl v5.36以降とMoo、そしてMojoliciousのHTTPクライアントであるMojo::UserAgentを使って、拡張性の高いWebスクレイパーを構築していきます。

このシリーズが対象とする読者

このシリーズは以下の読者を想定しています。

  • Perl入学式を卒業した方
  • 「Mooで覚えるオブジェクト指向プログラミング」シリーズを読了した方
  • 実務で役立つモダンなPerlを使ってみたい方

前シリーズで学んだhassubでクラスを定義する方法、newでオブジェクトを生成する方法、そしてextendsによる継承とオーバーライドの知識を活用していきます。

このシリーズについて

このシリーズは「Mooで覚えるオブジェクト指向プログラミング」シリーズを読了した方を対象に、実践的なWebスクレイパーを作りながらオブジェクト指向設計を深く学ぶシリーズです。

シリーズ全体の目次は以下をご覧ください。

今回のゴール

今回は、ニュースサイトから見出しを取得する単純なスクレイパーを作成します。まずはMojoliciousのMojo::UserAgentを使ってHTTPリクエストを送信し、取得したHTMLからMojo::DOMを使って必要な情報を抽出する方法を学びましょう。

環境構築

まず、必要なモジュールをインストールします。

1
2
# Mojoliciousのインストール
$ cpanm Mojolicious

MojoliciousをインストールするとMojo::UserAgentとMojo::DOMが一緒にインストールされます。

Mojo::UserAgentでHTTPリクエストを送信する

Mojo::UserAgentは、Mojoliciousに含まれる軽量で高機能なHTTPクライアントです。まずは基本的な使い方を見てみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Mojo::UserAgent(Mojoliciousに含まれる)

use v5.36;
use Mojo::UserAgent;

# UserAgentオブジェクトを生成
my $ua = Mojo::UserAgent->new;

# GETリクエストを送信
my $res = $ua->get('https://www.perl.org/')->result;

# レスポンスの状態を確認
if ($res->is_success) {
    say "取得成功!";
    say "Content-Type: " . $res->headers->content_type;
} else {
    say "取得失敗: " . $res->message;
}

このコードをfetch_demo.plとして保存し、実行すると以下のような出力が得られます。

1
2
3
$ perl fetch_demo.pl
取得成功!
Content-Type: text/html; charset=utf-8

Mojo::DOMでHTMLから要素を抽出する

次に、取得したHTMLから特定の要素を抽出する方法を学びましょう。Mojo::DOMを使うと、CSSセレクタで簡単にHTML要素を指定できます。

実際のWebサイトに依存するとサイト構造の変更などで動かなくなるリスクがあるため、今回はローカルでサンプルHTMLを使って練習します。

まず、sample_news.htmlというファイルを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html>
<head>
    <title>サンプルニュースサイト</title>
</head>
<body>
    <h1>今日のニュース</h1>
    <div class="article">
        <h2 class="headline">Perl 5.42.0が2025年7月にリリース</h2>
        <p class="summary">新機能を多数搭載した最新安定版が公開</p>
    </div>
    <div class="article">
        <h2 class="headline">PerlがTIOBEインデックスでトップ10に復帰</h2>
        <p class="summary">2025年9月、27位から大躍進を遂げる</p>
    </div>
    <div class="article">
        <h2 class="headline">Perl Toolchain Summit 2025が開催</h2>
        <p class="summary">CPANインフラの維持・発展に向けた取り組み</p>
    </div>
</body>
</html>

次に、このHTMLから見出し(h2.headline)を抽出するスクリプトを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Mojo::UserAgent(Mojoliciousに含まれる)

use v5.36;
use Mojo::UserAgent;

my $ua = Mojo::UserAgent->new;

# ローカルファイルをHTTPで取得するためにfile://スキームを使用
# 実際のWebサイトをスクレイピングする場合はURLを指定
my $res = $ua->get('file://./sample_news.html')->result;

if ($res->is_success) {
    # Mojo::DOMオブジェクトを取得
    my $dom = $res->dom;

    # CSSセレクタで見出しを全て取得
    my $headlines = $dom->find('h2.headline');

    say "=== ニュース見出し一覧 ===";
    my $count = 1;
    for my $headline ($headlines->each) {
        say "$count. " . $headline->text;
        $count++;
    }
} else {
    say "取得失敗: " . $res->message;
}

このコードをnews_scraper_v1.plとして保存し、実行します。

1
2
3
4
5
$ perl news_scraper_v1.pl
=== ニュース見出し一覧 ===
1. Perl 5.42.0が2025年7月にリリース
2. PerlがTIOBEインデックスでトップ10に復帰
3. Perl Toolchain Summit 2025が開催

見事にHTMLから見出しだけを抽出できました!

Mojo::DOMの便利なセレクタ

Mojo::DOMでは、jQueryライクなCSSセレクタが使えます。よく使うセレクタをいくつか紹介します。

  • div - タグ名で選択
  • .class - クラス名で選択
  • #id - ID名で選択
  • div.class - タグ名とクラス名の組み合わせ
  • div p - 子孫要素を選択(divの中のp)
  • div > p - 直接の子要素を選択
  • a[href] - 特定の属性を持つ要素を選択

例えば、記事の要約(p.summary)も取得したい場合は以下のように書きます。

1
2
3
4
5
6
# 記事ごとにループ
for my $article ($dom->find('div.article')->each) {
    my $headline = $article->at('h2.headline')->text;
    my $summary = $article->at('p.summary')->text;
    say "【$headline】 $summary";
}

findは条件に一致する全ての要素を返し、atは最初の1つだけを返します。

Webスクレイピングのマナー

実際のWebサイトをスクレイピングする際は、以下のマナーを守りましょう。

  • robots.txtを確認し、スクレイピングが許可されているか確認する
  • 短時間に大量のリクエストを送らない(サーバーに負荷をかけない)
  • 取得したデータの利用規約を確認する
  • 可能であればAPIが提供されていないか確認する(APIがあればそちらを使う)

Mojo::UserAgentでリクエスト間隔を空けるには、sleepを使います。

1
2
3
4
5
for my $url (@urls) {
    my $res = $ua->get($url)->result;
    # ... 処理 ...
    sleep(1);  # 1秒待つ
}

今回のまとめ

今回は以下のことを学びました。

  • Mojo::UserAgentでHTTPリクエストを送信する方法
  • Mojo::DOMでHTMLから要素を抽出する方法
  • CSSセレクタによる要素の指定
  • Webスクレイピングのマナー

次回予告

今回作ったスクレイパーは、ニュースサイトから見出しを取得するだけの単純なものでした。次回は、天気予報サイトからも情報を取得したくなったとき、どうなるかを見ていきます。同じようなコードをコピペして対応することになりますが…そこには罠が待っています。

お楽しみに!

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。