序文
バックエンドの同僚から、多くの映画ダウンロード リソースは Web クローラーでクロールできると聞いていました。当時は挑戦してみたいという気持ちが強くて、学びたいと思っていました。しかし、当時の私はあまりにも怠け者だったので、すぐに幸福を得ることができる人生のあらゆる種類の誘惑に耐えることができませんでした。深刻なビジネスをする時間はありません。この件を数年先延ばしにした。以前、ナゲッツでクローラに関する記事を見たことがあり、その記憶が甦り、今度はクローラのプログラムを書いて、心に溜め込んだバックグラウンドタスクを解放しなければとその時決心しました。心のしこりを解消し、精神的な負担を取り除きました。
エフェクトデモ
クローラーの設定データはconfig.jsに記述されており、クローラープログラムを起動すると1分ごとにjsonファイルが作成され、その内容がクロール対象のWebサイトのデータとなります。
一連の考え
他人のWebサイトのコンテンツを気軽にクロールするのは権利侵害で違法だとネット上で言われているので、プログラマのベースキャンプレアアースの総合記事ランキングデータをクロールするなど、法律に違反しないWebサイトを探しますナゲッツ(ランキング表にはランキング、タイトル、各記事のリンク)、練習用ハンド。最初はすべてが難しいので、どこから始めればよいでしょうか?これは 3 つのステップで実装されます。
- 最初のステップは、対象の Web サイトを分析し、目的のデータを取得する方法を観察することです。
- 2 番目のステップは、データをクロールし、クロールされたデータをローカル ファイルに保存することです。
- 3 番目のステップは、ターゲット Web サイトのコンテンツを定期的にクロールし、定期的にクロールすることです。
対象のWebサイトを分析する
まず、Nuggetsの記事一覧・総合コラムページをレンダリングするとこんな感じになるのですが、Webページのソースコードを確認すると、ページランキングのデータが動的に取得されてレンダリングされていることがわかります。
この点は、 Webページの静的コンテンツを取得した後のデータ抽出操作に基づいて、静的なWebコンテンツしかnode-https.get+cheerio
ため、インターネット上で広く普及している組み合わせ方式を使用できないと判断します。この記事で選択した対象ページのデータは動的にレンダリングされるため、 Douban Moviesのような Web サイトのクローリングにはまったく問題ありません。ナゲッツの記事ランキング リストなど、コンテンツが動的データでレンダリングされるページをクロールしたい場合、それは無力であるように思えます。それは続行できないという意味ですか?今回はどうしてそんな簡単に諦めてしまうのでしょうか?探し回って試してみた結果、ついに救世主を見つけたのですが、どのような方法をとったのでしょうか?node-https.get
cheerio
node-https.get
次に、記事ランキングの各記事のランキング、タイトル、リンク情報をクロールしたい場合は、ページの dom 構造を観察して開始点を見つける必要があります。以下の図で丸で囲まれたいくつかのページ要素のスタイル名に従って、記事ランキング リストの各記事の 3 つの項目を dom ツリーから解析できます。
デバッグコンソールで実行し、document.querySelector(".hot-list > .article-item-link > .article-item-wrap > .article-item-left >.article-number")
取得した内容が正しいか確認します。はい、それが私たちが望んでいることです。さらに、記事のリンクに Web サイトのドメイン名が欠落していることが判明したため、独自に記事のリンクを追加しました。ページ データを解析するための完全なコードは次のとおりです。
js
コードをコピーする
// 操作dom, 获取文章列表页面的内容 function getData(pageOrigin) { const list = []; const itemSelector = ".hot-list >.article-item-link"; const commonSelector = ".article-item-wrap > .article-item-left"; const rankSelector = [commonSelector, ".article-number"].join(">"); const titleSelector = [commonSelector, ".article-detail > .aticle-title"].join(">"); document.querySelectorAll(itemSelector).forEach((ele) => { // const rank = ele.querySelector(rankSelector).innerText.replace(/[\n\s]/g, ""); const rank = ele.querySelector(rankSelector).innerText; const title = ele.querySelector(titleSelector).getAttribute("title"); const link = `${pageOrigin}${ele.getAttribute("href")}`; list.push({ 排名: rank, 标题: title, 链接: link, }); }); return list; }
クロールデータ
Puppeteer
私たちの偉大なマスターをデビューに招待しました。もし彼がその場面を救っていなかったら、今回も私は顔を平手打ちされていたでしょう。まず簡単な自己紹介をします。Puppeteer は、Chrome ブラウザの動作をシミュレートするために 2017 年に Chrome 開発チームによってリリースされた Node.js パッケージです。詳しい紹介をさせていただきます。
パペッティアとは何ですか?
- デフォルトでは、Puppeteer は Chrome をヘッドレスで起動しますが、パラメータ制御を通じてインターフェイスを使用して Chrome を起動することもできます
- Puppeteer は、Chrome DevTools プロトコルを通じて Chromium/Chrome ブラウザの動作を制御する一連の API を提供します。
- Puppeteer はデフォルトで最新の Chromium バージョンをバインドしますが、他のバージョンをバインドするように設定することもできます
上記は、ヘッドレス (ヘッドレス ブラウザ) とは何なのかという別の概念につながります。ヘッドレスブラウザとは、ブラウザが非インターフェース環境で動作することを意味し、人間の介入なしにコマンドラインやプログラミング言語を通じてブラウザが操作され、動作がより安定します。
パペッティアは何ができるの?
- SPA または SSR Web サイトをクロールする
- Web ページのスクリーンショットを撮るか、PDF ファイルを生成します
- UI自動テスト、フォーム送信、キーボード入力、クリックおよびその他の動作をシミュレートします。
- Web サイトのタイムラインをキャプチャして、パフォーマンスの問題の診断に役立てます。
- 最新の自動テスト環境を作成し、最新の js と最新の Chrome ブラウザを使用してテスト ケースを実行します。
- Chrome 拡張機能をテストする
- ...
必要なのは、動的データのレンダリングが完了した後に Puppeteer がページ関数をクロールできることです。どうやってするの?スペースの制限のため、この記事では使用されている Puppeteer API の一部に焦点を当てます。完全な API を知りたい場合は、公式ドキュメントを参照してください。
使用される Puppeteer API の概要
まず、Puppeteer インスタンスの作成方法を見て、このインスタンスの作成に関連する API について説明します。
js
コードをコピーする
const puppeteer = require("puppeteer"); // 使用 puppeteer.launch 启动 Chrome (async () => { const browser = await puppeteer.launch({ headless: false, // 有浏览器界面启动 slowMo: 100, // 放慢浏览器执行速度,方便测试观察 args: [ // 启动 Chrome 的参数,详见上文中的介绍 "–no-sandbox", "--window-size=1280,960", ], }); const page = await browser.newPage(); await page.goto("https://www.baidu.com"); const articleList = await page.evaluate((pageOrigin) => { return getData(); // 操作dom, 获取文章列表页面的内容 function getData() {} }, crawlPageOrigin); await page.close(); await browser.close(); })();
- puppeteer.launch : puppeteer は、ブラウザ インスタンスを作成するための 2 つの方法を提供します: puppeteer.launch は毎回 Chrome インスタンスを開始し、puppeteer.connect は同じ Chrome インスタンスを共有して、ブラウザの起動と終了にかかる時間を短縮します。 puppeteer.launch のパラメータ(下の図に示すように)、そしてより重要なものは headless です。これが false に設定されている場合、インターフェイスを備えたブラウザがデバッグのために起動されます。一般に、デフォルト値は true または 'new ' が使用されます (新しいバージョンには 'new' が使用されます)。
- Browser : ブラウザ インスタンスに対応して、ブラウザには複数の BrowserContext を含めることができます。
- Page :browserContext.newPage() または browser.newPage() によって作成されたタブ ページを示します。browser.newPage() はページの作成時にデフォルトの BrowserContext を使用します。
- page.goto : 新しいページを開き、waitUtil と timeout の 2 つのパラメータを指定します。waitUtil は、何かが表示されるまで実行が完了することを意味し、timeout は、この時間が経過しても終了しない場合に例外がスローされることを意味します。
js
コードをコピーする
await page.goto('https://www.baidu.com', { timeout: 30 * 1000, waitUntil: [ 'load', // 等待 “load” 事件触发 'domcontentloaded', // 等待 “domcontentloaded” 事件触发 'networkidle0', // 在 500ms 内没有任何网络连接 'networkidle2' // 在 500ms 内网络连接个数不超过 2 个 ] });
- page.evaluate (pageFunction[, ...args])
ブラウザ環境で機能を実行します。この方法は初心者向けに設計されています。まず第一に、理解すべき重要な概念があります两个独立的环境
。Puppeteer を使用する場合、ほぼ確実に次の 2 つの環境間でのデータ交換が発生します。これら 2 つの環境を理解することが重要です运行 Puppeteer 的 Node.js 环境
。Puppeteer 操作页面的 Page DOM环境
js
コードをコピーする
// 外面是node环境,不能操作dom const articleList = await page.evaluate((pageOrigin) => { // 里面是无头浏览器环境,可以操作dom return getData(); }, crawlPageOrigin);
page.evaluate
内部環境と外部環境は直接接続されておらず、page.evaluate
メソッド。パラメータは変数のみであり、関数を渡すことはできません。関数を渡すとnullになります。関数の受け渡し方法は、page.exposeFunction("函数名", 函数);
ノード環境で定義した関数をPage Dom環境に渡すことですが、渡されたノード関数はPage Dom環境から渡されるdomパラメータを受け取ることができません。ただし、Page Dom環境で処理した結果は外部ノード環境に返すことができます。ノード環境とPage Dom環境間のデータフローを実現します。
クローラーを実装する
上記の知識を基礎として、puppeteer を使用してページ データをクロールするプログラムを作成してみましょう。
js
コードをコピーする
// 无头浏览器模块 const puppeteer = require("puppeteer"); // 目标页面 const crawlPage="https://juejin.cn/hot/articles/1"; // 网页爬虫 async function crawler() { //创建实例 const browser = await puppeteer.launch({ //无浏览器界面启动 headless: "new", }); // 新开一个tab页面 const page = await browser.newPage(); // 加载目标页,在 500ms 内没有任何网络请求才算加载完 await page.goto(crawlPage, { waitUntil: "networkidle0" }); // 在无头浏览器页面dom环境,获取页面数据 const articleList = await page.evaluate(() => { return getData(); // 操作dom, 获取文章列表页面的内容 function getData() { // ... return list; } }); // 关闭tab页 await page.close(); // 关闭实例 await browser.close(); }
スケジュールされたクロール
クローラー プログラムは通常、ターゲット ページのコンテンツを定期的にクロールします。では、Web ページを定期的にクロールするアクションを実装するにはどうすればよいでしょうか? node-schedule
Node には、タスクを定期的に実行できる と呼ばれるツールキットがあります。
インストール
Cシャープ
コードをコピーする
pnpm add node-schedule
移行
js
コードをコピーする
const schedule = require("node-schedule"); // 创建任务,任务名称必须唯一 schedule.scheduleJob(`任务名称`, `时间`, () => { }); // 删除任务 schedule.scheduledJobs[`任务名称`].cancel();
時刻形式
フォーマット | 意味 |
---|---|
10 * * * * * | 毎分10秒目に発火 |
10 20 * * * * | 毎時20分10秒にトリガー |
10 20 1 * * * | 毎日午前 1 時 20 分 10 秒にトリガーされます |
10 20 1 2 * * | 毎月 2 日の 1:20:10 にトリガーされます |
2023 年 10 20 20 5 * | 2023 年 5 月 20 日の 1:20:10 にトリガーされました |
10 20 1 * * 1 | 毎週月曜日の 1:20:10 にトリガーされます |
次に、Web クローラーを定期的に呼び出す機能を実装し、node-schedule
タスクの作成と削除の 2 つのメソッドをカプセル化してみましょう。ここでのタイミングタスクのタイミング時間は、0 \* \* \* \* \*
結果をより早く確認するために設定されており、実際に Web ページのコンテンツをクロールする場合には、必ずしもそれほど高い頻度は必要ありません。
時限クロールの実装
js
コードをコピーする
// 定时任务模块 const Alarm = require("./alarm"); // 爬虫模块 const crawler = require("./crawler"); main(); function main() { new Alarm({ // 定时任务名称 alarmName: "自动爬虫任务-20230520", // 定时任务计划 alarmTime: "0 * * * * *", }).create(() =>{ crawler(); }); }
alarm.js
コードは以下のように表示されます。
js
コードをコピーする
const schedule = require("node-schedule"); class Alarm { constructor({ alarmName, alarmTime }) { this.alarmName = alarmName; // 定时任务名称 this.alarmTime = alarmTime; // 定时任务时间 } // 创建定时任务 async create(callback) { schedule.scheduleJob(`${this.alarmName}`, `${this.alarmTime}`, callback); } // 删除定时任务 delete() { if (schedule.scheduledJobs[this.alarmName]) { schedule.scheduledJobs[this.alarmName].cancel(); return true; } return false; } } module.exports = Alarm;
nodemon
また、ノード開発を行う際には、ファイル変更後のホットスタートを実現できるこのノードツールキットをインストールするのがベストだと感じています。これは、開発ページのコードを変更した後に自動的にページを更新するのと同じくらい便利です。
コードをコピーする
pnpm install -g nodemon
スケジュールされたタスクの実行効果は次のとおりです。
エピローグ
ずっと爬虫類に興味があり、ぜひ自分でも実現したいと思っていたのですが、今日やっと旧フラッグが完成しました。また、クローラ機能を書き終えた後にクローラプログラムを見直したところ、まだまだ改善の余地があると感じました。たとえば、データのクエリをより効率的かつ便利にするためにデータベースにデータを書き込みます。別の例としては、より分かりやすい方法でデータを表示するビジュアル ページを作成することなどが挙げられます。時間とエネルギーが限られているので、時間があるときに後で改善します。この記事で書かれたクローラー アプリケーションは実用的な価値は高くなく、純粋に練習と新しい知識の学習を目的としています。Web クローラーにも興味がある場合は、このアドレスをクリックして演習をダウンロードし、質問がある場合は一緒に議論してください。
リンク: https://juejin.cn/post/7235137314401157180