🤖
[Playwight] TSで動的サイトをスクレイピング
はじめに
動的なサイトとは、JSによるDOMの更新が行われるサイト。
静的なサイトと違って、URLを指定してHTMLを取得し、スクレイピングをしようとしてもうまくいかない。(その時点ではJSにより生成される本体のコードを取得できていないから)
よって、Playwright
やpuppeteer
、selenium
などのヘッドレスブラウザを操作するライブラリを使って実際にサイトにアクセスすることで、DOM操作後のHTMLが取得できます。
今回は、
- シンプル
- 動作の軽さ
の点から、Playwright
を使用します。
動作環境
-
mac
: System Version: macOS 14.4 (23E214) -
node
: v22.2.0 -
Playwright
: 1.45.3
手順
前提
以下の動的なサイトをスクレイピングします。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example of Dynamic content for html</title>
</head>
<body>
<div id="content">Loading...</div>
<script>
document.addEventListener("DOMContentLoaded",(event)=>{
setTimeout(()=>{
document.getElementById("content").innerHTML="Hello World!";
},1000);
})
</script>
</body>
</html>
- アクセスすると、
Loading...
と表示される - 1秒後に
Hello World!
に変わる
-
axios
やcheerio
などを使ってHTMLを取得するだけなら、Loading...
しか取得できない
Playwright
を使ってHello World!を取得する
% npm install playwright -D
playwright.ts
import { chromium } from 'playwright';
(async () => {
const url = "http://127.0.0.1:5500/index.html";
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url);
await page.waitForSelector("#content");
await page.waitForFunction(
selector => document.querySelector(selector)?.innerHTML !== "Loading...",
'#content'
)
const content = await page.$eval("#content", el => el.innerHTML);
console.log("content", content);
await browser.close();
})();
- ヘッドレスChromiumを起動
- URL先に移動
-
#content
が読み込まれるまで待機 -
#content
がLoading...(最初の文字列)から変更されるまで待機 -
#content
の中身を取得
% npm run dev
> type_scraping@1.0.0 dev
> ts-node ./src/playwright.ts
content: Hello World!
Discussion