PythonでPlaywrightを始めてみた|自分のブログから記事一覧をCSV取得

ブラウザ操作をPythonで自動化したいと思ったとき、以前はSeleniumを触っていました。

ただ、待機処理や要素の指定などで何度かつまずき、正直なところ「もう少し分かりやすく書けないかな」と感じる場面もありました。

そこで今回、気になっていた Playwright を改めて触ってみることにしました。

とはいえ、私自身まだPlaywrightを使いこなせているわけではありません。

なので今回は、最初から全部覚えようとせず、

「自分のブログをPlaywrightで操作して、記事タイトルとURLをCSVに保存する」

という小さな課題を作って、実際に動かしながら覚えてみます。

目次

今回やること

今回のゴールは次の4つです。

  • Playwrightで自分のブログを開く
  • ページタイトルを取得する
  • 記事タイトルとURLを取得する
  • CSVファイルに保存する

最終的には、こんな形のCSVを作ります。

Bash
記事タイトル,URL
記事タイトル1,https://example.com/...
記事タイトル2,https://example.com/...

Playwrightとは

Playwrightは、ブラウザ操作を自動化できるツールです。

Pythonから、

  • Webページを開く
  • ボタンをクリックする
  • 入力欄に文字を入れる
  • ページ内の文字を取得する
  • スクリーンショットを撮る

といった操作ができます。

今回はPython版を使います。

詳しい仕様や最新の使い方は、Playwright公式ドキュメント(Python) も参考にしてください。

作業用フォルダと仮想環境を作る

まず、作業用フォルダを作りました。

Bash
cd C:\dev
mkdir playwright-study
cd playwright-study

続いて仮想環境を作ります。

Bash
python -m venv .venv

PowerShellで仮想環境を有効にします。

Bash
.\.venv\Scripts\Activate.ps1

ターミナルの先頭に、

Bash
(.venv)

と表示されればOKです。

Playwrightをインストールする

Playwright本体をインストールします。

Bash
pip install playwright

続いて、操作するブラウザもインストールします。

Bash
playwright install chromium

ここまでで準備完了です。

まずはブログを開いてみる

最初は、とにかくブラウザを開くだけにしました。

main.py を作成して、次のコードを書きます。

Python
from playwright.sync_api import sync_playwright

URL = "https://jiijisanpo.com/"

with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=False,
        slow_mo=500
    )

    page = browser.new_page()

    print("ブログを開きます")
    page.goto(URL)

    print("タイトル:", page.title())

    page.screenshot(
        path="blog.png",
        full_page=True
    )

    print("スクリーンショットを保存しました")

    browser.close()

実行します。

Bash
python main.py

ブラウザが自動で起動し、自分のブログが表示されました。

さらに、

Python
page.title()

でページタイトルを取得し、

Python
page.screenshot()

でスクリーンショットまで保存できました。

ここまででも、

「Pythonから本当にブラウザを操作できている」

という感覚がかなり分かりやすいです。

リンクをクリックしてみる

次に、ブログ内のリンクをクリックしてみました。

使ったのはこのコードです。

Python
page.get_by_role(
    "link",
    name="Pythonの始め方はこちら"
).click()

これで、画面上にある

「Pythonの始め方はこちら」

というリンクをクリックできます。

個人的にPlaywrightで面白いと感じたのが、この書き方です。

Python
get_by_role("link", name="...")

HTMLの細かい指定だけではなく、

「これはリンクで、表示名はこれ」

という、人間が画面を見る感覚に近い指定ができます。

記事タイトルをまとめて取得する

次は、トップページに表示されている記事タイトルを取得してみました。

記事タイトルは h2 要素になっていたので、

Python
titles = page.locator("h2")

と指定します。

そして、

Python
titles.count()

で件数を取得できます。

さらに、

Python
titles.nth(i).inner_text()

で1件ずつタイトルを取り出せます。

コードはこんな形です。

Python
titles = page.locator("h2")

print(f"見つかった見出し数:{titles.count()}")

for i in range(titles.count()):
    title = titles.nth(i).inner_text()
    print(f"{i + 1}. {title}")

実行すると、トップページの記事タイトルが一覧で表示されました。

URLも取得したい

次は、記事タイトルと一緒にURLも取りたくなりました。

最初は単純に、

Python
title.locator("a")

と書きました。

つまり、

「h2の中にあるaタグを探す」

という考え方です。

ところが結果は、

Bash
リンクなし

ばかりになりました。

見た目とHTML構造は違う

ブラウザ上では記事タイトルがリンクに見えるので、

「h2の中にaタグがあるだろう」

と思っていました。

しかし実際のHTML構造はそうではありませんでした。

イメージとしては、

HAML
<a href="記事URL">
    <div>
        <h2>記事タイトル</h2>
    </div>
</a>

のように、h2 の外側をリンクが囲っている構造でした。

そこで、

Python
title.locator("xpath=ancestor::a[1]")

と変更しました。

これは、

「このh2から上方向にたどって、一番近いaタグを探す」

という意味です。

すると、記事URLを取得できました。

ここは今回かなり勉強になった部分でした。

Webページの見た目だけではなく、

HTMLがどんな親子関係になっているかを見ることが大事

だと実感しました。

記事タイトルとURLをCSVへ保存する

最後に、取得した記事タイトルとURLをCSVへ保存します。

完成版は次のコードです。

Python
import csv
from playwright.sync_api import sync_playwright


URL = "https://jiijisanpo.com/"


with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=False,
        slow_mo=300
    )

    page = browser.new_page()
    page.goto(URL)

    titles = page.locator("h2")

    articles = []

    for i in range(titles.count()):
        title = titles.nth(i)

        text = title.inner_text()

        link = title.locator("xpath=ancestor::a[1]")

        if link.count() > 0:
            url = link.get_attribute("href")
        else:
            url = ""

        articles.append([text, url])

    with open(
        "articles.csv",
        "w",
        newline="",
        encoding="utf-8-sig"
    ) as f:

        writer = csv.writer(f)

        writer.writerow([
            "記事タイトル",
            "URL"
        ])

        writer.writerows(articles)

    print(
        f"{len(articles)}件を articles.csv に保存しました"
    )

    browser.close()

実行すると、

Bash
10件を articles.csv に保存しました

と表示され、articles.csv が作成されました。

日本語をExcelで開いたときに文字化けしにくいように、

Python
encoding="utf-8-sig"

を指定しています。

今回覚えたPlaywrightの基本

今回だけでも、いくつか基本操作を触ることができました。

Python
page.goto()

ページを開く。

Python
page.title()

ページタイトルを取得する。

Python
page.get_by_role()

役割や表示名から要素を探す。

Python
page.locator()

ページ内の要素を探す。

Python
inner_text()

表示されている文字を取得する。

Python
get_attribute()

HTML属性を取得する。

こうして小さな目的を1つ決めて進めると、単に機能一覧を読むより理解しやすいと感じました。

Seleniumで苦労した私が感じたこと

まだPlaywrightを触り始めたばかりなので、Seleniumと細かく比較できる段階ではありません。

ただ今回触った範囲では、

Python
page.get_by_role(
    "link",
    name="Pythonの始め方はこちら"
)

のような書き方はかなり分かりやすく感じました。

また、

Python
page.goto()
page.locator()
page.screenshot()

など、何をしているコードなのかが読み取りやすい印象があります。

一方で、今回URL取得でつまずいたように、Playwrightを使えばHTMLを理解しなくてもよい、というわけではありません。

このあたりも実際に触りながら覚えていきたいと思います。

まとめ

今回は、Playwrightの勉強を兼ねて、自分のブログを操作してみました。

最終的に、

ブログを開く → 記事タイトルを取得 → URLを取得 → CSV保存

までできました。

最初からPlaywrightを完璧に理解しようとすると大変ですが、

「小さな実用品を1つ作る」

と決めると、かなり取り組みやすくなります。

私自身まだPlaywrightを使いこなせていません。

だからこそ今後も、実際に小さな課題を作りながら覚えていく予定です。

次回は、

Playwrightのcodegenを使って、ブラウザ操作からコードを自動生成する方法

を試してみます。

目次