Think Big Act Local

Beautiful Soupでスクレイピングした情報をmicroCMSに保存する

開発日誌

Beautiful Soupでスクレイピングした情報をmicroCMSに保存する

欲しい情報がWebサイト上でしかなかったり、複数ページの情報を集約したい場合などスクレイピングしたいケースがあります。
今回はPythonの人気ライブラリBeautiful Soupでスクレイピングし、そのデータをmicroCMSに書き込んでAPI化する流れを紹介します。

Beautiful Soupでスクレイピング

スクレイピングツールは色々な種類がありますが、自分が選ぶときに重要視しているのは簡単に使えるかどうか、言葉を選ばずに言えば雰囲気で実装を進められるかどうか、です。
スクレイピングはデータを集める手段で、実際に実現したいことはそのデータを使った先にあると思います。データ収集は大事ですが、できるだけ時短で行えるかは大事なポイントです。

Beautiful SoupはDOMやCSSセレクタで要素を指定するなど大体やりたいことはできますし、テキストの処理など細かいところまで気が利いています。具体的な使い方は以下の記事がわかりやすいです:
https://qiita.com/Chanmoro/items/db51658b073acddea4ac

microCMSにデータ保存

スクレイピングしたデータは利用しやすい形で保存します。データストアは色々な選択肢があると思いますが、今回はmicroCMSに保存してみます。
理由は以前の記事で詳しく書きました。
https://himaratsu.com/scraping-to-microcms/

全文検索に対応していたりリッチな入稿画面も使えたりと便利です。ちなみにデータ数は10,000行まで無料です。(料金プラン

実装してみる

Beautiful Soupでページを読み込む

今回はサンプルとして、このブログ(himaratsu.com)のトップページをスクレイピングして記事一覧のAPIを作成してみます。

↑この部分をスクレイピングする

実装はこんな感じになります。

import requests
from bs4 import BeautifulSoup

page_url = "https://himaratsu.com"

res = requests.get(page_url)
soup = BeautifulSoup(res.text, 'html.parser')

entries = soup.select('#__layout > div > div > div.divider > div > ul:nth-child(3) > li')
print(entries)


これを main.py という名前で保存します。実行してみると以下の内容が取得できます。

% python main.py
[<li class="list" data-v-5b4a4c79=""><a class="link" data-v-5b4a4c79="" href="/firebase-to-microcms/"><picture data-v-5b4a4c79=""><source data-srcset="https://images.microcms-assets.io/assets/78a63137199b497c83483af900a61ebb/0ae9abc6a97d4a4681d484f846593093/social.png?w=670&fm=webp" data-v-5b4a4c79="" type="image/webp"/> <img alt="" class="ogimage lazyload" data-src="https://images.microcms-assets.io/assets/78a63137199b497c83483af900a61ebb/0ae9abc6a97d4a4681d484f846593093/social.png?w=670" data-v-5b4a4c79=""/></picture> <dl class="content" data-v-5b4a4c79=""><dt class="title" data-v-5b4a4c79="">microCMSのWRITE APIを使ってFirebaseのデータをmicroCMSに移行する</dt> <dd data-v-5b4a4c79=""><div data-v-3217003c="" data-v-5b4a4c79=""><span class="category" data-v-3217003c="">開発日誌</span> <div class="meta" data-v-3217003c=""><span class="timestamp" data-v-3217003c=""><img alt="" data-v-3217003c="" src="/images/icon_clock.svg"/> <time data-v-3217003c="" datetime="2021-09-16">
        2021/09/16
      </time></span></div></div></dd></dl></a></li>, 
      // ... (省略) 
]

内容を見てみると記事一覧のデータが取れてそうですね。

ここで、ソースコードの中に以下の記述について、

entries = soup.select('#__layout > div > div > div.divider > div > ul:nth-child(3) > li')

この select に渡している '#__layout...' はどう決めれば良いでしょうか?

HTML構造を自分で読み解いても良いですが、ブラウザの検証ツールを使うともっと簡単です。

こんな感じで対象の要素の上で右クリック > 「検証」を選び、


右ペインに出てくる検証ツールで、対象のDOM上で右クリック > 「Copy」>「Copy selector」とします。
そうすると以下のセレクタがコピーできます。

'#__layout > div > div > div.divider > div > ul:nth-child(3) > li:nth-child(1)'

最後の li の末尾の :nth-child(1) は「1番目の要素」という指定で、今回は記事一覧のすべてのDOMが欲しいので消しておきましょう。
実際には試行錯誤しながら実装を進めることになると思いますが、検証ツールと組み合わせることでかなり効率化できます。

欲しい情報を取得する

大枠の記事DOMが取れたので、その中の情報をパースしましょう。今回は「記事タイトル」と「記事URL」をパースすることにします。
先ほどのDOMをよく見て、こんな感じで書きました。

for entry in entries:
    title = entry.select_one('dt.title').get_text()
    link = entry.select_one('a.link')['href']
    data = {
        "title": title,
        "link": link
    }
    print(data)

これを実行すると以下のようになっています。

{'title': 'microCMSのWRITE APIを使ってFirebaseのデータをmicroCMSに移行する', 'link': '/firebase-to-microcms/'}
{'title': 'SwiftUIでScrollViewの中にWebViewを配置する', 'link': '/swiftui-webview-in-scrollview/'}
...省略

無事取れていますね。次はこのデータをmicroCMSに保存していきます。

microCMSのサービスの設定

microCMSのアカウント登録、サービス作成は済ませておいてください。
公式のブログが画像つきで分かりやすいと思います。

APIの作成で、こんな感じでポチポチとAPIスキーマを定義します。

デフォルトではGET以外のHTTPメソッドはOFFになっています。今回はデータ追加したいのでPOSTを許可します。

最後に書き込み用のAPI-KEYを発行します。

これで準備OKです。

microCMSにデータを保存する

microCMSへの書き込みはPOSTで値を投げるだけで良いので、以下のようなメソッドを準備します。

import json
import urllib.request

def request_post(url, data_dict):
    try:
        headers = {"Content-Type": "application/json",
                   "X-WRITE-API-KEY": "<YOUR_WRITE_API_KEY>"}

        data = json.dumps(data_dict).encode("utf-8")

        request = urllib.request.Request(url, data, method='POST', headers=headers)
        response = urllib.request.urlopen(request)
        content = response.read().decode('utf-8')

        return content
    except Exception as e:
        raise e


このメソッドを先ほどの記事一覧の実装から呼び出しましょう。

for entry in entries:
    title = entry.select_one('dt.title').get_text()
    link = entry.select_one('a.link')['href']
    data = {
        "title": title,
        "link": link
    }
    request_post("https://<YOUR_SERVICE_DOMAIN>.microcms.io/api/v1/entries", data)

スクリプトを実行するとデータが登録されていきます。


こんな感じでデータが登録できました。ちゃんと入ってますね。


APIプレビューを使ってレスポンスの形を確認できます。パラメータなどもここで色々試せます。

APIはページング、条件を絞っての取得、全文検索などに対応しており多機能です。あとはこのAPIを使ってWebサービスやアプリを開発していけばOKです。
データの値の変更が必要になった時もmicroCMSの画面から簡単に更新できます。

まとめ

Python + Beautiful Soup + microCMS でWebサイトを即席でAPI化する方法の紹介でした。
データストアとしてmicroCMSを利用することで強力なAPIが作れますし、データの更新のハードルも下げてくれるので良い構成だと思います。

最後に、スクレイピングはマナーを節度をもって行いましょう。

ABOUT ME

himara2
Swift, Python, Flutterなどを書いて過ごしてます。