Erstellen Sie mit Puppeteer einen Autopreis-Scraper-Optimierer

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});

und das war's!