Ana içeriğe atla

Chrome Yönetimi (puppeteer)

A-Parser + Puppeteer

A-Parser, popüler puppeteer kütüphanesini kullanarak sayfaları indirmek ve oluşturmak için Chrome (Chromium) tarayıcısını bir motor olarak kullanmanıza olanak tanır.

A-Parser ile birlikte puppeteer kullanmanın temel avantajları:

  • Her tarayıcı sekmesi için ayrı proxy desteği
  • Tarayıcı sekmelerinin çoklu iş parçacığı ile yönetimi
  • İsteklerin kesilmesi (interception)
  • Kuyruk yönetimi, sorgu oluşturma ve sonuç işleme konularında A-Parser'ın tüm yetenekleri

Chrome tarayıcısını kullanmak aşağıdaki olanakları sağlar:

  • DOM ve JavaScript oluşturma (rendering)
  • Site öğeleriyle etkileşimli çalışma imkanı:
    • Form doldurma
    • Bağlantılara tıklama
    • drag & drop
    • Dosya yükleme
    • Fare emülasyonu
    • Ve çok daha fazlası; her türlü standart işlem otomatikleştirilebilir
  • Chromium tarayıcısı kullanıcıların kullandığı tarayıcıya maksimum düzeyde benzediği için çeşitli veri çekme korumalarını daha kolay atlatma
  • Headless modda, yani tarayıcı grafik arayüzü olmadan çalışma imkanı; bu sayede kaynak tasarrufu sağlanır ve tarayıcı grafik ortamı olmayan sunucularda çalıştırılabilir
not

Tarayıcı çalışmasının, normal A-Parser iş parçacıklarına göre kaynaklara (CPU, Bellek) çok daha fazla ihtiyaç duyduğu göz önünde bulundurulmalıdır.

Sitenin karmaşıklığına bağlı olarak, mevcut her işlemci çekirdeği başına en fazla 1-2 iş parçacığı (tarayıcı sekmesi) kullanılması önerilir; örneğin 8 çekirdekli işlemciler için 8 ila 16 sekme arası.

Kullanım örneği

Chrome::ScreenshotMaker2 veri kazıyıcı örneği üzerinden inceleyelim:

  • Veri kazıyıcı, belirtilen boyutta web sitelerinin ekran görüntülerini alır ve ayrıca resmi küçültebilir (ölçeklendirebilir)
  • İsteğe bağlı olarak proxy kullanabilir
  • Her A-Parser iş parçacığı için ayrı bir tarayıcı sekmesi oluşturur
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() {
// tarayıcıyı başlatıyoruz
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) {
// ekran görüntüsünü yeniden boyutlandırmak gerekiyorsa jimp modülünü bağlıyoruz
jimp = require('jimp');
};
};

async destroy() {
// görev tamamlandığında tarayıcıyı kapatıyoruz
if (browser)
await browser.close();
}

page: PuppeteerTypes.Page;

async threadInit() {
// iş parçacığı başlatılırken tarayıcı sayfası oluşturuyoruz
this.page = await browser.newPage();

// standart puppeteer metotları
await this.page.setCacheEnabled(true);
await this.page.setDefaultNavigationTimeout(this.conf.timeout * 1000);

// A-Parser'a bu sayfa için proxy kullanmasını söylüyoruz
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}`);

// sorguda belirtilen sayfaya gidiyoruz
await page.goto(set.query);
// ekran görüntüsü için kaydırma çubuğunu gizliyoruz
await page.evaluate(() => { document.querySelector('html').style.overflow = 'hidden'; });

// ekran görüntüsünü alıyoruz
results.screenshot = await page.screenshot();

if (parseInt(conf.resize_width)) {
// gerektiğinde resmi yeniden boyutlandırıyoruz
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;

// tarayıcı keep-alive kullandığı için mevcut bağlantıları kapatıyoruz
await self.puppeteer.closeActiveConnections();
break;
}
catch (error) {
self.logger.put(`Fetch page error: ${error}`);
// tarayıcı keep-alive kullandığı için mevcut bağlantıları kapatıyoruz
await self.puppeteer.closeActiveConnections();
// tarayıcı sekmesi için proxy değiştiriyoruz
await self.proxy.next();
}
}

return results;
}
}

Bu örnek, her sekme için farklı proxylerin kullanım kolaylığını ve çoklu iş parçacıklı çalışmayı (1 iş parçacığı = 1 tarayıcı sekmesi) göstermektedir.

Metot açıklamaları

await this.puppeteer.launch(opts?)

Bu metot, puppeteer kütüphanesinin .launch metoduna benzer; Chromium tarayıcısını gerekli opts seçenekleriyle başlatır. Temel fark, A-Parser ile entegrasyonu ve her sekme için proxy desteği sağlaması ile ek seçeneklerin bulunmasıdır:

logConnections?: boolean

Tüm bağlantıların (proxy kullanarak veya kullanmadan bağımsız olarak) günlüğe kaydedilmesini sağlar, günlük çıktısı iş parçacıklarına göre ayrı ayrı verilir.

stealth?: boolean

Chromium'u gerçek bir Chrome gibi maskelemek için puppeteer-extra eklentisini kullanır.

stealthOpts?: any

puppeteer-extra eklentisi için ek seçenekler.

extraPlugins?: array

puppeteer-extra/packages gibi ek eklentilerin kullanımı.

A-Parser + Puppeteer

Diğer seçenekler

Diğer tüm başlatma seçenekleri orijinal puppeteer dokümantasyonunda görülebilir.

await this.puppeteer.setPageUseProxy(page)

Bu metot, proxylerin doğru çalışması için tarayıcı sayfasını A-Parser iş parçacığı ile ilişkilendirir; sayfa oluşturulduktan hemen sonra çağrılmalıdır:

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

await this.puppeteer.closeActiveConnections(page?)

Bu metot, istek işleme tamamlandıktan sonra veya bir sonraki deneme için proxy değiştirmeden önce çağrılmalıdır.

Chrome tarayıcısı varsayılan olarak bağlandığı sitelerle bağlantıları açık bırakır; bu metot kullanılan kaynak sayısını kontrol etmeyi sağlar ve proxy üzerindeki yükü azaltır.

page argümanı isteğe bağlıdır; argümansız çağrıldığında A-Parser, mevcut iş parçacığı ile ilişkili sekme için bağlantıları kapatacaktır.

await this.puppeteer.logScreenshot()

Metot mevcut sayfanın ekran görüntüsünü günlüğe kaydeder.