Ursprünglich in meinem Blog veröffentlicht
Puppeteer ist eine großartige Node.js-Bibliothek, die uns viele Befehle zur Verfügung stellt, um eine kopflose (oder nicht) Chromium-Instanz zu steuern und die Navigation mit wenigen Codezeilen zu automatisieren. In diesem Beitrag werden wir die Superkräfte des Puppenspielers nutzen und ein Autoinformations-Scraping-Tool für den Gebrauchtwagenkatalog erstellen und die beste Option auswählen.
Vor ein paar Tagen habe ich mit meinem Teamkollegen und großen Freund @mafesernaarbole gelesen über Web Scraping und verschiedene Online-Tools, die sie für ein persönliches Projekt benötigte. Beim Durchsehen verschiedener Artikel und Repositories fanden wir Puppeteer , die eine High-Level-API zur Steuerung von Headless Chrome über das DevTools-Protokoll ist . Dieses tolle Tool hat unser Interesse geweckt und obwohl es am Ende des Tages für sie nicht nützlich war, sagten wir beide:"Hölle ja! Damit müssen wir etwas anfangen!!". Ein paar Tage später sagte ich ihr, Puppenspieler wäre ein großartiges Thema für den ersten Artikel meines Blogs ... und hier bin ich. Ich hoffe es gefällt euch.
Unser Studienfall
Die Idee ist ziemlich einfach, es gibt einen Gebrauchtwagenkatalog in unserem Land, Kolumbien, es ist tucarro.com.co . Im Grunde genommen die Marke und das Modell des Fahrzeugs tucarro.com.co bietet Ihnen eine Liste mit passenden Gebrauchtwagen, die landesweit zum Verkauf stehen. Die Sache ist, dass der potenzielle Kunde eines nach dem anderen dieser Ergebnisse durchsuchen und analysieren muss, welche die beste Wahl (oder Wahlmöglichkeiten) ist.
Unser Fokus liegt also darauf, eine kleine Node.js zu erstellen App zum Navigieren auf der Katalog-Website, Suchen wie ein Mensch, dann nehmen wir die erste Ergebnisseite, kratzen ihre Informationen (insbesondere das Autojahr, die gefahrenen Kilometer und den Preis ... und natürlich die Anzeigen-URL). Schließlich werden wir mit diesen Informationen und unter Verwendung eines Optimierungsalgorithmus dem Kunden die beste Wahl (oder Wahlmöglichkeiten) basierend auf dem Preis und den zurückgelegten Kilometern anbieten.
Ersteinrichtung
Wir sind dabei, eine Node.js zu erstellen Daher ist der erste Schritt natürlich, einen neuen npm
zu erstellen Projekt in einem neuen Verzeichnis. Mit der -y
Parameter wird die package.json mit Standardwerten erstellt:
$ npm init -y
Und fügen Sie den Puppenspieler hinzu Abhängigkeit von Ihrem Projekt
$ npm install --save puppeteer
# or, if you prefer Yarn:
$ yarn add puppeteer
Fügen Sie schließlich in unserer Datei package.json das folgende Skript hinzu:
"scripts": {
"start": "node index.js"
}
Dieses Skript vereinfacht die Ausführung unserer App - jetzt können wir es mit nur npm start
tun Befehl
Lass uns rocken
Mit unserem npm
Projekt erfolgreich konfiguriert, der nächste Schritt ist, ja, Codierung, lasst uns unseren index.js
erstellen Datei. Dann ist hier das Skelett für unseren Puppenspieler App
'use strict'
const puppeteer = require('puppeteer')
async function run() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
browser.close()
}
run();
Grundsätzlich importieren wir einen puppeteer
Abhängigkeit in Zeile 2 , dann öffnen wir eine async
Funktion, um alle Browser/Puppenspieler-Interaktionen einzuschließen, erhalten wir in den folgenden Zeilen eine Instanz für den Chromium-Browser und öffnen dann einen neuen Tab (Seite) ... am Ende in den letzten Zeilen schließen wir den Browser (und seine Prozess) und schließlich den async
ausführen Funktion.
Navigieren zu unserer Zielseite
Das Aufrufen einer bestimmten Website ist eine einfache Aufgabe mit unserer Tab-Instanz (page
). Wir müssen nur den goto
verwenden Methode:
await page.goto('https://www.tucarro.com.co/')
So sieht die Website im Browser aus
Suchen
Unser Ziel ist es, die erste Ergebnisseite ohne Filter, also alle Marken, zu finden und zu kratzen. Dazu müssen wir nur mit der Website interagieren und auf Buscar
klicken Button, wir können es mit dem click
erreichen Methode von page
Beispiel.
await page.waitForSelector('.nav-search-submit')
await page.click('button[type=submit]');
Beachten Sie, dass die erste Zeile unserem Skript erlaubt, auf das Laden eines bestimmten Elements zu warten. Damit stellen wir sicher, dass Buscar
Schaltfläche gerendert wird, um darauf zu klicken, der zweite klickt einfach auf die Schaltfläche und löst den folgenden Bildschirm aus
Die Überraschung hier ist, dass die Motorräder dort verladen wurden, also müssen wir den Kategorien-Link für Fahrzeuge und Lastwagen Carros y Camionetas
verwenden Verwenden Sie natürlich dieselbe Klickfunktion und überprüfen Sie zunächst, ob der Link gerendert wurde.
await page.waitForSelector('#id_category > dd:nth-child(2) > h3 > a')
await page.click('#id_category > dd:nth-child(2) > h3 > a');
Und los geht's, jetzt haben wir unsere Auto-Ergebnisseite ... lass es uns kratzen!
Abkratzen!
Bei unserer Ergebnisseite müssen wir nur über DOM
iterieren Knoten und extrahieren Sie die Informationen. Zum Glück Puppenspieler kann uns auch dabei helfen.
await page.waitForSelector('.ch-pagination')
const cars = await page.evaluate(() => {
const results = Array.from(document.querySelectorAll('li.results-item'));
return results.map(result => {
return {
link: result.querySelector('a').href,
price: result.querySelector('.ch-price').textContent,
name: result.querySelector('a').textContent,
year: result.querySelector('.destaque > strong:nth-child(1)').textContent,
kms: result.querySelector('.destaque > strong:nth-child(3)').textContent
}
});
return results
});
console.log(cars)
Im obigen Skript verwenden wir den evaluate
Methode für die Ergebnisprüfung, dann iterieren wir mit einigen Abfrageselektoren die Ergebnisliste, um die Informationen jedes Knotens zu extrahieren und eine Ausgabe wie diese für jeden Artikel/jedes Auto zu erzeugen
{ link: 'https://articulo.tucarro.com.co/MCO-460314674-ford-fusion-2007-_JM',
price: '$ 23.800.000 ',
name: ' Ford Fusion V6 Sel At 3000cc',
year: '2007',
kms: '102.000 Km' }
Oh ja! Wir haben die Informationen und mit JSON
Struktur, aber wenn wir sie optimieren wollen, müssen wir die Daten normalisieren - schließlich sind die Berechnungen mit diesen Kms
etwas kompliziert und $
Symbole, nicht wahr? ... Also werden wir unser Ergebniskartenfragment wie folgt ändern
return results.map(result => {
return {
link: result.querySelector('a').href,
price: Number((result.querySelector('.ch-price').textContent).replace(/[^0-9-]+/g,"")),
name: result.querySelector('a').textContent,
year: Number(result.querySelector('.destaque > strong:nth-child(1)').textContent),
kms: Number((result.querySelector('.destaque > strong:nth-child(3)').textContent).replace(/[^0-9-]+/g,""))
}
});
Sicher, Regular Expressions
retten Sie den Tag, wir haben Nummern, wo wir Nummern wollen.
Optimierungszeit!!
Zu diesem Zeitpunkt haben wir bereits einen Vorgeschmack auf die Geschmacksrichtungen von Puppeteer bekommen, was unser Hauptziel für diesen Artikel war. In diesem letzten Abschnitt werden wir eine einfache Heuristik verwenden, um die beste Autoauswahl basierend auf den gesammelten Daten zu treffen. Grundsätzlich erstellen wir eine heuristische Funktion, um einige score
zu berechnen die es uns ermöglichen, jedes Fahrzeug zu bewerten und die beste Option auszuwählen. Dazu berücksichtigen wir folgende Punkte:
- Jeder Variablen weisen wir dann eine Gewichtung zu, basierend auf der Wichtigkeit für den potenziellen Kunden (Preis hat 4, und Jahr und Kilometer haben jeweils 3).
- Angesichts der Tatsache, dass die Kilometer und der Preis minimiert werden sollten, werden wir seine Werte als Bruch-Nenner verwenden
- Zur Vereinfachung der Berechnung normalisieren wir die numerischen Faktoren für unsere Variablen, sodass jeder Preis zwischen 1 Million, Jahr und km durch 1.000 geteilt würde
Dies ist die endgültige Formel Haftungsausschluss:Dies ist eine hypothetische Formel zur Vervollständigung dieser Übung, daher hat sie im wirklichen Leben keinen mathematischen oder wissenschaftlichen Wert
score = 4 (1/price) + 3 (year) + 3 (1/kms)
Und das Code-Snippet mit dieser Formel
let car = {score: 0}
for (let i = 0; i < cars.length; i++) {
cars[i].score = (4 * (1/(cars[i].price/1000000))) + (3 * (cars[i].year/1000)) + (3 * (1/(cars[i].kms/1000)))
if(cars[i].score > car.score){
car = cars[i]
}
}
console.log(car)
Endlich mit Puppenspieler Wir besuchen den Ergebnislink und machen einen Screenshot
await page.goto(car.link)
await page.waitForSelector('.gallery__thumbnail')
await page.screenshot({path: 'result.png', fullPage: true});