Chrome制御 (puppeteer)

A-Parserは、人気のライブラリpuppeteerを使用して、ページのダウンロードとレンダリングのエンジンとしてChrome (Chromium)ブラウザを使用することを可能にします。
A-Parserと連携してpuppeteerを使用する主な利点:
- 各ブラウザタブごとの個別プロキシのサポート
- ブラウザタブのマルチスレッド管理
- リクエストのインターセプト
- キュー管理、クエリ形成、結果処理に関するA-Parserの全機能
Chromeブラウザの使用により、以下の可能性が開かれます:
DOMおよびJavaScriptのレンダリング- サイト要素とのインタラクティブな操作:
- フォームへの入力
- リンクのクリック
- drag & drop
- ファイルのアップロード
- マウスのエミュレーション
- その他、あらゆる標準的なアクションを自動化可能
- ブラウザChromiumはユーザーが使用するものと酷似しているため、多様なアンチスクレイピング保護をより簡単に回避可能
Headlessモード(ブラウザのグラフィカルインターフェースなし)での動作が可能で、リソースを節約し、グラフィカル環境のないサーバーでもブラウザを実行可能
ブラウザの動作は、通常のA-Parserスレッドよりもリソース(CPU、メモリ)を大幅に消費することを考慮する必要があります。
サイトの複雑さに応じて、利用可能なCPUコア1つにつき1〜2個以下のスレッド(ブラウザタブ)を使用することをお勧めします。例えば、8コアプロセッサの場合は8〜16タブです。
使用例
スクレイパーChrome::ScreenshotMaker2を例に説明します:
- スクレイパーは指定されたサイズのサイトのスクリーンショットを作成し、画像を縮小(スケーリング)することもできます
- オプションでプロキシを使用できます
- A-Parserの各スレッドに対して個別のブラウザタブを作成します
import { BaseParser, PuppeteerTypes } from 'a-parser-types';
let browser: PuppeteerTypes.Browser;
let jimp;
class JS_Chrome_ScreenshotsMaker2 extends BaseParser {
static defaultConf: typeof BaseParser.defaultConf = {
version: '0.2.1',
results: {
flat: [
['screenshot', 'PNG screenshot'],
]
},
results_format: '$screenshot',
load_timeout: 30,
width: 1024,
height: 768,
log_screenshots: 0,
headless: 1,
};
static editableConf: typeof BaseParser.editableConf = [
['log_screenshots', ['checkbox', 'Log Screenshots']],
['width', ['textfield', 'Viewport Width']],
['height', ['textfield', 'Viewport Height']],
['resize_width', ['textfield', 'Resize Width']],
['resize_height', ['textfield', 'Resize Height']],
['headless', ['checkbox', 'Chrome Headless']],
];
async init() {
// ブラウザを初期化
browser = await this.puppeteer.launch({
headless: this.conf.headless,
logConnections: false,
defaultViewport: {
width: parseInt(this.conf.width),
height: parseInt(this.conf.height),
}
});
if (this.conf.resize_width) {
// スクリーンショットのリサイズが必要な場合はjimpモジュールを読み込む
jimp = require('jimp');
};
};
async destroy() {
// タスク完了時にブラウザを閉じる
if (browser)
await browser.close();
}
page: PuppeteerTypes.Page;
async threadInit() {
// スレッド初期化時にブラウザページを作成
this.page = await browser.newPage();
// 標準的なpuppeteerメソッド
await this.page.setCacheEnabled(true);
await this.page.setDefaultNavigationTimeout(this.conf.timeout * 1000);
// このページにプロキシを使用するようA-Parserに指示
await this.puppeteer.setPageUseProxy(this.page);
this.logger.put(`New page created for thread #${this.threadId}`);
}
async parse(set, results) {
const self = this;
const { conf, page } = self;
for (let attempt = 1; attempt <= conf.proxyretries; attempt++) {
try {
self.logger.put(`Attempt #${attempt}`);
// クエリで指定されたページに移動
await page.goto(set.query);
// スクリーンショット用にスクロールバーを非表示にする
await page.evaluate(() => { document.querySelector('html').style.overflow = 'hidden'; });
// スクリーンショットを取得
results.screenshot = await page.screenshot();
if (parseInt(conf.resize_width)) {
// 必要に応じて画像をリサイズ
let image = await jimp.read(results.screenshot);
image.resize(parseInt(conf.resize_width), parseInt(conf.resize_height));
results.screenshot = await image.getBufferAsync('image/png');
}
self.logger.put(`Screenshot(${attempt}): OK, size: ${parseInt("" + (results.screenshot.length / 1024))}KB`);
if (conf.log_screenshots)
self.logger.putHTML("<img src='data:image/png;base64," + results.screenshot.toString('base64') + "'>");
results.success = 1;
// ブラウザがkeep-aliveを使用するため、現在の接続を閉じる
await self.puppeteer.closeActiveConnections();
break;
}
catch (error) {
self.logger.put(`Fetch page error: ${error}`);
// ブラウザがkeep-aliveを使用するため、現在の接続を閉じる
await self.puppeteer.closeActiveConnections();
// ブラウザタブのプロキシを変更
await self.proxy.next();
}
}
return results;
}
}
この例は、各タブで異なるプロキシを使用する簡便さと、マルチスレッド動作(1スレッド = 1ブラウザタブ)を示しています。
メソッドの説明
await this.puppeteer.launch(opts?)
このメソッドは、puppeteerライブラリの.launchメソッドに似ており、必要なオプションoptsを使用してChromiumブラウザを起動します。主な違いは、A-Parserとの統合、各タブのプロキシサポート、および追加オプションの存在です:
logConnections?: boolean
すべての接続(プロキシ使用の有無に関わらず)のロギングを有効にします。ログ出力はスレッドごとに個別に行われます。
stealth?: boolean
puppeteer-extraプラグインを使用して、Chromiumを本物のChromeに偽装します。
stealthOpts?: any
puppeteer-extraプラグイン用の追加オプション。
extraPlugins?: array
puppeteer-extra/packagesのような追加プラグインの使用。

その他のオプション
その他のすべての起動オプションについては、puppeteerのオリジナルドキュメントを参照してください。
await this.puppeteer.setPageUseProxy(page)
このメソッドは、プロキシを正しく動作させるためにブラウザページをA-Parserスレッドに関連付けます。ページ作成直後に呼び出す必要があります:
const page = await browser.newPage();
await this.puppeteer.setPageUseProxy(page);
await this.puppeteer.closeActiveConnections(page?)
このメソッドは、リクエスト処理の完了後、または次の試行を処理するためにプロキシを変更する前に呼び出す必要があります。
Chromeブラウザはデフォルトで接続先のサイトとの接続を開いたままにしますが、このメソッドを使用することで使用リソース数を制御し、プロキシへの負荷を軽減できます。
引数pageはオプションです。引数なしで呼び出した場合、A-Parserは現在のスレッドに関連付けられたタブの接続を閉じます。
await this.puppeteer.logScreenshot()
現在のページのスクリーンショットをログに記録します。