Heim BlogWeb-Scraping Web Scraping mit Playwright und Node.js

Web Scraping mit Playwright und Node.js

von Kadek

Das Extrahieren von Daten aus Websites ist in verschiedenen Bereichen unverzichtbar geworden, von der Datenerfassung bis zur Wettbewerbsanalyse. Allerdings kann es schwierig sein, Inhalte, die über JavaScript, AJAX-Anfragen und komplexe Interaktionen geladen werden, mit einfachen Tools zu erfassen. Hier kommen Headless-Browser-Automatisierungstools wie Playwright ins Spiel.

In diesem Blog befassen wir uns mit der Verwendung von Playwright zum Web-Scraping. Wir werden seine Vorteile, das Scraping einzelner und mehrerer Seiten, die Fehlerbehandlung, das Klicken auf Schaltflächen, das Senden von Formularen und wichtige Techniken wie die Nutzung von Proxys zur Umgehung der Erkennung und zum Abfangen von Anfragen untersuchen. Darüber hinaus der Vergleich mit anderen Web-Scraping- und Automatisierungstools wie Puppeteer und Selenium.

Was ist Dramatiker?

Playwright ist ein beliebtes Open-Source-Framework, das auf Node.js für Webtests und Automatisierung basiert. Es ermöglicht das Testen von Chromium, Firefox und WebKit mit einer einzigen API. Playwright wurde von Microsoft entwickelt und bietet effiziente, zuverlässige und schnelle browserübergreifende Webautomatisierung. Es funktioniert auf mehreren Plattformen, einschließlich Windows, Linux und macOS, und unterstützt alle modernen Webbrowser. Darüber hinaus bietet Playwright sprachübergreifende Unterstützung für TypeScript, JavaScript, Python, .NET und Java.

Erste Schritte mit Dramatiker

Vor dem Scrapen von Websites bereiten wir die Node.js- und Python-Umgebungen unseres Systems für Playwright vor.

Projekteinrichtung und -installation

Für Nodejs:

Stellen Sie sicher, dass auf Ihrem System die neueste Version von Node.js installiert ist. Für dieses Projekt verwenden wir Node.js v20.9.0.

Erstellen Sie ein neues Verzeichnis für Ihr Projekt, navigieren Sie dorthin und initialisieren Sie durch Ausführen ein Node.js-Projekt npm init. Der npm init -y Der Befehl erstellt eine package.json Datei mit allen Abhängigkeiten.

mkdir playwright-scraping 
cd playwright-scraping
npm init -y

Jetzt können Sie Playwright mit NPM installieren:

npm install playwright

Um Playwright nutzen zu können, müssen Sie außerdem einen kompatiblen Browser installieren. Für jede Playwright-Version sind bestimmte Browser-Binärversionen erforderlich. Führen Sie den folgenden Befehl aus, um die neuesten Browserversionen zu installieren:

npx playwright install

Dadurch werden die neuesten Versionen von Chromium, Firefox und WebKit installiert. Sie können jeden dieser Browser in Ihrem Code verwenden, für dieses Tutorial verwenden wir jedoch Chromium.

So sieht der komplette Prozess aus:


Installieren Sie npm-Pakete
Installieren Sie NPM-Pakete

Öffne das package.json Datei hinzufügen und hinzufügen "type": "module" zur Unterstützung moderner JavaScript-Syntax.


Fügen Sie die Datei package.json hinzu
Fügen Sie die Datei package.json hinzu

Öffnen Sie abschließend das Projekt in Ihrem bevorzugten Code-Editor und erstellen Sie eine neue Datei mit dem Namen index.js.


Erstellen Sie die Datei index.js
Erstellen Sie die Datei index.js

Für Python:

Stellen Sie sicher, dass auf Ihrem System die neueste Version von Python installiert ist. Als nächstes installieren Sie die Playwright Python-Bibliothek und die erforderlichen Browser.

pip install playwright
playwright install

So sieht der komplette Prozess aus:


Installieren Sie Playwright mit Pip
Installieren Sie Playwright mit Pip

Start von Playwright

Für Nodejs:

Schreiben wir unseren ersten Playwright-Code, der eine neue Seite in einem Chromium-Browser öffnet.

import { chromium } from 'playwright';

async function main() {
    // Launch a new instance of a Chromium browser with headless mode 
    // disabled for visibility
    const browser = await chromium.launch({
        headless: false
    });

    // Create a new Playwright context to isolate browsing session
    const context = await browser.newContext();
    // Open a new page/tab within the context
    const page = await context.newPage();

    // Navigate to the GitHub topics homepage
    await page.goto('<https://github.com/topics>');

    // Wait for 1 second to ensure page content loads properly
    await page.waitForTimeout(1000);

    // Close the browser instance after task completion
    await browser.close();
}

// Execute the main function
main();

Der obige Code importiert die chromium Modul zur Steuerung von Chromium-basierten Browsern. Anschließend wird eine neue, sichtbare Instanz des Chromium-Browsers gestartet chromium.launch() mit dem headless Option auf eingestellt False. Eine neue Browserseite wird geöffnet und die page.goto() Die Funktion navigiert zur GitHub-Themen-Webseite. Nach einer Wartezeit von einer Sekunde kann der Benutzer die Seite sehen, bevor sie endgültig geschlossen wird.

Für Python:

Playwright für Python bietet sowohl synchrone als auch asynchrone APIs. Das folgende Beispiel zeigt die asynchrone API in Aktion:

from playwright.async_api import async_playwright
import asyncio

async def main():
    # Initialize Playwright asynchronously
    async with async_playwright() as p:
        # Launch a Chromium browser instance with headless mode disabled
        browser = await p.chromium.launch(headless=False)
        
        # Create a new context within the browser to isolate browsing session
        context = await browser.new_context()
        
        # Create a new page/tab within the context
        page = await context.new_page()
        
        # Navigate to the GitHub topics homepage
        await page.goto('<https://github.com/topics>')
        
        # Wait for 1 second to ensure page content loads properly
        await page.wait_for_timeout(1000)
        
        # Close the browser instance after task completion
        await browser.close()

# Run the main function asynchronously
asyncio.run(main())

Sowohl Node.js- als auch Python-Code weisen Ähnlichkeiten auf, es gibt jedoch einige wesentliche Unterschiede. Python verwendet die Asyncio-Bibliothek für asynchrone Vorgänge. Darüber hinaus unterscheiden sich die Konventionen zur Benennung von Funktionen, wobei Python „snake_case“ verwendet (z. B. wait_for_timeout) und JavaScript mit camelCase (z. B. waitForTimeout).

Das folgende Beispiel zeigt die synchrone API in Aktion:

from playwright.sync_api import sync_playwright

def main():
    # Initialize Playwright synchronously
    with sync_playwright() as p:
        # Launch a Chromium browser instance with headless mode disabled
        browser = p.chromium.launch(headless=False)

        # Create a new context within the browser to isolate browsing session
        context = browser.new_context()

        # Create a new page/tab within the context
        page = context.new_page()

        # Navigate to the GitHub topics homepage
        page.goto('<https://github.com/topics>')

        # Wait for 1 second to ensure page content loads properly
        page.wait_for_timeout(1000)

        # Close the browser instance after task completion
        browser.close()

if __name__ == '__main__':
    main()

Die oben genannten Node.js- und Python-Codes öffnen die folgende Seite.


Recherchieren Sie auf der Github-Seite
Recherchieren Sie auf der Github-Seite

Grundlegendes Schaben mit Dramatiker

Nachdem Ihre Umgebung nun eingerichtet ist, tauchen wir mit Playwright in ein grundlegendes Web-Scraping ein. Sie können alles, was Sie normalerweise manuell tun, im Browser tun, vom Erstellen von Screenshots bis zum Crawlen mehrerer Seiten.

Auswählen der Daten zum Scrapen

Wir werden Daten aus GitHub-Themen extrahieren. Auf diese Weise können Sie das Thema und die Anzahl der Repositorys auswählen, die Sie extrahieren möchten. Der Scraper gibt dann die mit dem ausgewählten Thema verknüpften Informationen zurück.


Scrape NodeJS-Pakete
Scrape NodeJS-Pakete

Wir verwenden Playwright, um einen Browser zu starten, zur GitHub-Themenseite zu navigieren und die erforderlichen Informationen zu extrahieren. Dazu gehören Details wie der Repository-Eigentümer, der Repository-Name, die Repository-URL, die Anzahl der Sterne des Repositorys, seine Beschreibung und alle zugehörigen Tags.


Extrahieren Sie nur nützliche Daten
Extrahieren Sie nur nützliche Daten

Auffinden von Elementen und Extrahieren von Daten

Wenn Sie die Themenseite öffnen, sehen Sie 20 Repositorys. Jeder Eintrag wird als angezeigt <article> -Element zeigt Informationen zu einem bestimmten Repository an. Sie können jedes Element erweitern, um detailliertere Informationen zum entsprechenden Repository anzuzeigen.


Suchen Sie Tags mit DevTools
Suchen Sie Tags mit DevTools

Das Bild unten zeigt eine erweiterte Darstellung <article> Element, das alle Informationen über das Repository anzeigt.


Verwenden Sie Klassen
Verwenden Sie Klassen

Extrahieren von Benutzer- und Repository-Informationen:

  1. Benutzer: Verwenden h3 > a:first-child um das erste Anker-Tag direkt innerhalb von a anzusprechen <h3> Etikett.
  2. Repository-Name: Zielt auf das zweite untergeordnete Element innerhalb desselben <h3> Elternteil. Dieses Kind enthält sowohl den Namen als auch die URL. Benutzen Sie die textContent Eigenschaft zum Extrahieren des Namens und der getAttribute('href') Methode zum Extrahieren der URL.
  3. Anzahl der Sterne: Verwendung #repo-stars-counter-star um das Element auszuwählen und die tatsächliche Zahl daraus zu extrahieren title Attribut.
  4. Repository-Beschreibung: Verwendung div.px-3 > p um den ersten Absatz innerhalb von a auszuwählen div mit der Klasse px-3.
  5. Repository-Tags: Verwendung a.topic-tag um alle Ankertags mit der Klasse auszuwählen topic-tag.

Gemeinsame Funktionen:

Um die oben genannten Selektoren effektiv zu nutzen, sind hier die allgemeinen Funktionen:

  • $$eval(selector, function): Diese Funktion wählt alle Elemente aus, die mit übereinstimmen selector und übergibt sie als Array an die function. Anschließend wird der Rückgabewert der Funktion zurückgegeben.
  • $eval(selector, function): Diese Funktion wählt das erste Element aus, das mit dem übereinstimmt selector und übergibt es als Argument an die function. Anschließend wird der Rückgabewert der Funktion zurückgegeben.
  • querySelector(selector): Diese Funktion gibt das erste Element zurück, das mit dem übereinstimmt selector.
  • querySelectorAll(selector): Diese Funktion gibt eine Liste aller Elemente zurück, die mit übereinstimmen selector.

Hier ist ein Codeausschnitt:

repos.forEach(repo => {
    const user = repo.querySelector('h3 > a:first-child').textContent.trim();
    const repoLink = repo.querySelector('h3 > a:nth-child(2)');
    const repoName = repoLink.textContent.trim();
    const repoUrl = repoLink.getAttribute('href');
    const repoStar = repo.querySelector('#repo-stars-counter-star').getAttribute('title');
    const repoDescription = repo.querySelector('div.px-3 > p').textContent.trim();
    const tagsElements = Array.from(repo.querySelectorAll('a.topic-tag'));
    const tags = tagsElements.map(tag => tag.textContent.trim());

Sehen wir uns den gesamten Prozess zum Extrahieren aller Repositorys von einer einzelnen Seite an.

Der Prozess beginnt mit der page.$$eval-Funktion. Diese Funktion wählt alle Elemente mit der Klasse aus border innerhalb der article Tag und übergibt sie als Array an die bereitgestellte Funktion. Wir definieren alle Variablen und Selektoren innerhalb dieser Funktion.

const extractedRepos = await page.$$eval('article.border', repos => { ... });

Erstellen Sie außerdem ein leeres Array mit dem Namen repoData um die extrahierten Informationen zu speichern.

const repoData = ();

Durchläuft jedes Element im repos Array, um alle relevanten Daten für jedes Repository mithilfe der bereitgestellten Selektoren zu extrahieren.

repos.forEach(repo => { ... });

Abschließend werden die extrahierten Daten für jedes Repository dem hinzugefügt repoData Array, und das Array wird zurückgegeben.

repoData.push({ user, repoName, repoStar, repoDescription, tags, repoUrl });

Hier ist der Code für alle oben genannten Schritte.

const extractedRepos = await page.$$eval('article.border', repos => {
    const repoData = ();

    repos.forEach(repo => {
        const user = repo.querySelector('h3 > a:first-child').textContent.trim();
        const repoLink = repo.querySelector('h3 > a:nth-child(2)');
        const repoName = repoLink.textContent.trim();
        const repoUrl = repoLink.getAttribute('href');
        const repoStar = repo.querySelector('#repo-stars-counter-star').getAttribute('title');
        const repoDescription = repo.querySelector('div.px-3 > p').textContent.trim();
        const tagsElements = Array.from(repo.querySelectorAll('a.topic-tag'));
        const tags = tagsElements.map(tag => tag.textContent.trim());

        repoData.push({ user, repoName, repoStar, repoDescription, tags, repoUrl });
    });

    return repoData;
});

Hier ist der vollständige Code. Wenn Sie diesen Code ausführen, wird die erste Seite von GitHub Topics extrahiert.

import { chromium } from 'playwright';

(async () => {
    // Launch a headless browser
    const browser = await chromium.launch({ headless: true });

    // Open a new page
    const context = await browser.newContext();
    const page = await context.newPage();

    // Navigate to the Node.js topic page on GitHub
    await page.goto('<https://github.com/topics/nodejs>');

    const extractedRepos = await page.$$eval('article.border', repos => {
        // Array to store extracted data
        const repoData = ();

        // Extract data from each repository element
        repos.forEach(repo => {
            const user = repo.querySelector('h3 > a:first-child').textContent.trim();
            const repoLink = repo.querySelector('h3 > a:nth-child(2)');
            const repoName = repoLink.textContent.trim();
            const repoUrl = repoLink.getAttribute('href');
            const repoStar = repo.querySelector('#repo-stars-counter-star').getAttribute('title');
            const repoDescription = repo.querySelector('div.px-3 > p').textContent.trim();
            const tagsElements = Array.from(repo.querySelectorAll('a.topic-tag'));
            const tags = tagsElements.map(tag => tag.textContent.trim());

            // Add extracted data to the array
            repoData.push({ user, repoName, repoStar, repoDescription, tags, repoUrl });
        });

        // Return the extracted data
        return repoData;
    });

    console.log(`Total repositories extracted: ${extractedRepos.length}\\n`);

    // Print extracted data to the console
    console.dir(extractedRepos, { depth: null }); // Show all nested data

    // Close the browser
    await browser.close();
})();

Das Ergebnis ist:


Repository-Daten drucken
Repository-Daten drucken

Wenn Sie über Playwright hinaus mehr über Web Scraping mit Node.js erfahren möchten, könnte Ihnen unser umfassender Leitfaden zum Web Scraping mit Node.js hilfreich sein. In diesem Artikel werden zusätzliche Bibliotheken und Techniken zur Verbesserung Ihrer Scraping-Funktionen mit Node.js behandelt

Fortgeschrittene Schabetechniken

Wir haben die einzelne Seite erfolgreich gelöscht. Kommen wir nun zum erweiterten Scraping mit Playwright. Sie können auf Schaltflächen klicken, Formulare ausfüllen, mehrere Seiten crawlen und Header und Proxys drehen, um Ihr Scraping zuverlässiger zu machen …

Auf Schaltflächen klicken und auf Aktionen warten

Sie können weitere Repositorys laden, indem Sie unten auf der Seite auf die Schaltfläche „Mehr laden…“ klicken. Hier sind die Aktionen, um Playwright anzuweisen, weitere Repositorys zu laden:

  1. Warten Sie, bis die Schaltfläche „Mehr laden…“ angezeigt wird.
  2. Klicken Sie auf die Schaltfläche „Mehr laden…“.
  3. Warten Sie, bis die neuen Repositorys geladen sind, bevor Sie fortfahren.

Fügen Sie die Verarbeitung der Schaltfläche „Mehr laden“ hinzu
Fügen Sie die Verarbeitung der Schaltfläche „Mehr laden“ hinzu

Das Klicken auf Schaltflächen in Playwright ist unkompliziert! Übergeben Sie einfach einen gültigen CSS-Selektor an locator Methode, die das Element auf der Seite effizient findet.

const button = await page.locator('button(type="submit").ajax-pagination-btn.f6');
await button.click();

In diesem Fall ist die page.locator() Die Methode sucht nach einem Schaltflächenelement mit Attributen type="submit" und CSS-Klassen ajax-pagination-btn Und f6.

Umgang mit dynamischen Inhalten und Navigation

Um mehrere Seiten mit Playwright zu scrappen, müssen Sie wiederholt auf die Schaltfläche „Mehr laden…“ klicken, bis Sie das Ende erreichen. Wir können jedoch Code schreiben, um diesen Prozess zu automatisieren und eine bestimmte Anzahl von gewünschten Repositorys zu durchsuchen. Stellen Sie sich zum Beispiel vor, dass es 10.000 Repositorys für „nodejs“ gibt und Sie nur Daten für 1.000 davon extrahieren möchten.

So crawlt das Skript mehrere Seiten:

  1. Öffnen Sie die Themenseite „nodejs“ auf GitHub.
  2. Erstellen Sie einen leeren Satz zum Speichern eindeutiger Repository-Dateneinträge.
  3. $$eval Die Funktion extrahiert Daten aus jedem Repository wie Benutzername, Repository-Name, Sternanzahl, Beschreibung, Tags und URL.
  4. Die extrahierten Daten werden nur gespeichert, wenn sie eindeutig sind.
  5. Der Code sucht mithilfe eines bestimmten Locators nach einer „Nächsten Seite“. Falls verfügbar, klickt es auf die Schaltfläche, um zur nächsten Seite zu wechseln und den Scraping-Vorgang zu wiederholen.
  6. Wenn keine Schaltfläche gefunden wird, wird die Schleife beendet.
  7. Abschließend wird die gestartete Browserinstanz geschlossen.

Hier ist der Code:

import { chromium } from 'playwright';

async function scrapeData(numRepos) {
    const browser = await chromium.launch({ headless: true });
    const context = await browser.newContext();
    const page = await context.newPage();
    await page.goto('<https://github.com/topics/nodejs>');

    const uniqueRepos = new Set();

    while (uniqueRepos.size < numRepos) {
        const extractedData = await page.$$eval('article.border', repos => {
            return repos.map(repo => {
                const userLink = repo.querySelector('h3 > a:first-child');
                const repoLink = repo.querySelector('h3 > a:last-child');
                const user = userLink?.textContent.trim() || '';
                const repoName = repoLink?.textContent.trim() || '';
                const repoStar = repo.querySelector('#repo-stars-counter-star')?.title || '';
                const repoDescription = repo.querySelector('div.px-3 > p')?.textContent.trim() || '';
                const tags = Array.from(repo.querySelectorAll('a.topic-tag')).map(tag => tag.textContent.trim());
                const repoUrl = repoLink?.href || '';

                return { user, repoName, repoStar, repoDescription, tags, repoUrl };
            });
        });

        extractedData.forEach(entry => uniqueRepos.add(JSON.stringify(entry)));

        if (uniqueRepos.size >= numRepos) {
            break;
        }

        const button = await page.locator('button(type="submit").ajax-pagination-btn.f6');
        if (!button) {
            console.log('Pagination button not found. All data scraped.');
            break;
        }

        await button.click();
        await page.waitForLoadState('networkidle');
    }

    const uniqueList = Array.from(uniqueRepos).slice(0, numRepos).map(entry => JSON.parse(entry));
    console.dir(uniqueList, { depth: null });

    await browser.close();
}

scrapeData(30);

Umgang mit Fehlern

Beim Scraping von Webseiten können aufgrund verschiedener Faktoren mehrere Fehler auftreten, darunter menschliche Fehler wie die Angabe einer nicht funktionierenden URL oder das Versäumnis, auf eine Schaltfläche zu klicken. Darüber hinaus fehlt möglicherweise das Zieldatenelement auf der Seite, beispielsweise fehlt in einem Code-Repository möglicherweise eine Beschreibung oder Sterne.

Glücklicherweise gibt es Strategien, mit diesen Herausforderungen umzugehen. Eine häufige Variante ist die Verwendung try/catch Blöcke. Mit diesen Blöcken können Sie Fehler wie fehlgeschlagene Seitennavigation oder Zeitüberschreitungen reibungslos behandeln, so verhindern, dass Ihr Code abstürzt, und eine fortgesetzte Ausführung ermöglichen.

Hier ist der vollständige Code mit Fehlerbehandlung und Randfällen:

import { chromium } from 'playwright';

async function scrapeData(numRepos) {
    let browser;
    try {
        browser = await chromium.launch({ headless: true });
        const context = await browser.newContext();
        const page = await context.newPage();
        await page.goto('<https://github.com/topics/nodejs>');

        const uniqueRepos = new Set();

        while (uniqueRepos.size < numRepos) {
            const extractedData = await page.$$eval('article.border', repos => {
                return repos.map(repo => {
                    const userLink = repo.querySelector('h3 > a:first-child');
                    const repoLink = repo.querySelector('h3 > a:last-child');
                    const user = userLink?.textContent.trim() || '';
                    const repoName = repoLink?.textContent.trim() || '';
                    const repoStar = repo.querySelector('#repo-stars-counter-star')?.title || '';
                    const repoDescription = repo.querySelector('div.px-3 > p')?.textContent.trim() || '';
                    const tags = Array.from(repo.querySelectorAll('a.topic-tag')).map(tag => tag.textContent.trim());
                    const repoUrl = repoLink?.href || '';

                    return { user, repoName, repoStar, repoDescription, tags, repoUrl };
                });
            });

            if (extractedData.length === 0) {
                console.log('No articles found on this page.');
                break;
            }

            extractedData.forEach(entry => uniqueRepos.add(JSON.stringify(entry)));

            if (uniqueRepos.size >= numRepos) {
                break;
            }

            const button = await page.locator('button(type="submit").ajax-pagination-btn.f6');
            if (!button) {
                console.log('Next button not found. All data scraped.');
                break;
            }

            await button.click();
            await page.waitForLoadState('networkidle');
        }

        const uniqueList = Array.from(uniqueRepos).slice(0, numRepos).map(entry => JSON.parse(entry));
        console.dir(uniqueList, { depth: null });
    } catch (error) {
        console.error('Error during scraping:', error);
    } finally {
        if (browser) {
            await browser.close();
        }
    }
}

scrapeData(30).catch(error => console.error('Unhandled error:', error));

Verwenden von Proxys mit Playwright

Das Scrapen von Daten von Websites kann manchmal eine Herausforderung sein. Websites können den Zugriff basierend auf Ihrem Standort einschränken oder Ihre IP-Adresse blockieren. Hier kommen Proxys zum Einsatz. Proxys helfen dabei, diese Einschränkungen zu umgehen, indem sie Ihre echte IP-Adresse und Ihren Standort verbergen.

Holen Sie sich zunächst Ihren Proxy aus der Liste der kostenlosen Proxys. Fügen Sie dann ein Proxy-Objekt zu Ihren Browser-Startoptionen hinzu. Legen Sie im Proxy-Objekt fest server Parameter zu Ihrem proxyUrl. Starten Sie abschließend den Browser, indem Sie die aufrufen chromium.launch Funktion, Bereitstellung der launchOptions Objekt, das Sie gerade definiert haben.

import { chromium } from 'playwright';

const proxyUrl="<http://20.210.113.32:80>";

const launchOptions = {
    proxy: {
        server: proxyUrl
    }
};

(async () => {
    const browser = await chromium.launch(launchOptions);
    const page = await browser.newPage();

    await page.goto('<http://httpbin.org/ip>');

    const pageContent = await page.textContent('body');
    console.log(pageContent);
})();

Das Ergebnis ist:


Überprüfen Sie Ihre Proxy-Arbeit
Überprüfen Sie Ihre Proxy-Arbeit

Wir haben es geschafft! Die IP-Adresse stimmt mit der auf der Webseite überein und bestätigt, dass Playwright den angegebenen Proxy verwendet.

Notiz: Kostenlose Proxys werden aufgrund ihrer Unzuverlässigkeit nicht empfohlen. Insbesondere ihre kurze Lebensdauer macht sie für reale Szenarien ungeeignet.

Abfangen von HTTP-Anfragen

Mit Playwright können Sie den Netzwerkverkehr wie HTTP- und HTTPS-Anfragen, XMLHttpRequests (XHRs) und Abrufanfragen einfach überwachen und ändern. Unten finden Sie einen Codeausschnitt, der zeigt, wie ein Anforderungsheader geändert wird.

import { chromium } from 'playwright';

(async () => {
    const browser = await chromium.launch({ headless: true });
    const context = await browser.newContext();
    const page = await context.newPage();

    await page.route('<https://httpbin.org/headers>', (route, request) => {
        // Get original headers
        const originalHeaders = request.headers();

        // Modify the Accept-Language and User-Agent headers
        const modifiedHeaders = { ...originalHeaders };
        modifiedHeaders('accept-language') = 'fr-FR'; // Change to French
        modifiedHeaders('user-agent') = 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; RM-1127_16056) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.10536';

        // Continue the request with modified headers
        route.continue({
            headers: modifiedHeaders,
        });
    });

    // Make the request with modified headers
    await page.goto('<https://httpbin.org/headers>');

    // Extract the data to see if the fields are updated
    const response = await page.evaluate(() => {
        return JSON.parse(document.querySelector('pre').textContent);
    });

    console.log('Response:', response);

    await browser.close();
})();

Der Code richtet einen Routenhandler für die URL ein https://httpbin.org/headers. Dieser Handler fängt Anfragen ab und ändert bestimmte Header wie „Accept-Language“ und „User-Agent“, bevor er sie sendet.

Innerhalb der Handlerfunktion wird die geändert Accept-Language Kopfzeile zu 'fr-FR' (Französisch) und die User-Agent auch die Kopfzeile. Nach diesen Änderungen setzt der Handler die Anforderung mit den aktualisierten Headern fort route.continue().

Original-Header – besuchen Sie https://httpbin.org/headers, um den Original-Header anzuzeigen.


Recherchieren Sie Ihre Überschriften
Recherchieren Sie Ihre Überschriften

Geänderter Header – von unserem Code zurückgegeben.


Recherchieren Sie Ihre Überschriften
Recherchieren Sie Ihre Überschriften

Ausfüllen von Formularen

Das Ausfüllen und Absenden von Formularen ist mit Playwright ganz einfach. Sie müssen nur die Selektoren an übergeben .fill() Funktion zum Ausfüllen der Werte in den Eingabefeldern wie Benutzername und Passwort. Dann nutzen Sie die .click() Funktion zum Absenden des Formulars.

Sehen wir uns dies in Aktion an, indem wir uns mit Playwright bei unserem Reddit-Konto anmelden.

import { chromium } from 'playwright';

(async () => {

    const browser = await chromium.launch({ headless: true });

    const page = await browser.newPage();

    await page.goto('<https://reddit.com/login>');

    await page.fill('input(name="username")', "satyamtri");
    await page.fill('input(name="password")', "<secret-password>");

    await page.click('.login');

    await page.waitForNavigation();

    await page.screenshot({
        path: "reddit.png",
        fullPage: false
    });

    await browser.close();

})();

Das Ergebnis ist:


Recherchieren Sie auf der Reddit-Seite
Recherchieren Sie auf der Reddit-Seite

Screenshot-Erfassung von Webseiten

Mit Playwright können Sie Screenshots von Webseiten aufnehmen. Diese Funktion ist für die visuelle Überprüfung wertvoll, da sie es Ihnen ermöglicht, den Schnappschuss zu jedem Zeitpunkt zu erfassen.

import { chromium } from 'playwright';

async function screenShot() {
    const browser = await chromium.launch({
        headless: true
    });
    
    const context = await browser.newContext();
    const page = await context.newPage();
    
    await page.setViewportSize({ width: 1280, height: 800 }); // set screenshot dimension
    await page.goto('<https://github.com/topics/nodejs>')
    await page.screenshot({ path: 'images/screenshot.png' })
    await browser.close()
}
screenShot();

Das Ergebnis ist:


Finden Sie Repositorys
Finden Sie Repositorys

Um die gesamte Seite zu erfassen, legen Sie fest fullPage Eigentum zu true. Sie können auch das Bildformat ändern jpg oder jpeg zum Speichern in verschiedenen Formaten.

await page.screenshot({ path: 'images/screenshot.jpg', fullPage: true });

Um einen bestimmten Bereich auf einer Webseite zu erfassen, verwenden Sie die clip Eigentum. Es erfordert die Definition von vier Werten:

  • x: Horizontaler Abstand von der oberen linken Ecke des Erfassungsbereichs.
  • y: Vertikaler Abstand von der oberen linken Ecke des Erfassungsbereichs.
  • width: Breite des Erfassungsbereichs.
  • height: Höhe des Erfassungsbereichs.
await page.screenshot({
        path: "images/screenshot.png", fullPage: false, clip: {
            x: 5,
            y: 5,
            width: 320,
            height: 160
        }
    });

Das Ergebnis ist:


Verwenden Sie Themen
Verwenden Sie Themen

Gekratzte Daten in Excel speichern

Eindrucksvoll! Wir haben die Daten erfolgreich gelöscht. Speichern wir es in einer Excel-Datei, anstatt es auf der Konsole auszudrucken.

Wir werden das verwenden exceljs Paket zum Schreiben der Daten in die Excel-Datei. Aber bevor Sie dies tun, installieren Sie es mit dem folgenden Befehl:

npm install exceljs

Hier ist der Codeausschnitt zum Speichern von Daten in der Excel-Datei:

const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet('GitHub Repositories');
sheet.columns = (
    { header: 'User', key: 'user' },
    { header: 'Repository Name', key: 'repoName' },
    { header: 'Stars', key: 'repoStar' },
    { header: 'Description', key: 'repoDescription' },
    { header: 'Repository URL', key: 'repoUrl' },
    { header: 'Tags', key: 'tags' }
);

uniqueList.forEach(entry => {
    sheet.addRow(entry);
});

await workbook.xlsx.writeFile('github_repos.xlsx');

Das Code-Snippet nutzt mehrere Funktionen:

  1. new ExcelJS.Workbook(): Erstellt ein neues ExcelJS-Arbeitsmappenobjekt.
  2. workbook.addWorksheet('GitHub Repositories'): Fügt der Arbeitsmappe ein neues Arbeitsblatt mit dem Namen „GitHub Repositories“ hinzu.
  3. sheet.columns: Definiert die Spalten im Arbeitsblatt. Jedes Spaltenobjekt gibt den Header und den Schlüssel für diese Spalte an.
  4. sheet.addRow(entry): Fügt dem Arbeitsblatt eine Zeile mit Daten aus dem Eintragsobjekt hinzu (stellt Daten für eine einzelne Zeile dar).
  5. workbook.xlsx.writeFile('github_repos.xlsx'): Schreibt die Arbeitsmappe in eine Datei mit dem Namen „github_repos.xlsx“ im XLSX-Format.

Der vollständige Code:

import { chromium } from 'playwright';
import ExcelJS from 'exceljs';

async function scrapeData(numRepos) {
    let browser;
    try {
        browser = await chromium.launch({ headless: true });
        const context = await browser.newContext();
        const page = await context.newPage();
        await page.goto('<https://github.com/topics/nodejs>');

        const uniqueRepos = new Set();

        while (uniqueRepos.size < numRepos) {
            const extractedData = await page.$$eval('article.border', repos => {
                return repos.map(repo => {
                    const userLink = repo.querySelector('h3 > a:first-child');
                    const repoLink = repo.querySelector('h3 > a:last-child');
                    const user = userLink?.textContent.trim() || '';
                    const repoName = repoLink?.textContent.trim() || '';
                    const repoStar = repo.querySelector('#repo-stars-counter-star')?.title || '';
                    const repoDescription = repo.querySelector('div.px-3 > p')?.textContent.trim() || '';
                    const tags = Array.from(repo.querySelectorAll('a.topic-tag')).map(tag => tag.textContent.trim());
                    const repoUrl = repoLink?.href || '';

                    return { user, repoName, repoStar, repoDescription, tags, repoUrl };
                });
            });

            if (extractedData.length === 0) {
                console.log('No articles found on this page.');
                break;
            }

            extractedData.forEach(entry => uniqueRepos.add(JSON.stringify(entry)));

            if (uniqueRepos.size >= numRepos) {
                break;
            }

            const button = await page.locator('button(type="submit").ajax-pagination-btn.f6');
            if (!button) {
                console.log('Next button not found. All data scraped.');
                break;
            }

            await button.click();
            await page.waitForLoadState('networkidle');
        }

        const uniqueList = Array.from(uniqueRepos).slice(0, numRepos).map(entry => JSON.parse(entry));

        // Save data to Excel file
        const workbook = new ExcelJS.Workbook();
        const sheet = workbook.addWorksheet('GitHub Repositories');
        sheet.columns = (
            { header: 'User', key: 'user' },
            { header: 'Repository Name', key: 'repoName' },
            { header: 'Stars', key: 'repoStar' },
            { header: 'Description', key: 'repoDescription' },
            { header: 'Repository URL', key: 'repoUrl' },
            { header: 'Tags', key: 'tags' }
        );

        uniqueList.forEach(entry => {
            sheet.addRow(entry);
        });

        await workbook.xlsx.writeFile('github_repos.xlsx');
        console.log('Data saved to excel file.');

    } catch (error) {
        console.error('Error during scraping:', error);
    } finally {
        if (browser) {
            await browser.close();
        }
    }
}

scrapeData(30).catch(error => console.error('Unhandled error:', error));

Das Ergebnis ist:


Datei mit Ergebnissen
Datei mit Ergebnissen

Andere Tools wie Selenium und Puppeteer bieten ähnliche Funktionalitäten wie Playwright. Allerdings hat jedes Tool seine Stärken in Bezug auf Ausführungsgeschwindigkeit, Entwicklererfahrung und Community-Support.

Playwright zeichnet sich durch seine Fähigkeit aus, mithilfe einer einzigen API nahtlos in mehreren Browsern (einschließlich Chromium, WebKit und Firefox) zu laufen. Es verfügt außerdem über eine umfangreiche Dokumentation und unterstützt verschiedene Programmiersprachen wie Python, Node.js, Java und .NET.

Während Puppeteer auch entwicklerfreundlich und einfach einzurichten ist, ist es auf JavaScript- und Chromium-Browser beschränkt. Selenium hingegen bietet die umfassendste Browser- und Sprachunterstützung, kann jedoch langsamer und weniger benutzerfreundlich sein.

Was die Geschwindigkeit betrifft, liegt Puppeteer im Allgemeinen an der Spitze, dicht gefolgt von Playwright (wobei Playwright in einigen Fällen sogar Puppeteer übertrifft). Selen hinkt in der Leistung hinterher.

Lassen Sie uns die NPM-Trends und die Beliebtheit dieser drei Bibliotheken untersuchen. Die Daten deuten darauf hin, dass die Akzeptanz von Playwright bei Entwicklern zunimmt.


Vollständiger Bibliotheksvergleich
Vollständiger Bibliotheksvergleich

Werfen wir einen Blick auf die Vergleichstabelle:

Parameter Dramatiker Puppenspieler Selen
Geschwindigkeit Schnell Schnell Langsam
Dokumentation Exzellent Exzellent Gerecht
Entwicklererfahrung Am besten Gut Gerecht
Sprachunterstützung JavaScript, Python, C#, Java JavaScript Java, Python, C#, Ruby, JavaScript, Kotlin
Von Microsoft Google Community und Sponsoren
Gemeinschaft Klein, aber aktiv Groß und aktiv Groß und aktiv
Browser-Unterstützung Chromium, Firefox und WebKit Chrom Chrome, Firefox, IE, Edge, Opera, Safari

Abschluss

Playwright bietet ein leistungsstarkes und vielseitiges Toolkit für Web-Scraping-Aufgaben mit hervorragender Dokumentation und einer wachsenden Community. Durch die Nutzung seiner Funktionen können Sie wertvolle Daten effizient aus Websites extrahieren, sich wiederholende Browserinteraktionen automatisieren und verschiedene Arbeitsabläufe optimieren.

In diesem Leitfaden haben wir uns auf die GitHub-Themenseite konzentriert, auf der Sie ein Thema (z. B. NodeJS) auswählen und die Anzahl der Repositorys zum Scrapen angeben können. Wir haben den Umgang mit Fehlern und Randfällen beim Scraping, die Verwendung von Proxys zur Vermeidung von Erkennung und den Vergleich mit Selenium und Puppeteer erläutert.

Wenn Sie Erfahrung sammeln, lernen Sie fortgeschrittene Techniken im Detail kennen, z. B. das Konfigurieren von Proxys, das Abfangen von Anfragen, das Verwalten von Cookies und das Blockieren unnötiger Ressourcen und Bilder. Sie können mehr über Playwright erfahren, indem Sie die offizielle Dokumentation besuchen, die leicht verständlich und detailliert ist.

Related Posts

Hinterlasse einen Kommentar