Clientseitiges Web-Scraping mit JavaScript unter Verwendung von jQuery und Regex

Als ich mein erstes Open-Source-Projekt, codeBadges, erstellte, dachte ich, es wäre einfach, Benutzerprofildaten von allen wichtigen Code-Lernwebsites abzurufen.

Ich war mit API-Aufrufen und Anfragen vertraut. Ich dachte, ich könnte einfach jQuery verwenden, um die Daten von den verschiedenen APIs abzurufen und zu verwenden.

var name = 'codemzy'; $.get('//api.github.com/users/' + name, function(response) { var followers = response.followers;});

Das war einfach. Es stellt sich jedoch heraus, dass nicht jede Website über eine öffentliche API verfügt, mit der Sie einfach die gewünschten Daten abrufen können.

Aber nur weil es keine öffentliche API gibt, heißt das nicht, dass Sie aufgeben müssen! Sie können Web Scraping verwenden, um die Daten mit nur wenig zusätzlicher Arbeit abzurufen .

Mal sehen, wie wir clientseitiges Web-Scraping mit JavaScript verwenden können.

Zum Beispiel werde ich meine Benutzerinformationen aus meinem öffentlichen freeCodeCamp-Profil abrufen. Sie können diese Schritte jedoch auf jeder öffentlichen HTML-Seite ausführen.

Der erste Schritt beim Scraping der Daten besteht darin, das gesamte HTML-Format mithilfe einer jQuery- .getAnforderung abzurufen .

var name = "codemzy";$.get('//www.freecodecamp.com/' + name, function(response) { console.log(response);});

Genial, der gesamte Seitenquellcode wurde gerade in der Konsole protokolliert.

Hinweis: Wenn Sie zu diesem Zeitpunkt einen Fehler in der Art von erhalten No ‘Access-Control-Allow-Origin’ header is present on the requested resourceÄrgere dich nicht. Scrollen Sie nach unten zum Abschnitt Lassen Sie sich nicht von CORS aufhalten .

Das war einfach. Unter Verwendung von JavaScript und jQuery fordert der obige Code eine Seite von www.freecodecamp.org an, wie dies ein Browser tun würde. Und freeCodeCamp antwortet mit der Seite. Anstelle eines Browsers, der den Code zum Anzeigen der Seite ausführt, erhalten wir den HTML-Code.

Und genau das ist Web Scraping, bei dem Daten von Websites extrahiert werden.

Ok, die Antwort ist nicht genau so ordentlich wie die Daten, die wir von einer API zurückerhalten.

Aber ... wir haben die Daten irgendwo drin.

Sobald wir den Quellcode haben, müssen wir nur noch die Daten abrufen, die wir brauchen!

Wir können die Antwort durchsuchen, um die Elemente zu finden, die wir benötigen.

Angenommen, wir möchten anhand der Antwort auf das Benutzerprofil wissen, wie viele Herausforderungen der Benutzer abgeschlossen hat.

Zum Zeitpunkt des Schreibens sind die abgeschlossenen Herausforderungen eines Wohnmobils in Tabellen im Benutzerprofil organisiert. Um die Gesamtzahl der abgeschlossenen Herausforderungen zu erhalten, können wir die Anzahl der Zeilen zählen.

Eine Möglichkeit besteht darin, die gesamte Antwort in ein jQuery-Objekt zu packen, damit wir jQuery-Methoden verwenden können .find(), um die Daten abzurufen .

// number of challenges completedvar challenges = $(response).find('tbody tr').length;

Das funktioniert gut - wir bekommen das richtige Ergebnis. Aber es ist kein guter Weg , um das gewünschte Ergebnis zu erzielen. Wenn Sie die Antwort in ein jQuery-Objekt verwandeln, wird tatsächlich die gesamte Seite geladen, einschließlich aller externen Skripte, Schriftarten und Stylesheets von dieser Seite. Oh!

Wir brauchen ein paar Datenbits. Wir brauchen die Seite wirklich nicht zum Laden und schon gar nicht alle externen Ressourcen, die damit verbunden sind.

Wir könnten die Skript-Tags entfernen und dann den Rest der Antwort über jQuery ausführen. Zu diesem Zweck könnten wir Regex verwenden, um nach Skriptmustern im Text zu suchen und diese zu entfernen.

Oder noch besser, warum nicht Regex verwenden, um zu finden, wonach wir suchen?

// number of challenges completedvar challenges = response.replace(/[\s|\S]*?/g).match(//g).length;

Und es funktioniert! Mit dem obigen Regex-Code entfernen wir die Tabellenkopfzeilen (die keine Herausforderungen enthielten) und stimmen dann alle Tabellenzeilen ab, um die Anzahl der abgeschlossenen Herausforderungen zu zählen.

Es ist noch einfacher, wenn die gewünschten Daten nur in der Antwort im Klartext enthalten sind. Zum Zeitpunkt des Schreibens waren die Benutzerpunkte im HTML-Format ähnlich

[ 1498 ]]

Ich warte nur darauf, abgekratzt zu werden.

var points = response.match(/

\[ ([\d]*?) \]/)[1];

Im obigen Regex-Muster stimmen wir mit dem gesuchten h1-Element überein, einschließlich des Elements [ ], das die Punkte umgibt, und gruppieren eine beliebige Zahl darin. ([\d]*?).Wir erhalten ein Array zurück, das erste [0]Element ist die gesamte Übereinstimmung und das zweite [1]ist unsere Gruppenübereinstimmung (unsere Punkte) ).

Regex ist nützlich, um alle Arten von Mustern in Zeichenfolgen abzugleichen, und es ist ideal, um unsere Antwort zu durchsuchen, um die Daten zu erhalten, die wir benötigen.

Sie können denselben dreistufigen Prozess verwenden, um Profildaten von verschiedenen Websites zu entfernen:

  1. Verwenden Sie clientseitiges JavaScript
  2. Verwenden Sie jQuery, um die Daten zu kratzen
  3. Verwenden Sie Regex, um die Daten nach den relevanten Informationen zu filtern

Bis ich auf ein Problem stoße, CORS.

Lass dich nicht von CORS aufhalten!

CORS oder Cross-Origin Resource Sharing können ein echtes Problem beim clientseitigen Web-Scraping sein.

Aus Sicherheitsgründen beschränken Browser originenspezifische HTTP-Anforderungen, die aus Skripten heraus initiiert werden. Und da wir clientseitiges Javascript im Front-End für das Web-Scraping verwenden, können CORS-Fehler auftreten.

Hier ist ein Beispiel für den Versuch, Profildaten aus CodeWars zu entfernen.

var name = "codemzy";$.get('//www.codewars.com/users/' + name, function(response) { console.log(response);});

Zum Zeitpunkt des Schreibens führt das Ausführen des obigen Codes zu einem CORS-bezogenen Fehler.

Wenn Access-Control-Allow-Originan der Stelle, an der Sie kratzen, kein Header vorhanden ist , können Probleme auftreten.

The bad news is, you need to run these sorts of requests server-side to get around this issue.

Whaaaaaaaat, this is supposed to be client-side web scraping?!

The good news is, thanks to lots of other wonderful developers that have run into the same issues, you don’t have to touch the back end yourself.

Staying firmly within our front end script, we can use cross-domain tools such as Any Origin, Whatever Origin, All Origins, crossorigin and probably a lot more. I have found that you often need to test a few of these to find the one that will work on the site you are trying to scrape.

Back to our CodeWars example, we can send our request via a cross-domain tool to bypass the CORS issue.

var name = "codemzy";var url = "//anyorigin.com/go?url=" + encodeURIComponent("//www.codewars.com/users/") + name + "&callback=?";$.get(url, function(response) { console.log(response);});

And just like magic, we have our response.