26. Februar 2024
Mit node.js JavaScript-generierte Inhalte scrapen
Eine etwas unkonventionelle Lösung habe ich mit für folgendes Problem überlegt.
Für einen Kunden scrape ich automatisiert bestimmte Inhalte diverser Websites.
Problem Nr. 1: Inzwischen werden viele Inhalte erst im Client-seitig mit JavaScript generiert. Das macht es unmöglich sie mit PHP zu crawlen. Auf der Suche nach einer Lösung stößt man schnell auf „node.js“ & „puppeteer“.
Problem Nr. 2: Ich habe keinen Webserver auf dem ich node.js nutzen kann.
Deshalb habe ich mir folgende Lösung überlegt:
Ich habe node.js lokal installiert. Anschließend habe ich „axios, puppeteer & form-data“ via npm installiert. Mit Hilfe von ChatGPT habe ich ein Skript entwickelt, das die gewünschte URL aufruft und den Code der generierten HTML-Seite auf einen Webserver überträgt und dort als statische HTML-Seite ablegt. Diese Seite kann ich dann wie gewohnt mit einem „normalen“ PHP-Crawler auslesen.
const axios = require('axios');
const puppeteer = require('puppeteer');
const FormData = require('form-data');
const apiKey = 'sofahpoeh4e898zw34853u9fh34';
const filename = 'content-XY.html';
async function getGeneratedSource(url) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle2' });
await page.evaluate(() => new Promise(resolve => setTimeout(resolve, 5000)));
//await page.waitForTimeout(5000);
const generatedSource = await page.content();
await browser.close();
return generatedSource;
}
async function sendSourceToPHP(source, apiKey, filename) {
console.log(source);
try {
const form = new FormData();
form.append('source', source);
form.append('apiKey', apiKey);
form.append('filename', filename);
const response = await axios.post('####URL_DES_ZIELSERVERS####/getdata.php', form, {
headers: {
...form.getHeaders(),
},
});
console.log(response.data);
} catch (error) {
console.error('Fehler beim Senden des Quelltexts:', error.message);
}
}
const websiteUrl = '#####URL_DER_ZU_CRAWLENDEN_WEBSITE#####';
getGeneratedSource(websiteUrl)
.then((source) => sendSourceToPHP(source, apiKey, filename))
.catch((error) => console.error('Fehler beim Extrahieren des Quelltexts:', error));
Code-Sprache: JavaScript (javascript)
Dieser Code ruft die Inhalte der zu crawlenden Website aus und sendet sie an den Zielserver. Die „sendSourceToPHP.js“ kann im Terminal mit „node sendSourceToPHP.js“ ausgeführt werden. Sinnvoll ist es hierfür einen Cronjob einzurichten.
Auf dem Zielserver werden die Daten von folgendem Code empfangen und als statische HTML-Website gespeichert:
<?php
$receivedSource = $_POST['source'];
$receivedApiKey = $_POST['apiKey'];
$receivedFilename = $_POST['filename'];
$validApiKey = 'sofahpoeh4e898zw34853u9fh34';
if ($receivedApiKey === $validApiKey) {
$filePath = $receivedFilename;
file_put_contents($filePath, $receivedSource);
echo 'Daten erfolgreich empfangen und gespeichert.';
} else {
http_response_code(403);
echo 'Ungültiger API-Key.';
}
?>
Code-Sprache: HTML, XML (xml)
Die Verwendung eines (beliebigen) API-Keys verhindert, dass fremde Inhalte an das Skript übertragen werden können.