第36回「スクレイピング(8)」取得したデータを分析と可視化につなげる

こんにちは、小澤です。

前回は、JavaScriptで動くページとSeleniumの基本について紹介しました。requestsとBeautifulSoupで取得したHTMLの中に目的の情報がない場合、ブラウザを自動操作して、画面に表示されたあとの要素を取得する方法がある、という内容でした。

ここまでの連載では、HTMLの構造を確認し、BeautifulSoupで必要な部分を取り出し、複数ページを巡回し、CSVやExcelに保存し、さらに定期実行やSeleniumの考え方まで見てきました。しかし、スクレイピングは、データを取得したところで終わりではありません。今回は、その次の段階として、取得したデータを分析や可視化につなげる方法を紹介します。分析といっても、いきなり難しい統計処理を行うわけではありません。まずは中身を確認し、空白や重複を整え、件数を数えるところから始めます。

まずは保存したデータを読み込む

前回までに、取得したデータをCSVやExcelとして保存する方法を扱いました。今回は、記事一覧をarticles.csvとして保存している、という前提で考えてみます。CSVファイルは、pandasを使うと簡単に読み込むことができます。

import pandas as pd
 
df = pd.read_csv(“articles.csv”)
 
print(df.head())
print(df.info()) 

head()は、先頭の数行を確認するためのメソッドです。info()を使うと、列名、データ件数、欠損値の有無、データ型などを確認できます。まずは中身を見る、という作業を入れておくと、後の処理でつまずきにくくなります。たとえば、列名が想定と違っていたり、日付が空欄になっていたりすることがあります。保存したあとに一度確認する、という流れを習慣にしておくとよいでしょう。

取得データでよくある問題

Webページから取得したデータには、余計な空白や改行が入っていることがあります。また、同じ記事や商品を何度も保存してしまい、重複した行ができることもあります。前後に空白があるだけで別の値として扱われることもあるため、簡単な整形は重要です。

たとえば、title列の前後に空白が入っている場合は、次のように取り除くことができます。

df[“title”] = df[“title”].str.strip()
df = df.drop_duplicates(subset=[“url”])

str.strip()は、文字列の前後にある空白や改行を取り除きます。drop_duplicates()は、重複した行を削除するためのメソッドです。記事一覧であれば、URLが同じなら同じ記事だと判断できる場合が多いので、url列を基準に重複を取り除いています。このような小さな整形が後の集計結果に影響します。スクレイピングのコードだけでなく、保存後のデータを確認する処理もセットで考えることが大切です。

文字列として入った数値を整える

商品価格やランキングのような数値データを取得する場合、Webページ上では「1,980円」のような文字列として書かれていることが多いです。このままでは、平均を計算したり、大小を比較したりすることができません。分析に使う場合は、カンマや円などの文字を取り除き、数値として扱える形に変換します。

df[“price”] = df[“price”].str.replace(“,”, “”)
df[“price”] = df[“price”].str.replace(“円”, “”)
df[“price”] = df[“price”].astype(int)

このコードでは、price列からカンマと円の文字を取り除き、最後にastype(int)で整数に変換しています。実際のデータでは、「価格未定」や空欄が混ざっている場合もあります。まずは数件のデータで中身を確認し、どのような表記ゆれがあるかを見てから処理を追加すると進めやすいです。

件数を数えて傾向を見る

データをきれいにしたら、まずは件数を数えてみます。たとえば、記事のカテゴリごとに何件あるかを知りたい場合は、value_counts()を使うと簡単です。

category_count = df[“category”].value_counts()
print(category_count)

これだけで、カテゴリごとの件数を確認できます。スクレイピングで集めたデータは、集めた時点では単なる一覧ですが、件数を数えるだけでも傾向が見えてきます。

もう少し集計したい場合は、groupby()を使います。たとえばカテゴリごとの平均価格を見たい場合は、次のように書けます。

price_summary = df.groupby(“category”)[“price”].mean()
print(price_summary) 

groupby()は、指定した列ごとにデータをまとめるためのメソッドです。カテゴリごと、日付ごと、店舗ごとなど、どの単位でまとめたいのかを決めることで、一覧データを分析しやすい形にできます。

日付データを扱う

スクレイピングでは、記事の公開日、更新日、取得日など、日付に関するデータを保存することがあります。時系列で並べたり、日別に件数を集計したりする場合は、日付型に変換しておくと便利です。

df[“date”] = pd.to_datetime(df[“date”])
daily_count = df.groupby(df[“date”].dt.date).size()
print(daily_count)

pd.to_datetime()を使うと、文字列として保存されていた日付を、pandasで扱いやすい日付型に変換できます。そのうえで、dt.dateを使って日付部分だけを取り出し、groupby()で日別の件数を数えています。たとえば、毎日スクレイピングを実行しているような場合、日ごとの記事数や商品数の変化を見ることができます。急に件数が減っていれば、サイト側のHTML構造が変わった可能性もあります。分析のためだけでなく、処理が正常に動いているかを確認する手がかりにもなります。

簡単なグラフにしてみる

集計結果は、数字のままでも確認できますが、グラフにすると変化や偏りが見やすくなります。Pythonではmatplotlibを使うと、pandasで集計した結果をそのままグラフにできます。

import matplotlib.pyplot as plt
 
category_count.plot(kind=”bar”)
plt.tight_layout()
plt.savefig(“category_count.png”)
plt.show()

このコードでは、カテゴリごとの件数を棒グラフとして表示し、category_count.pngという画像ファイルにも保存しています。資料で共有する場合は、画像として保存しておくと扱いやすくなります。ただ、グラフを作ればそれだけで分かりやすくなるわけではありません。項目数が多すぎると読みにくくなります。最初は、件数の棒グラフや日別の折れ線グラフなど、シンプルなものから使うのがよいでしょう。

実務での注意点

スクレイピングで取得したデータを分析に使う場合、特に注意したいのは、データの意味を確認することです。Webページ上の表記は、人間が読むことを前提にしているため、分析しやすい形とは限りません。また、取得したデータをそのまま上書きしてしまうと、後から原因を調べにくくなります。実務では、取得直後の元データと、整形後のデータを分けて保存しておくと安心です。さらに、定期実行している場合は、日付や時刻をファイル名に入れて保存しておくと管理しやすくなります。たとえば、articles_20260730.csvのようにしておけば、いつ取得したデータなのかが分かります。

もちろん、スクレイピングの基本的なマナーも変わりません。利用規約を確認し、必要以上に短い間隔でアクセスしないこと、取得したデータの扱いに注意することは、分析や可視化の段階でも大切です。実在サイトを対象にする場合は、サイトに負荷をかけない設計にすることを忘れないようにしましょう。

今回のまとめ

今回は、スクレイピングで取得したデータを、pandasを使って分析や可視化につなげる方法を紹介しました。まずCSVを読み込み、head()やinfo()で中身を確認しました。次に、空白の除去や重複削除、価格の数値変換など、よくある整形処理を見ました。そのうえで、value_counts()やgroupby()を使って集計し、matplotlibで簡単なグラフにする流れを確認しました。

スクレイピングは、取得して保存するだけではなく、その後にどう確認し、どう整形し、どう使うかまで考えることで、実務に役立つ仕組みになります。最初は小さな集計で十分です。件数を数える、日付ごとの変化を見る、といった基本的な処理から試してみるとよいでしょう。

次回は、スクレイピング処理をもう少し運用しやすくするために、ファイル構成や設定値の分け方、ログやエラー処理の整理について紹介します。コードが長くなってきたときに、どのように分けておくと後から直しやすいのかを見ていきます。次回もお楽しみに。

PAGE TOP