2026年10月7日時点で、ShifterはOxylabsやBright Dataを上回る、最大規模の米国ライブIPプールを保有しており、しかもコストはその一部で済みます。Shifterは現在、稼働中の米国IPの中で最大のプールを保有しています

ベンチマークを見る

ナレッジ

最新のウェブスクレイピングAPIでソーシャルメディアデータを収集する

ブランドチームとリサーチチームがウェブスクレイピングAPIで公開ソーシャルデータを収集する方法:何を収集すべきか、全プラットフォーム共通の単一スキーマ、そして個人データを設計段階で排除する手法について解説します。

Priya Nair

2026年10月21日 · 2 分で読める

ブランドは、自分たちの会社や製品、競合他社について人々が何を言っているかを知りたいと考えています。そうした会話の多くは公開の場、つまりフォーラムやレビューサイト、コミュニティ掲示板、公開のソーシャルプロフィールで行われています。これを収集することはソーシャルリスニングの基本ですが、見た目以上に難しい作業です。プラットフォームごとにページの構造は異なり、多くはJavaScriptでコンテンツを描画し、収集するもののほとんどに人が関わっています。

このガイドでは、チームが今日どのようにウェブスクレイピングAPIを使って公開のソーシャルデータを収集しているかを扱います。どのソースを使うべきか、どのような場合に公式APIの方が適切なのか、まったく異なるプラットフォームをどう一つのデータセットにまとめるか、そして個人データを設計段階から排除する方法についてです。

まず知りたいことを明確にする

ソーシャルデータのプロジェクトは、まず何でも収集してから後で判断しようとすると失敗します。どの問いに答えようとしているのかを先に決めてください。

  • 量: そのブランドはどのくらいの頻度で言及されているか、その頻度は変化しているか。
  • 話題: 人々は何について、どの製品や問題について語っているか。
  • 比較: 自社ブランドへの言及は競合と比べてどうか。
  • インシデント: クレームや模倣品の出品が広がっていないか。

それぞれの問いに必要なフィールドはごくわずかです。投稿のリンク、時刻、本文、そしてソースだけです。投稿者について、それ以上の情報を必要とするプロジェクトはほとんどありません。

ソースの収集ルートを選ぶ

ソース最適なルート
必要を満たす公式APIがあるプラットフォーム利用規約の範囲内で公式APIを使う
公開のフォーラム、コミュニティ掲示板、レビューサイト公開ページの収集
JavaScriptで描画されるページレンダリング対応のウェブスクレイピングAPI
ログインが必要なもの全般収集しない

公式APIが存在し、それが自分たちの量や予算に合う場合は、たいていそれが最も信頼性が高く、明確に許可されたルートです。公式APIが存在しない公開ページについては、ウェブスクレイピングAPIがソーシャルサイトを扱いにくくしている部分、つまりJavaScriptのレンダリング、コンテンツの読み込み待機、特定の国で表示される通りのページ取得を処理してくれます。抽出ルールにより、必要なフィールドは生のHTMLではなくJSONとして返されます。

どのサイトでも公開範囲にとどまってください。ログインの先にあるコンテンツ、非公開グループ、ダイレクトメッセージは対象外です。これはアクセスすることが通常、収集を禁じる利用規約への同意を意味するからであり、また関係する人々がプライバシーを期待しているからでもあります。

すべてのプラットフォームを一つのスキーマに

各ソースはフィールドの名前付けがそれぞれ異なります。フォーラムにはパーマリンクと本文があり、レビューサイトにはリンクとレビュー本文があり、日付は異なる形式とタイムゾーンで来ます。これらを別々に分析すると、比較が成り立たなくなります。収集と同時に、すべてのソースを一つの小さなスキーマにマッピングしてください。

  • source: 投稿がどのソースから来たか。
  • url: 正規化されたアドレス。これにより同じ投稿が重複カウントされない。
  • published_at: UTCでの時刻。
  • text: 空白を正規化した投稿本文。
  • author_key: 投稿者名の代わりに使う仮名化されたキー。

以下のモジュールはこのマッピングを行い、重複したURL(トラッキングパラメータやフラグメントにより、同じ投稿が複数に見えることがよくあります)を除去し、ブランドごとの日次言及数を数えます。

import hashlib
from collections import Counter
from datetime import datetime, timezone
from urllib.parse import urlsplit, urlunsplit

# Where each source keeps the fields we need, after extraction rules have run.
FIELD_MAPS = {
    "forum":  {"url": "permalink", "text": "body", "author": "username", "time": "created"},
    "review": {"url": "link", "text": "review_text", "author": "reviewer", "time": "date"},
}


def canonical(url):
    """Drop query strings and fragments so the same post counts once."""
    parts = urlsplit(url)
    return urlunsplit((parts.scheme, parts.netloc.lower(), parts.path.rstrip("/"), "", ""))


def normalise(source, raw, salt):
    """One post in a common shape, with the author pseudonymised and no other personal data."""
    m = FIELD_MAPS[source]
    when = datetime.fromisoformat(raw[m["time"]].replace("Z", "+00:00")).astimezone(timezone.utc)
    return {
        "source": source,
        "url": canonical(raw[m["url"]]),
        "published_at": when.isoformat(timespec="seconds"),
        "text": " ".join(raw[m["text"]].split()),
        "author_key": hashlib.sha256((salt + raw[m["author"]]).encode()).hexdigest()[:16],
    }


def daily_mentions(posts, brands):
    """Count posts per day that mention each brand, counting each URL once."""
    seen, counts = set(), Counter()
    for post in posts:
        if post["url"] in seen:
            continue
        seen.add(post["url"])
        day = post["published_at"][:10]
        for brand in brands:
            if brand.lower() in post["text"].lower():
                counts[(day, brand)] += 1
    return dict(sorted(counts.items()))

3件の例示レコード(うち1件はトラッキングパラメータ付きの重複)に適用すると、次のようになります。

import os

from social import daily_mentions, normalise

salt = os.environ.get("MENTIONS_SALT", "rotate-me-per-project")
raw = [
    ("forum", {"permalink": "https://forum.example/t/88?ref=home", "body": "Acme kettle died after a week",
               "username": "kitchen_fan", "created": "2026-10-20T08:15:00Z"}),
    ("forum", {"permalink": "https://forum.example/t/88", "body": "Acme kettle died after a week",
               "username": "kitchen_fan", "created": "2026-10-20T08:15:00Z"}),
    ("review", {"link": "https://reviews.example/p/42", "review_text": "Better than my old Brandly one",
                "reviewer": "J. D.", "date": "2026-10-20T19:40:00+02:00"}),
]
posts = [normalise(source, item, salt) for source, item in raw]
print(daily_mentions(posts, ["Acme", "Brandly"]))
{('2026-10-20', 'Acme'): 1, ('2026-10-20', 'Brandly'): 1}

重複は一度だけカウントされ、レビューの現地時刻はUTCに変換され、ユーザー名は出力に一切含まれません。

個人データを、設計段階から排除する

公開された投稿であっても、ヨーロッパをはじめ多くの地域では依然として個人データであり、どれほど公開性が高くてもデータ保護規則が適用されます。最も安全な設計は、その問いに必要な最小限の情報だけを人について保持することです。

  • 投稿者を仮名化する。 ソルト付きハッシュを使えば、ユーザー名を保存せずに、異なる投稿者の数を数えたり、同一アカウントによる繰り返し投稿を見つけたりできます。プロジェクトごとに異なるソルトを使い、秘密に保ってください。
  • プロフィールは収集しない。 フォロワー数や自己紹介文、写真、個人の所在地は、ブランドに関する問いにはほとんど必要ありません。
  • 保持期間を短くする。 集計された件数や話題は保持しておけますが、生のテキストは分析後に削除できることがほとんどです。
  • 集計の形で報告する。 個人を特定できる形ではなく、傾向や事例として公表してください。

データがきれいになった後の分析についてはセンチメント分析のためのソーシャルプラットフォームのスクレイピングのガイドを、クエリセットの構築と地域差の扱いについてはオンラインでのブランド言及の追跡のガイドをご覧ください。

穏やかに収集する

ソーシャルサイトやコミュニティサイトは、そのユーザーのために運営されています。閲覧者が普通にブラウジングする程度のペースで収集し、アーカイブ全体をクロールするよりも新着投稿を一覧表示するページを優先し、収集をやめるよう求められたソースからは収集を停止してください。ブランドモニタリングで、重要なソースを1日1回巡回する以上のことが必要になることはめったにありません。

よくある質問

ソーシャルメディアのデータを収集することは合法ですか。

公開投稿の収集は多くの場合合法ですが、プラットフォームの利用規約、データへのアクセス方法、データ保護法のすべてが適用されます。適合する場合は公式APIを使い、ログインの先にあるコンテンツは避け、個人データはその目的に必要な範囲にとどめてください。具体的なケースについては法的助言を受けてください。

プラットフォームのAPIとウェブスクレイピングAPIのどちらを使うべきですか。

必要なデータと量を利用規約の範囲内でカバーできる場合は、公式APIを使ってください。適切なAPIが存在しない公開ページ、特にJavaScriptで描画されるページには、ウェブスクレイピングAPIを使ってください。

ソーシャルメディアから個人データを収集しないようにするにはどうすればよいですか。

その問いに必要なフィールドだけを収集し、ユーザー名をソルト付きの仮名化キーに置き換え、プロフィールは一切収集せず、生のテキストは必要な期間だけ保持し、結果は集計の形で報告してください。

ソーシャルの言及はどのくらいの頻度で収集すべきですか。

ほとんどのブランドモニタリングでは、1日1回で十分です。ローンチ時やインシデント発生時のみ頻度を上げ、実際にオーディエンスが投稿しているソースに集中してください。

結論

ソーシャルデータが貴重なのは、それが実在の人々が公の場で発言した内容だからであり、まさにそれゆえに慎重な扱いが必要です。まず問いを明確にし、適合する場合は公式APIを、公開ページにはウェブスクレイピングAPIを使い、すべてのソースを一つの小さなスキーマにマッピングし、個人データを最初から設計で排除してください。その結果得られるのは、必要以上の情報を収集することなくブランドに関する問いに答えられるデータセットです。

始める準備はできていますか?

Shifterのレジデンシャルプロキシをお試しください。IP 205M+件、195+カ国、$0.10/GBから。

始める