Voraussetzungen
Bevor wir beginnen, stellen wir sicher, dass wir über die erforderlichen Tools verfügen.
Laden Sie zunächst Node.js von der offiziellen Website herunter und installieren Sie es. Achten Sie dabei darauf, die Long-Term-Support-Version (LTS) zu verwenden. Dadurch wird automatisch auch der Node Package Manager (NPM) installiert, den wir zur Installation weiterer Abhängigkeiten nutzen werden.
Für dieses Tutorial verwenden wir Visual Studio Code als unsere integrierte Entwicklungsumgebung (IDE), aber Sie können jede andere IDE Ihrer Wahl verwenden. Erstellen Sie einen neuen Ordner für Ihr Projekt, öffnen Sie das Terminal und führen Sie den folgenden Befehl aus, um ein neues Node.js-Projekt einzurichten:
npm init -y
Dadurch wird eine Datei namens package.json in Ihrem Projektverzeichnis erstellt, in der Informationen zu Ihrem Projekt und dessen Abhängigkeiten gespeichert werden.
Als Nächstes müssen wir TypeScript und die Typdefinitionen für Node.js installieren. TypeScript bietet optionale statische Typisierung, die hilft, Fehler im Code zu vermeiden. Führen Sie dazu im Terminal folgenden Befehl aus:
npm install typescript @types/node --save-dev
Sie können die Installation überprüfen, indem Sie Folgendes ausführen:
npx tsc --version
TypeScript verwendet eine Konfigurationsdatei namens tsconfig.json, um Compiler-Optionen und andere Einstellungen zu speichern. Um diese Datei in Ihrem Projekt zu erstellen, führen Sie den folgenden Befehl aus:
npx tsc -init
Stellen Sie sicher, dass der Wert für „outDir“ auf „dist“ gesetzt ist. Auf diese Weise trennen wir die TypeScript-Dateien von den kompilierten Dateien. Weitere Informationen zu dieser Datei und ihren Eigenschaften finden Sie in der offiziellen TypeScript-Dokumentation.
Erstellen Sie nun in Ihrem Projekt ein Verzeichnis „src“ und eine neue Datei „index.ts“. Hier werden wir den Scraping-Code ablegen. Um TypeScript-Code auszuführen, müssen Sie ihn zunächst kompilieren. Damit wir diesen zusätzlichen Schritt nicht vergessen, können wir einen benutzerdefinierten Befehl verwenden.
Öffne die Datei „package.json“ und bearbeite den Abschnitt „scripts“ wie folgt:
"scripts": {
"test": "npx tsc && node dist/index.js"
}
Auf diese Weise müssen Sie beim Ausführen des Skripts lediglich „npm run test“ in Ihr Terminal eingeben.
Um schließlich die Daten von der Website zu scrapen, verwenden wir Puppeteer, eine Headless-Browser-Bibliothek für Node.js, mit der Sie einen Webbrowser steuern und programmgesteuert mit Websites interagieren können. Um sie zu installieren, führen Sie diesen Befehl im Terminal aus:
npm install puppeteer
Dies ist sehr empfehlenswert, wenn Sie die Vollständigkeit Ihrer Daten sicherstellen möchten, da viele Websites heutzutage dynamisch generierte Inhalte enthalten. Wenn Sie neugierig sind, können Sie sich vor dem Fortfahren die Puppeteer-Dokumentation ansehen, um sich ein umfassendes Bild von den Möglichkeiten zu machen.
Die Daten finden
Nachdem Sie nun Ihre Umgebung eingerichtet haben, können wir uns mit der Extraktion der Daten befassen. Für diesen Artikel habe ich mich dafür entschieden, die Liste der in einer Region in Toledo, Spanien, verfügbaren Häuser und Wohnungen zu scrapen: https://www.idealista.com/pt/alquiler-viviendas/toledo/buenavista-valparaiso-la-legua/.
Wir werden die folgenden Daten aus jedem Eintrag auf der Seite extrahieren:
- die URL;
- den Titel;
- den Preis;
- die Details (Anzahl der Zimmer, Fläche usw.);
- die Beschreibung
All diese Informationen sind im folgenden Screenshot hervorgehoben:
Wenn Sie für jedes dieser Elemente die Entwicklertools öffnen, können Sie die CSS-Selektoren erkennen, die wir zum Auffinden der HTML-Elemente verwenden werden. Wenn Sie noch nicht so vertraut mit der Funktionsweise von CSS-Selektoren sind, können Sie gerne diesen Leitfaden für Anfänger zu Rate ziehen.
Datenextraktion
Bevor wir mit dem Schreiben unseres Skripts beginnen, überprüfen wir, ob die Installation von Puppeteer erfolgreich war:
import puppeteer from 'puppeteer';
async function scrapeIdealistaData(idealista_url: string): Promise<void> {
// Launch Puppeteer
const browser = await puppeteer.launch({
headless: false,
args: ['--start-maximized'],
defaultViewport: null
})
// Create a new page
const page = await browser.newPage()
// Navigate to the target URL
await page.goto(idealista_url)
// Close the browser
await browser.close()
}
scrapeIdealistaData("https://www.idealista.com/pt/alquiler-viviendas/toledo/buenavista-valparaiso-la-legua/")
Hier öffnen wir ein Browserfenster, erstellen eine neue Seite, navigieren zu unserer Ziel-URL und schließen den Browser. Der Einfachheit und zur visuellen Fehlerbehebung halber öffne ich das Browserfenster im maximierten Modus im Nicht-Headless-Modus.
Da alle Einträge die gleiche Struktur und die gleichen Daten haben, können wir in unserem Algorithmus alle Informationen für die gesamte Immobilienliste extrahieren. Nach Ausführung des Skripts können wir alle Ergebnisse durchlaufen und zu einer einzigen Liste zusammenfassen.
Um die URLs aller Immobilien zu erhalten, suchen wir die Ankerelemente mit der Klasse „item-link“. Anschließend wandeln wir das Ergebnis in ein JavaScript-Array um und ordnen jedes Element dem Wert des „href“-Attributs zu.
// Extract listings location
const listings_location = await page.evaluate(() => {
const locations = document.querySelectorAll('a.item-link')
const locations_array = Array.from(locations)
return locations ? locations_array.map(a => a.getAttribute('href')) : []
})
console.log(listings_location.length, listings_location)
Für die Titel können wir dann dasselbe Ankerelement verwenden, nur dass wir diesmal dessen „title“-Attribut extrahieren.
// Extract listings titles
const listings_title = await page.evaluate(() => {
const titles = document.querySelectorAll('a.item-link')
const titles_array = Array.from(titles)
return titles ? titles_array.map(t => t.getAttribute('title')) : []
})
console.log(listings_title.length, listings_title)
Für die Preise suchen wir die „span“-Elemente mit zwei Klassennamen: „item-price“ und „h2-simulated“. Es ist wichtig, die Elemente so eindeutig wie möglich zu identifizieren, damit das Endergebnis nicht verfälscht wird. Auch diese müssen in ein Array umgewandelt und dann ihrem Textinhalt zugeordnet werden.
// Extract listings prices
const listings_price = await page.evaluate(() => {
const prices = document.querySelectorAll('span.item-price.h2-simulated')
const prices_array = Array.from(prices)
return prices ? prices_array.map(p => p.textContent) : []
})
console.log(listings_price.length, listings_price)
Das gleiche Prinzip wenden wir auf die Objektdetails an, indem wir die „div“-Elemente mit dem Klassennamen „item-detail-char“ analysieren.
// Extract listings details
const listings_detail = await page.evaluate(() => {
const details = document.querySelectorAll('div.item-detail-char')
const details_array = Array.from(details)
return details ? details_array.map(d => d.textContent) : []
})
console.log(listings_detail.length, listings_detail)
Und schließlich die Beschreibung der Immobilien. Hier wenden wir einen zusätzlichen regulären Ausdruck an, um alle unnötigen Zeilenumbruchzeichen zu entfernen.
// Extract listings descriptions
const listings_description = await page.evaluate(() => {
const descriptions = document.querySelectorAll('div.item-description.description')
const descriptions_array = Array.from(descriptions)
return descriptions ? descriptions_array.map(d => d.textContent.replace(/(\r\n|\n|\r)/gm, "")) : []
})
console.log(listings_description.length, listings_description)
Nun sollten Sie 5 Listen haben, eine für jeden Datensatz, den wir gescrapt haben. Wie bereits erwähnt, sollten wir diese in einer einzigen Liste zusammenfassen. Auf diese Weise lassen sich die gesammelten Informationen viel einfacher weiterverarbeiten.
// Group the lists
const listings = []
for (let i = 0; i < listings_location.length; i++) {
listings.push({
url: listings_location[i],
title: listings_title[i],
price: listings_price[i],
details: listings_detail[i],
description: listings_description[i]
})
}
console.log(listings.length, listings)
Das Endergebnis sollte wie folgt aussehen:
[
{
url: '/pt/inmueble/99004556/',
title: 'Apartamento em ronda de Buenavista, Buenavista-Valparaíso-La Legua, Toledo',
price: '750€/mês',
details: '\n3 quart.\n115 m² área bruta\n2º andar exterior com elevador\nOntem \n',
description: 'Apartamento para alugar na Ronda Buenavista, em Toledo.Três quartos e duas casas de banho, sala, cozinha, terraço, garagem e arrecadação....'
},
{
url: '/pt/inmueble/100106615/',
title: 'Moradia em banda em Buenavista-Valparaíso-La Legua, Toledo',
price: '1.000€/mês',
details: '\n4 quart.\n195 m² área bruta\nOntem \n',
description: 'Magnífica casa geminada para alugar com 3 andares, 4 quartos aconchegantes, 3 banheiros, sala ampla e luminosa, cozinha totalmente equipa...'
},
{
url: '/pt/inmueble/100099977/',
title: 'Moradia em banda em calle Francisco Ortiz, Buenavista-Valparaíso-La Legua, Toledo',
price: '800€/mês',
details: '\n3 quart.\n118 m² área bruta\n10 jan \n',
description: 'O REMAX GRUPO FV aluga uma casa mobiliada na Calle Francisco Ortiz, em Toledo.Moradia geminada com 148 metros construídos, distribuídos...'
},
{
url: '/pt/inmueble/100094142/',
title: 'Apartamento em Buenavista-Valparaíso-La Legua, Toledo',
price: '850€/mês',
details: '\n4 quart.\n110 m² área bruta\n1º andar exterior com elevador\n10 jan \n',
description: 'Apartamento muito espaçoso para alugar sem móveis, cozinha totalmente equipada.Composto por 4 quartos, 1 casa de banho, terraço.Calefaç...'
}
]Bot-Erkennung umgehen
Wenn Sie Ihr Skript im Laufe dieses Tutorials mindestens zweimal ausführen, ist Ihnen vielleicht bereits diese lästige Seite aufgefallen:
Idealista nutzt DataDome als Anti-Bot-Schutz, der eine GeeTest-CAPTCHA-Herausforderung beinhaltet. Du musst das Puzzleteil verschieben, bis das Bild vollständig ist, und wirst dann zurück auf deine Zielseite weitergeleitet.
Mit diesem Code kannst du dein Puppeteer-Skript ganz einfach anhalten, bis du die Aufgabe gelöst hast:
await page.waitForFunction(() => {
const pageContent = document.getElementById('main-content')
return pageContent !== null
}, {timeout: 10000})
Dies weist unser Skript an, 10 Sekunden zu warten, bis ein bestimmter CSS-Selektor im DOM erscheint. Das sollte ausreichen, um das CAPTCHA zu lösen und die Navigation abzuschließen.
… Es sei denn, die Idealista-Seite blockiert Sie ohnehin.
An diesem Punkt wurde der Prozess komplexer und anspruchsvoller, und Sie haben Ihr Projekt noch nicht einmal skaliert.
Wie ich bereits erwähnt habe, wird Idealista durch DataDome geschützt. Sie sammeln verschiedene Browserdaten, um einen einzigartigen Fingerabdruck zu generieren und dir zuzuordnen. Wenn sie Verdacht schöpfen, erhältst du die oben genannte CAPTCHA-Herausforderung, die ziemlich schwer automatisch zu lösen ist.
Zu den gesammelten Browserdaten gehören:
- Eigenschaften des Navigator-Objekts (deviceMemory, hardwareConcurrency, languages, platform, userAgent, webdriver usw.)
- Zeit- und Leistungsprüfungen
- WebGL
- WebRTC IP-Sniffing
- Aufzeichnung von Mausbewegungen
- Inkonsistenzen zwischen dem User-Agent und Ihrem Betriebssystem
- und vieles mehr.
Eine Möglichkeit, diese Herausforderungen zu bewältigen und weiterhin in großem Umfang zu scrapen, ist die Verwendung einer Scraping-API. Diese Art von Diensten bietet eine einfache und zuverlässige Möglichkeit, auf Daten von Websites wie Idealista.com zuzugreifen, ohne dass Sie einen eigenen Scraper erstellen und warten müssen.
WebScrapingAPI ist ein Beispiel für ein solches Produkt. Sein Proxy-Rotationsmechanismus umgeht CAPTCHAs vollständig, und seine erweiterte Wissensdatenbank ermöglicht es, die Browserdaten zu randomisieren, sodass sie wie die eines echten Nutzers aussehen.
Die Einrichtung ist schnell und einfach. Sie müssen lediglich ein Konto registrieren, um Ihren API-Schlüssel zu erhalten. Dieser ist über Ihr Dashboard zugänglich und dient zur Authentifizierung der von Ihnen gesendeten Anfragen.
Da Sie Ihre Node.js-Umgebung bereits eingerichtet haben, können wir das entsprechende SDK nutzen. Führen Sie den folgenden Befehl aus, um es zu Ihren Projektabhängigkeiten hinzuzufügen:
npm install webscrapingapi
Jetzt müssen Sie nur noch die bisherigen CSS-Selektoren an die API anpassen. Die leistungsstarken Extraktionsregeln ermöglichen es, Daten ohne wesentliche Änderungen zu parsen.
import webScrapingApiClient from 'webscrapingapi';
const client = new webScrapingApiClient("YOUR_API_KEY");
async function exampleUsage() {
const api_params = {
'render_js': 1,
'proxy_type': 'residential',
'timeout': 60000,
'extract_rules': JSON.stringify({
locations: {
selector: 'a.item-link',
output: '@href',
all: '1'
},
titles: {
selector: 'a.item-link',
output: '@title',
all: '1'
},
prices: {
selector: 'span.item-price.h2-simulated',
output: 'text',
all: '1'
},
details: {
selector: 'div.item-detail-char',
output: 'text',
all: '1'
},
descriptions: {
selector: 'div.item-description.description',
output: 'text',
all: '1'
}
})
}
const URL = "https://www.idealista.com/pt/alquiler-viviendas/toledo/buenavista-valparaiso-la-legua/"
const response = await client.get(URL, api_params)
if (response.success) {
// Group the lists
const listings = []
for (let i = 0; i < response.response.data.locations.length; i++) {
listings.push({
url: response.response.data.locations[i],
title: response.response.data.titles[i],
price: response.response.data.prices[i],
details: response.response.data.details[i],
description: response.response.data.descriptions[i].replace(/(\r\n|\n|\r)/gm, "")
})
}
console.log(listings.length, listings)
} else {
console.log(response.error.response.data)
}
}
exampleUsage();Fazit
In diesem Artikel haben wir Ihnen gezeigt, wie Sie mit TypeScript und Puppeteer Daten von Idealista, einer beliebten spanischen Immobilienwebsite, scrapen können. Wir haben den Prozess der Einrichtung der Voraussetzungen und des Scrapings der Daten durchlaufen und einige Möglichkeiten zur Verbesserung des Codes besprochen.
Das Web-Scraping von Idealista kann wertvolle Informationen für Unternehmen und Privatpersonen liefern. Mit den in diesem Artikel beschriebenen Techniken können Sie Daten wie Immobilien-URLs, Preise und Beschreibungen von der Website extrahieren.
Wenn Sie zudem die Anti-Bot-Maßnahmen und die Komplexität des Scraping-Prozesses vermeiden möchten, kann die Verwendung eines professionellen Scrapers effizienter und zuverlässiger sein als die Erstellung eines eigenen.
Wenn Sie die in diesem Leitfaden beschriebenen Schritte und Techniken befolgen, können Sie das Potenzial des Web-Scrapings von Idealista ausschöpfen und es zur Unterstützung Ihrer geschäftlichen Anforderungen nutzen. Ob für Marktforschung, Lead-Generierung oder die Schaffung neuer Geschäftsmöglichkeiten – das Web-Scraping von Idealista kann Ihnen helfen, der Konkurrenz einen Schritt voraus zu sein.




