Closed7

Playwrightでスクレイピングをできるようにしよう。

ピン留めされたアイテム
masa5714masa5714

参考にして頂いているか分からないので、
積極的に「いいね!」を押して頂けるならば記事メンテナンスを継続していこうと思います!

2024年4月2日追記
Playwrightでスクレイピングするための知識を大量に盛り込んだ記事を書きました!

基礎的な内容からCanvasKitのサイトのスクレイピングというマニアックなものまで扱っています。
スクレイピング関連の記事としてはかなり豊富な情報量となっています。

プロキシを刺しながら低コストでスクレイピングするためのアイデアも取り扱っています。

ぜひご覧ください!

https://zenn.dev/masa5714/articles/9328c553bac649

▲2024年4月2日全文書き直しました!

記事を気に入って頂けましたらチップとして WebShare のアフィリエイトリンクを踏んで頂けるとすごく嬉しいです!(プロキシ使う予定がある場合。)

masa5714masa5714

はじめに

スクレイピングをする際にPlaywrightが最善かどうかを判断しましょう。
従来のHTTPリクエストだけでHTML取得できる場合はPlaywright不要です。node-fetchとか色々な方法で試してみてください。

SPAなどのJS経由で動くものはPlaywrightを用いてスクレイピングを行いましょう。
また、SSRしてくれるようなNext.jsのページであればPlaywright無しでもスクレイピング可能です。この方法とか使えると思います。

Playwirghtでスクレイピングを行うための準備(Playwrightをインストールする)

スクレイピング用のプロジェクトフォルダで下記コマンドを実行します。

npm init playwright@latest

色々と聞かれるので、そのまま Enter で進んで頂いて大丈夫です。

上記のようなファイル群が生成されます。

削除してもいいもの

  • testsディレクトリ
  • tests-examplesディレクトリ

は不要なので削除して頂いて問題ありません。

ファイルの説明

playwright.config.ts

Playwright の test 関数で実行したときに適用される設定ファイルです。
スクレイピングにおいてはtest関数を使う必要はないので、ここでは触れません。

masa5714masa5714

TypeScriptが動く環境を作ろう

npm install ts-node @types/node

ts-node は、TypeScriptのファイルをnode.jsで動かすためのものです。
ターミナルから npx ts-node hoge.ts のように叩くことで利用できます。

masa5714masa5714

Playwrightで Hello World! しよう

とりあえず開発環境が整ったのか確認したいと思います。

プロジェクトのルートディレクトリに index.ts というファイルを作り、
下記の記述をしておきましょう。

index.ts
import { chromium } from "playwright";

(async () => {
  const browser = await chromium.launch({
    headless: false,
  });
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto("https://yahoo.co.jp");

  await page.close(); // ページを閉じる
  await browser.close(); // ブラウザを閉じる
})();

そして、ターミナルから下記を叩きます。

npx ts-node index.ts

※ ts-node経由でindex.tsを実行するというコマンドです。

Chromeっぽいブラウザ(Chromium)で Yahoo!JAPAN のページが表示されれば準備OKです!
ターミナル上でタスクが実行されたままになっていると思うので、Ctrl + Cで止めておきましょう。

これでスクレイピングの環境が整いました。

masa5714masa5714

Playwright の基礎知識

async関数で実行する必要がある

Playwrightはブラウザに指示を出して、その結果をブラウザから受け取ります。
そのため、基本的には await で結果を待つことになるので、 async関数で実行する必要があります。

(async () => {
  const browser = await chromium .... // 省略
})()

のように記述しましょう。

masa5714masa5714

最低限必要な記述

import { chromium } from "playwright";

(async () => {
  const browser = await chromium.launch({
    headless: false,
  });
  const context = await browser.newContext();
  const page = await context.newPage();
  await page.goto("https://yahoo.co.jp");

  await browser.close();
})();

使いたいブラウザを指定する

index.ts
import { chromium } from "playwright";

Chromiumブラウザの他に、import { firefox }import { webkit } も使えます。

ブラウザを立ち上げる

index.ts
const browser = await chromium.launch({
  headless: false,
});

最短の記述は const browser = await await chromium.launch() です。
スクレイピングにおいてはブラウザ上の動きも見えていた方が便利なので、オプションで headless: false によって、ヘッドレスブラウザを無効化しています。パフォーマンスが気になるようであれば、ヘッドレスブラウザを利用すると良いでしょう。

コンテキストを分ける

index.ts
const context = await browser.newContext();

この記述は必須ではありませんが、一応書くようにしています。
コンテキストの動きとしては、新しいウィンドウのブラウザのようなイメージです。
ウィンドウを指定して作業を振り分けることができますね。

タブを開く

index.ts
const page = await context.newPage();

指定したウィンドウのブラウザに新しいタブを開きます。

対象のURLをブラウザで開く

index.ts
await page.goto("https://yahoo.co.jp");

指定したURL( この例では https://yahoo.co.jp )を指定したタブで開きます。

作業を完了する

index.ts
await page.close(); // 指定したタブだけを閉じる
await context.close(); // 指定したウィンドウだけを閉じる
await browser.close(); // 全てのブラウザを閉じて完全に終了

作業の完了はいくつか方法があります。
完全に終わるのは最後の await browser.close() です。
この辺りは動かしながら色々試してみてください。(ターミナルが終了を検出してくれるのはどれか、とか。)

masa5714masa5714

スクレイピングに必要な知識

1. プロキシを使おう

自宅のネット環境でそのままスクレイピングをすると最悪ブロッキングされてしまいます。
普段利用するサービスでブロックされてしまうと、かなり怠い(VPNなどで回避する必要が出てしまう)ので、最初からプロキシを適用した状態でスクレイピングするようにしましょう。

プロキシを適用することで、自分のIPアドレスを露出することなくサイトにアクセスできるので、ブロッキングされたとしてもプロキシのIPアドレスが犠牲になるだけで済みます。プロキシを切り替えればIPアドレスも切り替わります。

2. プロキシを使うときは帯域幅を意識しよう

有料のプロキシサービスでは、帯域幅によって追加課金が必要なケースがほとんどです。
低コストでスクレイピングするためにも、帯域幅は意識しておきましょう。
スクレイピングに不要な特に重いデータ(画像、Webフォント)を無効化しておくことをオススメします。

const browser = await chromium.launch({
  args: ["--blink-settings=imagesEnabled=false", "--disable-remote-fonts"],
})

このオプションを付けておけば画像とWebフォントを無効化できます。

このスクラップは2024/04/02にクローズされました