Wie man einen Scraper baut und eine Datei mit Puppeteer herunterlädt

Mihnea-Octavian Manolache am 25. April 2023

blog-image

Wenn Sie sich mit Web-Scraping beschäftigen und Node JS verwenden, haben Sie höchstwahrscheinlich schon von Puppeteer gehört. Und Sie sind bestimmt schon einmal auf eine Aufgabe gestoßen, bei der Sie eine Datei mit Puppeteer herunterladen mussten. Dies ist in der Tat eine immer wiederkehrende Aufgabe in der Scraping-Community. Aber sie ist in der Puppeteer-Dokumentation nicht gut dokumentiert.

Zum Glück werden wir uns gemeinsam darum kümmern. In diesem Artikel werden wir über Dateidownloads in Puppeteer sprechen. Es gibt zwei Ziele, die ich heute ansprechen möchte:

  1. Sie haben ein solides Verständnis dafür, wie Puppeteer mit Downloads umgeht
  2. Erstellen Sie einen funktionierenden Dateidownload-Scraper mit Node und Puppeteer

Am Ende dieses Artikels werden Sie sowohl die theoretischen als auch die praktischen Fähigkeiten erworben haben, die ein Entwickler benötigt, um einen File Scraper zu erstellen. Wenn dieses Projekt so spannend klingt wie für mich, dann lassen Sie uns loslegen!

Warum eine Datei mit Puppeteer herunterladen?

Es gibt viele Anwendungsfälle für einen File Scraper und StackOverflow ist voll von Entwicklern, die nach Antworten suchen, wie man Dateien mit Puppeteer herunterladen kann. Und wir müssen verstehen, dass Dateien Bilder, PDFs, Excel- oder Word-Dokumente und vieles mehr umfassen. Sie können sehen, warum all diese Dateien sehr wichtige Informationen für jemanden liefern können.

So gibt es beispielsweise Unternehmen in der Dropshipping-Branche, die sich auf Bilder aus externen Quellen wie Marktplätzen stützen. Ein weiteres gutes Beispiel für den Einsatz eines Scrapers zum Herunterladen von Dateien sind Unternehmen, die offizielle Dokumente überwachen. Oder auch kleine Projekte. Ich selbst habe ein Skript, das Rechnungen von der Website eines Partners herunterlädt.

Wenn es darum geht, Puppeteer zum Herunterladen von Dateien zu verwenden, haben sich die meisten Leute hauptsächlich aus zwei Gründen dafür entschieden:

  1. Es wurde für Node JS entwickelt, und Node JS ist eine der beliebtesten Programmiersprachen, sowohl für das Front-End als auch für das Back-End.
  2. Es wird ein echter Browser geöffnet, und einige Websites sind auf JavaScript angewiesen, um Inhalte darzustellen. Das bedeutet, dass Sie die Dateien mit einem normalen HTTP-Client, der keine JavaScript-Dateien darstellen kann, nicht herunterladen können.

Wie Puppeteer das Herunterladen von Dateien handhabt

Um zu verstehen, wie man mit Puppeteer Dateien herunterlädt, muss man auch wissen, wie Chrome das macht. Das liegt daran, dass Puppeteer im Kern eine Bibliothek ist, die Chrome über das Chrome DevTools Protocol (CDP) "steuert".

In Chrome können Dateien heruntergeladen werden:

  1. Manuell, zum Beispiel mit einem Klick auf eine Schaltfläche
  2. Programmatisch, über die Page Domain von CDP.

Und es gibt noch eine dritte Technik, die beim Web Scraping eingesetzt wird. Dabei wird ein neuer Akteur integriert: ein HTTP-Client. Auf diese Weise sammelt der Web Scraper "Hrefs" der Dateien, und dann wird ein HTTP-Client zum Herunterladen der Dateien verwendet. Jede Option hat ihre eigenen Anwendungsfälle, und so werden wir beide Wege erkunden.

Herunterladen von Dateien in Puppeteer mit einem Klick auf eine Schaltfläche

In dem glücklichen Fall, dass die Website, von der Sie Dateien abrufen möchten, Schaltflächen verwendet, müssen Sie lediglich das Klick-Ereignis in Puppeteer simulieren. Die Implementierung eines Datei-Downloaders ist in diesem Szenario ziemlich einfach. Puppeteer dokumentiert sogar die Page.click()-Methode und Sie können hier weitere Informationen finden.

Da dies ein "menschenähnliches" Verhalten ist, müssen wir Folgendes tun:

  • Öffnen Sie den Browser
  • Navigieren Sie zu der gewünschten Webseite
  • Suchen Sie das Schaltflächenelement (z. B. über seinen CSS-Selektor oder xPath)
  • Klicken Sie auf die Schaltfläche

Es gibt nur vier einfache Schritte, die wir in unserem Skript implementieren müssen. Bevor wir jedoch in die Programmierung eintauchen, möchte ich Ihnen sagen, dass die von Puppeteer gesteuerte Chrome-Instanz die heruntergeladene Datei genau wie Ihr täglicher Browser im Standard-Download-Ordner speichert, und zwar:

  • \Users\<username>\Downloads for Windows
  • /Users/<username>/Downloads for Mac
  • /home/<username>/Downloads for Linux

In diesem Sinne lassen Sie uns mit der Programmierung beginnen. Wir nehmen an, dass wir Astrophysiker sind und einige Daten von der NASA sammeln müssen, die wir später verarbeiten werden. Im Moment konzentrieren wir uns auf das Herunterladen der .doc-Dateien.

#Nr. 1: Identifizieren Sie anklickbare" Elemente

Wir werden hier zur NASA-Domäne navigieren und die Elemente der Seite untersuchen. Unser Schwerpunkt liegt auf der Identifizierung "klickbarer" Elemente. Um die Elemente zu finden, öffnen Sie die Entwicklertools (Command + Option + I / Control + Shift + I in Chrome):

blog-image

#Nr. 2: Code für das Projekt

import puppeteer from "puppeteer"

(async () => {

const browser = await puppeteer.launch({ headless: false })

const page = await browser.newPage()

await page.goto('https://www.nasa.gov/centers/dryden/research/civuav/civ_uav_doc-n-ref.html',

{ waitUntil: 'networkidle0' })

const tr_elements = await page.$x('html/body/div[1]/div[3]/div[2]/div[2]/div[5]/div[1]/table[2]/tbody/tr')

for (let i = 2; i<=tr_elements.length; i ++) {

const text = await tr_elements[i].evaluate(el => el.textContent)

if (text.toLocaleLowerCase().includes('doc')) {

try {

await page.click(`#backtoTop > div.box_710_cap > div.box_710.box_white.box_710_white > div.white_article_wrap_detail.text_adjust_me > div.default_style_wrap.prejs_body_adjust_detail > table:nth-child(6) > tbody > tr:nth-child(${i}) > td:nth-child(3) > a`)

}catch {}

}

}

await browser.close()

})()

Was wir hier tun, ist:

  1. Starten Sie Puppeteer und navigieren Sie zu unserer Ziel-Website
  2. Wählen Sie alle "tr"-Elemente aus, die den "hrf" enthalten, den wir später anklicken wollen.
  3. Iterieren Sie durch die tr-Elemente und
    a. Prüfen Sie, ob der Text innerhalb des Elements das Wort "doc" enthält
    b. Falls ja, erstellen wir den Selektor und klicken auf das Element
  4. Schließen Sie den Browser

Und das war's. Das Herunterladen von Dateien mit Puppeteer kann so einfach sein, wie es nur geht.

Herunterladen von Dateien in Puppeteer mit CDP

Ich weiß, dass der Standard-Download-Ordner für kleine Projekte kein großes Problem darstellt. Bei größeren Projekten hingegen werden Sie die mit Puppeteer heruntergeladenen Dateien sicherlich in verschiedenen Verzeichnissen organisieren wollen. Und genau hier kommt CDP ins Spiel. Um dieses Ziel zu erreichen, werden wir den aktuellen Code beibehalten und ihn nur ergänzen.

Das erste, woran man denken kann, ist die Auflösung des Pfades zum aktuellen Verzeichnis. Glücklicherweise können wir das eingebaute node:path-Modul verwenden. Alles, was wir tun müssen, ist, das Modul `path` in unser Projekt zu importieren und die Methode `resolve` zu verwenden, wie Sie gleich sehen werden.

Der zweite Aspekt ist die Einstellung des Pfades in unserem Browser mit Hilfe von CDP. Wie ich bereits sagte, verwenden wir die Methode "setDownloadBehavior" der Page Domain. So sieht unser aktualisierter Code mit den beiden hinzugefügten Methoden aus:

import puppeteer from "puppeteer"

import path from 'path'

(async () => {

const browser = await puppeteer.launch({ headless: false })

const page = await browser.newPage()

const client = await page.target().createCDPSession()

await client.send('Page.setDownloadBehavior', {

behavior: 'allow',

downloadPath: path.resolve('./documents')

});

await page.goto('https://www.nasa.gov/centers/dryden/research/civuav/civ_uav_doc-n-ref.html',

{ waitUntil: 'networkidle0' })

const tr_elements = await page.$x('html/body/div[1]/div[3]/div[2]/div[2]/div[5]/div[1]/table[2]/tbody/tr')

for (let i = 1; i<=tr_elements.length; i ++) {

const text = await tr_elements[i].evaluate(el => el.textContent)

if (text.toLocaleLowerCase().includes('doc')) {

try {

await page.click(`#backtoTop > div.box_710_cap > div.box_710.box_white.box_710_white > div.white_article_wrap_detail.text_adjust_me > div.default_style_wrap.prejs_body_adjust_detail > table:nth-child(6) > tbody > tr:nth-child(${i}) > td:nth-child(3) > a`)

} catch {}

}

}

await browser.close()

})()

Hier sehen Sie, was wir mit dem hinzugefügten Code machen:

  1. Wir erstellen eine neue CDPSession, um mit dem 'raw Chrome Devtools Protocol' zu sprechen
  2. Wir senden das Ereignis `Page.setDownloadBehavior` aus, wobei
    a. `behavior` auf `allow` Downloads gesetzt wird
    b.`downloadPath` mit `node:path` gebaut wird, um auf den Ordner zu zeigen, in dem wir unsere Dateien speichern werden

Und das ist alles, was Sie tun müssen, wenn Sie das Verzeichnis ändern wollen, in dem Sie Dateien mit Puppeteer speichern. Außerdem haben wir unser Ziel, einen Web-Scraper zum Herunterladen von Dateien zu bauen, erreicht.

Datei mit Puppeteer und Axios herunterladen

Die dritte Option, die wir besprochen haben, ist das Sammeln von Links zu den Zielseiten und die Verwendung eines HTTP-Clients, um sie herunterzuladen. Ich persönlich bevorzuge axios, aber es gibt auch Alternativen zu axios, wenn es um Web Scraping geht. Für dieses Tutorial werde ich axios verwenden und davon ausgehen, dass wir einen Scraper für Bilder von versteigerten Autos bauen.

#1: Sammeln Sie die Links zu unseren Dateien

const get_links = async (url) => {

const hrefs = []

const browser = await puppeteer.launch({ headless: false })

const page = await browser.newPage()

await page.goto(url, { waitUntil: 'networkidle0' })

const images = await page.$$('img')

for (let i = 1; i<=images.length; i ++) {

try {

hrefs.push(await images[i].evaluate(img => img.src))

} catch {}

}

await browser.close()

return hrefs

}

Ich bin sicher, dass Sie inzwischen mit der Puppeteer-Syntax vertraut sind. Im Gegensatz zu den obigen Skripten werten wir jetzt `img`-Elemente aus, extrahieren ihre Quell-URL, fügen sie an ein Array an und geben das Array zurück. Nichts Ausgefallenes an dieser Funktion.

#2: Dateien mit axios speichern

const download_file = async (url, save) => {

const writer = fs.createWriteStream(path.resolve(save))

const response = await axios({

url,

method: 'GET',

responseType: 'stream'

})

response.data.pipe(writer)

return new Promise((resolve, reject) => {

writer.on('finish', resolve)

writer.on('error', reject)

})

}

Diese Funktion ist ein wenig komplexer, da sie zwei neue Pakete einführt: `fs` und `axios`. Die erste Methode aus dem `fs`-Paket ist so ziemlich selbsterklärend. Sie erzeugt einen beschreibbaren Stream. Sie können hier mehr darüber lesen.

Als nächstes verwenden wir axios, um die URL des Servers "anzuzapfen" und teilen axios mit, dass die Antwort vom Typ "stream" sein wird. Schließlich, da wir mit einem Stream arbeiten, werden wir `pipe()` verwenden, um die Antwort in unseren Stream zu schreiben.

Nach diesem Aufbau müssen die beiden Funktionen nur noch zu einem lauffähigen Programm kombiniert werden. Fügen Sie dazu einfach die folgenden Codezeilen ein:

let i = 1

const images = await get_links('https://www.iaai.com/Search?url=PYcXt9jdv4oni5BL61aYUXWpqGQOeAohPK3E0n6DCLs%3d')

images.forEach(async (img) => {

await download_file(img, `./images/${i}.svg`)

i += 1

})

Schlussfolgerungen

Die Dokumentation von Puppeteer mag unklar sein, was das Herunterladen von Dateien angeht. Nichtsdestotrotz haben wir heute einige Möglichkeiten entdeckt, dies zu implementieren. Beachten Sie jedoch, dass das Scrapen von Dateien mit Puppeteer keine einfache Aufgabe ist. Puppeteer startet nämlich einen Headless-Browser, und diese werden normalerweise sehr schnell blockiert.

Wenn Sie auf der Suche nach einer heimlichen Möglichkeit sind, Dateien programmgesteuert herunterzuladen, können Sie sich an einen Web Scraping-Dienst wenden. Bei Web Scraping API haben wir viel Zeit und Mühe investiert, um unsere Fingerabdrücke zu verbergen, damit wir nicht entdeckt werden. Und das zeigt sich auch in unserer Erfolgsquote. Das Herunterladen von Dateien mit Web Scraping API kann so einfach sein wie das Senden einer Curl-Anfrage, und wir kümmern uns um den Rest.

In diesem Sinne hoffe ich wirklich, dass der heutige Artikel Ihnen bei Ihrem Lernprozess geholfen hat. Außerdem hoffe ich, dass wir unsere beiden ursprünglichen Ziele erreicht haben. Ab jetzt sollten Sie in der Lage sein, Ihre eigenen Tools zu erstellen und Dateien mit Puppeteer herunterzuladen.

Nachrichten und Aktualisierungen

Bleiben Sie auf dem Laufenden mit den neuesten Web Scraping-Anleitungen und Nachrichten, indem Sie unseren Newsletter abonnieren.

We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Ähnliche Artikel

Vorschaubild
LeitfädenScrapy Splash Tutorial: Die Kunst des Scrapings von JavaScript-gerenderten Websites mit Scrapy und Splash beherrschen

Lernen Sie, wie Sie mit Scrapy und Splash dynamische JavaScript-gerenderte Websites scrapen können. Von der Installation über das Schreiben eines Spiders bis hin zum Umgang mit Seitenumbrüchen und der Verwaltung von Splash-Antworten bietet dieser umfassende Leitfaden Schritt-für-Schritt-Anleitungen für Anfänger und Experten gleichermaßen.

Ștefan Răcila
Autorenavatar
Ștefan Răcila
6 Minuten lesen
Vorschaubild
LeitfädenErfahren Sie, wie Sie die Cloudflare-Erkennung mit dem besten Selenium-Browser umgehen

Erfahren Sie, welcher Browser am besten geeignet ist, um Cloudflare-Erkennungssysteme beim Web-Scraping mit Selenium zu umgehen.

Mihnea-Octavian Manolache
Autorenavatar
Mihnea-Octavian Manolache
9 Minuten lesen
Vorschaubild
Wissenschaft des Web ScrapingWeb Scraping leicht gemacht: Die Bedeutung von Data Parsing

Erfahren Sie, wie Sie mit Hilfe von Datenparsing, HTML-Parsing-Bibliotheken und schema.org-Metadaten effizient Daten für Web-Scraping und Datenanalysen extrahieren und organisieren können.

Suciu Dan
Autorenavatar
Suciu Dan
12 Minuten lesen