node-fetchでいいじゃん
もともとSeleniumとかPuppeteerとかPlayWrightで当然ながら合法的な範囲内でスクレイピングをしていました。しかし、golangでスクレイピングのスクリプトを書いたあとに、そもそもfetchでもいけるじゃないか、と気づきました。node-fetchで簡単にスクレイピングができるので記事にしてみました。
完成物
import fetch from 'node-fetch';
import { parse } from 'node-html-parser';
const main = async () => {
const url = 'https://qiita.com/';
const response = await fetch(url);
const body = await response.text();
const root = await parse(body);
const h2s = root?.querySelectorAll('h2');
h2s.forEach((element) => {
const text = element.innerText;
console.log({ text });
});
};
main();
結果
{ text: 'Dockerコンテナのpostgresqlがマルウェアに感染した件について' }
{ text: 'Dockerfile ベストプラクティス/2022夏' }
{ text: '「技術記事って、別に書かなくてもよくないすか?」' }
{ text: 'TexTraの翻訳 APIをJavaScriptだけで取得する' }
{ text: '動的計画法の実例: QRコードの最適なエンコードを求める' }
{ text: '全Qiita民に見てほしい!岡田監督のメッセージ:「自ら考えて動く」チームを育てる、グローバル水準の組織作りのメソッド' }
{ text: '【祝!!無限増殖】寝てる間に話題のStable Diffusionが無限に動く仕組みを作ってみた' }
{ text: '6歳娘「ねぇ、パパ!このテストコード、Given-When-Then構文で可読性、高めてみない?」' }
{ text: '【入門】Python を書く前に知っておきたいデータ型のあれこれ' }
{ text: '[Power BI] 新DAX関数 EVALUATEANDLOG を試してみる🎉' }
{ text: '新人エンジニアが先輩に言われたこと4つ' }
{ text: 'Kubernetes 1.25: SIG-CLI (kubectl) の変更内容' }
{ text: 'Elixirで冪根を求めることを楽しむ' }
{ text: '【Windows】Raspberry Pi Pico Wの開発環境の構築とLチカ【Python】' }
{ text: 'ゆめみさんのインターンでモブになってきた話' }
{ text: 'システム運用作業で気を付ける事 まとめ' }
{ text: '僕が考えた最強の作業手順書' }
{ text: '【NestJS】マルチステージビルドでNestJSイメージのサイズを小さくする方法' }
{ text: '【CSS】画像のbefore・afterをスライドさせて、比較できるようなUIを作ってみた。' }
{ text: 'EC2→ECS移行の際に、本番環境へのデプロイにecspressoを用いた話' }
{ text: '【UiPath】バージョン「22.7」Previewリリースまとめ' }
{ text: 'Apple Silicon M2はM1シリーズと比べて命令セットが拡張されている' }
{ text: '【JavaScript】TABキーによる要素のフォーカス送りをグループ内でループさせる' }
{ text: 'Stable DiffusionをAWSのEC2インスタンスで動かすまでの手順' }
{ text: 'チーズのヘタと早すぎる抽象化' }
{ text: 'Unity+MagicOnionでメタバース空間を作ってみる(第二回)' }
{ text: 'Goの fs.FS をOSのファイルシステムにマウントしたい' }
{ text: 'MUI(旧Material-UI)の Container で最大横幅を設定する ~ヘッダーの幅固定もできるよ~' }
{ text: 'Python,Ruby,PHP,Java,JavaScript,Perlの条件分岐の比較' }
{ text: 'UiPath_エクセルでセルの色を塗りつぶしたいな~' }
ひとまずQiitaからh2タグのテキストを全部拾ってくるスクリプトです。あとは適宜Selectorを変更するなり処理してみてください。
あとはcookieが必要なときはcookieをたせます。とあるサイトで18歳以上かどうかを判定するcookieがあったときは
下記のように対応しています。
import fetch from 'node-fetch';
import { parse } from 'node-html-parser';
const main = async () => {
const url = 'https://qiita.com/';
const options = {
headers: {
cookie: 'over18=yes'
}
};
const response = await fetch(url, options);
const body = await response.text();
const root = await parse(body);
const h2s = root?.querySelectorAll('h2');
h2s.forEach((element) => {
const text = element.innerText;
console.log({ text });
});
};
main();
本当にJavaScriptが必要なサイト以外はこんな感じで軽くスクレイピングできます。ブラウザを起動しなくても良いので軽量ですね。