Hoppa till huvudinnehåll

Hantera Chrome (puppeteer)

A-Parser + Puppeteer

A-Parser gör det möjligt att använda webbläsaren Chrome (Chromium) som motor för nedladdning och rendering av sidor genom att använda det populära biblioteket puppeteer.

De främsta fördelarna med att använda puppeteer tillsammans med A-Parser:

  • stöd för separata proxyer för varje webbläsarflik
  • flertrådad hantering av webbläsarflikar
  • avlyssning av förfrågningar
  • alla A-Parser-funktioner för köhantering, utformning av förfrågningar och bearbetning av resultat

Användning av webbläsaren Chrome öppnar följande möjligheter:

  • rendering av DOM och JavaScript
  • möjlighet till interaktivt arbete med webbplatselement:
    • ifyllnad av formulär
    • klick på länkar
    • drag & drop
    • filuppladdning
    • musemulering
    • och mycket mer, alla standardåtgärder kan automatiseras
  • enklare kringgående av olika skydd mot dataskrapning, eftersom webbläsaren Chromium är maximalt lik den som används av vanliga användare
  • möjlighet att köra i Headless-läge, dvs. utan webbläsarens grafiska gränssnitt, vilket sparar resurser och gör det möjligt att köra webbläsaren på servrar utan grafisk miljö
anteckning

Det är viktigt att notera att webbläsaranvändning är betydligt mer resurskrävande (CPU, minne) än vanliga trådar i A-Parser.

Beroende på webbplatsens komplexitet rekommenderas att använda högst 1-2 trådar (webbläsarflikar) per tillgänglig processorkärna, till exempel för en 8-kärnig processor - från 8 till 16 flikar.

Exempel på användning

Låt oss titta på ett exempel med scrapern Chrome::ScreenshotMaker2:

  • scrapern tar skärmdumpar av webbplatser i angiven storlek och kan även förminska (skala) bilden
  • kan valfritt använda proxy
  • skapar en separat webbläsarflik för varje tråd i 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() {
// initiera webbläsaren
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) {
// anslut jimp-modulen om det behövs ändra storlek på skärmdumpen
jimp = require('jimp');
};
};

async destroy() {
// stäng webbläsaren när uppgiften är klar
if (browser)
await browser.close();
}

page: PuppeteerTypes.Page;

async threadInit() {
// skapa en webbläsarsida vid trådinitiering
this.page = await browser.newPage();

// standardmetoder för puppeteer
await this.page.setCacheEnabled(true);
await this.page.setDefaultNavigationTimeout(this.conf.timeout * 1000);

// instruera A-Parser att använda proxy för denna sida
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}`);

// gå till sidan som anges i förfrågan
await page.goto(set.query);
// dölj rullningslisten för skärmdumpen
await page.evaluate(() => { document.querySelector('html').style.overflow = 'hidden'; });

// ta skärmdump
results.screenshot = await page.screenshot();

if (parseInt(conf.resize_width)) {
// ändra storlek på bilden vid behov
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;

// stäng aktuella anslutningar eftersom webbläsaren använder keep-alive
await self.puppeteer.closeActiveConnections();
break;
}
catch (error) {
self.logger.put(`Fetch page error: ${error}`);
// stäng aktuella anslutningar eftersom webbläsaren använder keep-alive
await self.puppeteer.closeActiveConnections();
// byt proxy för webbläsarfliken
await self.proxy.next();
}
}

return results;
}
}

Detta exempel visar hur enkelt det är att använda olika proxyer för varje flik, samt flertrådat arbete (1 tråd = 1 webbläsarflik).

Beskrivning av metoder

await this.puppeteer.launch(opts?)

Denna metod är analog med metoden .launch i biblioteket puppeteer, den startar webbläsaren Chromium med de nödvändiga alternativen opts. Den största skillnaden ligger i integrationen med A-Parser och stöd för proxy för varje flik, samt tillgång till ytterligare alternativ:

logConnections?: boolean

Aktiverar loggning av alla anslutningar (oavsett om proxy används eller inte), loggutmatningen sker separat per tråd.

stealth?: boolean

Använder insticksprogrammet puppeteer-extra för att maskera Chromium som en riktig Chrome.

stealthOpts?: any

Ytterligare alternativ för insticksprogrammet puppeteer-extra.

extraPlugins?: array

Användning av ytterligare insticksprogram, som till exempel puppeteer-extra/packages.

A-Parser + Puppeteer

Övriga alternativ

Alla andra startalternativ kan hittas i den ursprungliga dokumentationen för puppeteer.

await this.puppeteer.setPageUseProxy(page)

Denna metod kopplar webbläsarsidan till en A-Parser-tråd för korrekt proxyfunktion, den bör anropas omedelbart efter att sidan har skapats:

const page = await browser.newPage();
await this.puppeteer.setPageUseProxy(page);

await this.puppeteer.closeActiveConnections(page?)

Denna metod bör anropas efter att bearbetningen av en förfrågan är klar eller innan man byter proxy för att hantera nästa försök.

Webbläsaren Chrome lämnar som standard anslutningar öppna till webbplatser den ansluter till. Denna metod gör det möjligt att kontrollera mängden resurser som används och minskar belastningen på proxyn.

Argumentet page är valfritt; vid anrop utan argument stänger A-Parser anslutningarna för den flik som är kopplad till den aktuella tråden.

await this.puppeteer.logScreenshot()

Metoden loggar en skärmdump av den aktuella sidan.