a fool with a tool - scraping basics
DESCRIPTION
Reguläre Ausdrücke und XPath als Basis für jegliches Scraping.TRANSCRIPT
Reguläre Ausdrücke - Scraping Basics
...is still a fool!A (F)Uhl With A Tool...
Wer spricht hier?
Markus UhlSEOdiot
Programmieren (seit 1984)
SEO (seit 2002)
Web-Entwickler (6 Jahre)
PHPPerl
Death Metal
E-Gitarre
Bass
8 Jahre SEO-Agenturen
SEM
Condé Nast Verlag
VOGUE
GLAMOUR
GQ
Zocken (PS3)
FUS RO DAH!!!
Linux-Server Admin
Inhouse SEO
Was tun wir hier?Was ihr in 45 Minuten NICHT
könnt
Ubot oder ein anderes Tool bedienen
Copy&Paste aus der Präse für Eure Aufgaben
Auf ein Ergebnis mit zwei Mausklicks hoffen
Was ihr in 45 Minuten könnt
Reguläre Ausdrücke verstehen und entwickeln
Mit XPath beliebige Elemente des DOM-Trees addressieren
Beliebige Inhalte aus beliebigen Quellen scrapen
Reguläre AusdrückeDie Basis für algorithmische Analyse von Texten
Reguläre AusdrückeWurden bereits in den 60ern entwickelt
Beschreiben, wie eine zu suchende Zeichenkette aufgebaut ist („Pattern Matching“)
Ergeben erst mal eine Wahr/Falsch-Aussage (der Text entspricht diesem Muster oder nicht), können aber auch Zeichenfolgen extrahieren oder ersetzen
Werden in allen gängigen Programmiersprachen unterstützt
Können in vielen Programmen wie Notepad++, Screaming Frog oder OpenOffice verwendet werden. Nur MS Word hat natürlich einen komplett eigenen „Dialekt“.
Finden auch in der .htaccess von Apache Verwendung (mod_rewrite)
Auch Google Analytics unterstützt RegExes in den Filtern
GrundregelnReguläre Ausdrücke werden zur Verdeutlichung immer in Schrägstriche gesetzt:/regex/
Diese müssen in fortgeschrittenen Programmen wie Google Analytics aber oft nicht mit angegeben werden
Wenn im Ausdruck selbst ein Schrägstrich vorkommt, muss dieser mit einem Backslash „escaped“ werden: /AC\/DC/
Auch der Backslash selbst muss escaped werden:/\\/
Das escapen gilt immer, auch wenn die Schrägstriche aussenrum nicht angegeben werden müssen!
Escaped werden müssen auch alle weiteren Sonderzeichen, die für die RegEx Bedeutung haben
Modifier
Mit Hilfe angehängter „Modifier“ kann das Verhalten der RegEx beeinflusst werden
RegExes sind Case Sensitive. /campixx/ ist nicht das gleiche wie /Campixx/. Mit dem Modifier „i“ wird der Ausdruck aber Case Insensitive: /campixx/i findet dann auch „Campixx“
Reguläre Ausdrücke arbeiten zeilenweise. Mit den Modifiern „s“ und „m“ können mehrzeilige Texte verwendet werden (dazu später mehr)
Beim Extrahieren von sich wiederholenden Mustern führt der Modifier „g“ (global) dazu, dass nicht nur der erste gefundene Match zurückgegeben wird, sondern alle
Zeichenfolgen und Wildcards
konkrete Buchstabenfolgen:
/campixx/i – findet „campixx“ und „Campixx“
„.“ - irgendein beliebiges Zeichen außer einem Zeilenumbruch:
/campi../i – findet „campixx“ und „camping“
Achtung: will man einen echten Punkt finden, muss man den wie einen Schrägstrich escapen: /\./
Meta-Zeichen„\w“ – ein Buchstabe, eine Zahl oder ein Unterstrich (Word Character). Konkreter: die Buchstaben a bis z, A bis Z, Ziffern von 0 bis 9 sowie der Unterstrich „_“.
/camp\w\w\w/i findet „campixx“, „campino“ und „camping“
„\d“ - eine Zahl (Digit)
/campix\d\d\d\d/i - findet „campix2012“ und „campix2013“
„\s“ – Leerzeichen und Tabs (Spaces)
/campixx\s2013/ findet „campixx 2013“, aber nicht „campixx2013“
Von jedem Meta-Zeichen \w, \d und \s gibt es das genaue Gegenteil in Großbuchstaben: \W, \D und \S – kann manchmal hilfreich sein, um Ausdrücke kürzer zu schreiben
Einfache Wiederholungen
„?“ – das letzte Zeichen kommt nicht oder nur einmal vor
/campi?x?/ - findet „camp“, „campi“, „campx“ und „campix“
Achtung: suchen wir tatsächlich nach einem Fragezeichen, muss es escaped werden: /Hallo\?/
„*“ – das letzte Zeichen kommt nicht oder mehrmals vor
/campix*/ - findet „campi“, „campix“, „campixx“, „campixxxxxxxxxxx“
Vorsicht: die Kombination „.*“ ist gierig! Und denke ggf. ans escapen!
„+“ – das letzte Zeichen kommt ein- oder mehrmals vor
/campix+/ - findet „campix“ oder „campixx“, aber nicht „campi“
Du vermutest richtig – escapen nicht vergessen, wenn Du tatsächlich ein Plus-Zeichen suchst: /Google\+/
Konkrete Wiederholungen
{n} – das Zeichen kommt genau n-mal vor/campix{2}/ - findet „campixx“ und nichts anderes
{n,} – das Zeichen kommt mindestens n-mal vor/campix{2,}/ - findet „campixx“ und „campixxx“, aber nicht „campix“
{n,m} – das Zeichen kommt mindestens n-mal, höchstens m-mal vor/\d{4,5}\s\d+/ - findet alle Telefonnummern im Format „0179 3872342“ (Vorwahlen haben immer zwischen 4 und 5 Stellen?)
BackreferencesZum Weiterverarbeiten von Teilen der Matches werden Klammern gesetzt
/(\d{4,5})\s(\d+)/ trennt Vorwahl und Rufnummer
Diese extrahierten Werte, auch „Backreferences“ genannt, stehen dann in Variablen namens \1, \2 etc. zur Verfügung
/(\d{4,5})\s(\d+)/-> Vorwahl in \1, Rufnummer in \2
In der .htaccess wird stattdessen $1, $2 etc. verwendet
RewriteRule /alt/(.*) /neu/$1 [R=301,L]
Vorsicht: diese „/“ stehen für Verzeichnisse, NICHT für die Schreibregel der RegExes!
Alternativen„|“ – Pipe-Zeichen
Entweder die linke oder rechte Version
/ma|ey|ie?r/i - findet alle möglichen Schreibweisen des Namens „Mayer“, „Maier“, „Meier“, „Meyer“, „Mayr“, „Mair“...
Wenn mehr als ein Buchstabe betroffen ist oder sich die Alternativen schachteln, müssen Klammern drumrum helfen
/(handy|mobil)-?nummer/i – egal, ob im Formular nach der Handy- oder Mobilnummer gefragt wird und egal, ob da ein Bindestrich dazwischen ist oder nicht...
Beachte: werden die Werte später weiterverwendet, ändern sich evtl. die Nummern der Backreferences:
/(handy|mobil)-?nummer:\s+/(\d{4,5})\s(\d+)/i-> Vorwahl in \2, Rufnummer in \3
Zeichenklassen
„[...]“ – erlaubt nur die angegebenen Zeichen
/\d{4,5}[-\/\s]\d+/ - findet Telefonnummern mit den üblichen Trennzeichen, also egal ob 0179-3872342, 0179/3872342 oder 0179 3872342
Sind in manchen RegEx-Dialekten wichtig für Umlaute!\w für deutsche Texte ist dann: /[a-zäöüß]/i
„^“ – Negierung. Diese Zeichen dürfen nicht vorkommen.Beliebter Trick, um ein gieriges .* zu umgehen
Beispiel: <a href=„home.html“ class=„big“>/<a href=„(.*)“>/i – findet home.html“ class=“big/<a href=„([^“]+)“>/i – findet nur home.html
Zeilenumbrüche
„\n“
Der Zeilenumbruch ist das einzige Zeichen, das nicht von „.“ gematcht wird
Soll „.“ auch Zeilenumbrüche matchen, muss der Modifier „/s“ verwendet werden
Wenn also zum Beispiel ein Link im Quellcode über zwei Zeilen geht (etwas, das natürlich kein Programmierer je machen würde *hüstel*):
<a href=„home.html“class=„big“>/(<a.*>/ findet den Link nicht!/(<a.*>/s findet den Link.
Zeilenanfang & -ende„^“ – Beginn einer Zeile, „$“ – Ende einer Zeile
Beides ist in Verbindung mit mod_rewrite sinnvoll, um spezifische URLs weiterzuleiten
RewriteRule ^sinn$ /404.html [R=302,L]
Leitet ausschließlich die URL www.domain.de/sinn auf die Nicht-Gefunden-Seite, nicht aber die Seiten unsinn.html, macht-sinn.html oder das Verzeichnis /sinnlos
Bei mehrzeiligem Text matchen „^“ und „$“ nur genau einmal – auf die erste Zeile. Ist das Muster dort nicht vorhanden, wird die RegEx kein Ergebnis zurückliefern, auch wenn das Muster in späteren Zeilen vorkommt. Will man mehrere Zeilen untersuchen, muss man den Modifier „/m“ verwenden.
Beispiel: finde alle Absätze im Text, bei denen ich den Punkt am Ende vergessen habe:/[^\.]$/m
Erweiterung: eine Zeile kann natürlich auch mit Ausrufe-, Fragezeichen oder Doppelpunkt enden:/[^\.\?!:]$/m
Überraschung: nicht jedes Sonderzeichen hat eine Bedeutung in RegExes, so z.B. Doppelpunkt und Ausrufezeichen.
Word Boundaries
„\b“ – Wortgrenze. Der Übergang zwischen Wortzeichen (\w) und Nicht-Wortzeichen (\W)
Nützlich, wenn man ganze Worte sucht, keine Wortbestandteile, zum Beispiel:
/\ber\b/ig – findet alle „er“, aber nicht „Bier“ oder „Berg“
Merke: Google nutzt \b, um Dateinamen zu zerlegen. Ein Unterstrich „_“ ist als \w definiert. Deswegen findet /\bkeyword\b/ nichts in „mein_keyword.jpg“, weil zwischen „mein“ und „keyword“ kein \W und damit keine Word Boundary ist!
Komplexeres Beispiel
/^((\+|00)[1-9]\d{0,3}|0 ?[1-9]|\(00? ?[1-9][\d ]*\))[\d\-/ ]*$/
Die „perfekte“ Telefonnummern-Regex.
Erwischt alle Schreibweisen
+43 911 6348-24(030) 86402357089 43590450 22 56 / 4 35 90 450030-795-463872
Hausaufgabe: so modifizieren, dass man möglichst gleich Ländervorwahl (falls vorhanden), Vorwahl und Rufnummer in \1, \2 und \3 hat.
Ersetzen
Grundform der Syntax, zum Beispiel in PERL: s/dies/das/
Für andere Programme und Sprachen bitte Handbuch/Google konsultieren
Hier machen die Backreferences besonders Sinn. Beispiel: ich habe eine Liste von Namen. („Vorname Nachname“). Möchte ich stattdessen eine telefonbuchartige Liste („Nachname, Vorname“):
s/(\w+)\s(\w+)/\2, \1/g
Massen-Ersetzungen
Praxis-Beispiel: ich habe in einem Verzeichnis 500 Textdateien über Vogue liegen. Konvention für die Schreibweise ist VOGUE in Großbuchstaben und außerdem sind Vertipper wie Vouge oder Voque drin. Wie korrigiere ich alle Texte?
Lösung: PERL auf der Kommandozeile
perl –p –i –e „s/\bvou?g|qu?e\b/VOGUE/ig“ *.txt
(Merkhilfe: „Perl-Kuchen“ – Perl-Pie – Perl –p –i –e)
ZusammenfassungMit regulären Ausdrücken kann jedes beliebige Zeichenmuster in Texten gefunden und extrahiert werden. Bedenke: Websites bzw. deren Quellcode sind nichts anderes als Texte!
RegExes sind daher die Grundlage für jegliches Scraping von Informationen aus einer Webseite
Die Ausdrücke können unter Umständen sehr komplex werden – aber Übung macht den Meister!
Für ein gewünschtes Zeichenmuster gibt es oft nicht nur „die eine“ richtige Lösung, sondern unterschiedliche Wege
Über Google findet man sehr viele erprobte Standard-RegExes, z.B. für Telefonnummern, Email-Adressen, URLs
Wenn Deine RegEx keine Antwort findet, überdenke die Frage!
Buchtipp„Reguläre Ausdrücke“
http://amzn.to/XAoqAg
Tipp: RegExp TesterPlugin / Applikation für Google Chrome
Online RegEx TesterEinfach nach „regex tester“ googeln – es gibt sie wie Sand am Meer. Keiner sticht besonders hervor, keiner ist besonders schlecht.
XPathRoutenplaner für den DOM-Tree
XML Path Language XPath
Abfragesprache, um gezielt Elemente eines XML-Dokuments zu addressieren
Beschreibt bei HTML-Dateien somit den Pfad innerhalb des DOM-Trees, um zu einem bestimmten Tag zu gelangen
Grundlage weiterer Standards wie XSLT oder XQuery
Unterstützt auch Reguläre Ausdrücke
XPath Basics
XPath-Ausdrücke sind wie URLs aufgebautz.B. /html/title für den <title> oder /html/body/h1 für die erste H1-Überschrift
In den meisten Fällen verwendet man aber die Such-Syntax, wobei mit // (= der oberste Knoten) begonnen wirdz.B. //title statt /html/title oder //h1 statt /html/body/h1
Mehrere Elemente auswählenz.B. //* für alle Elemente oder //tr für alle Reihen einer Tabelle
Möchte man ein bestimmtes Element, wird die gewünschte Nummer des Elements in eckigen Klammern angegebenz.B. //h2[2] für die zweite H2-Überschrift
XPath, Attribute und RegExes
Gezielt nach Attributen der Tags suchenz.B. //@class für alle Elemente, die ein „class=...“ besitzen, egal ob das ein div, eine table, ein img oder sonst was ist. Eselsbrücke: @ttribut!
Nur Elemente, dessen Attribute bestimmte Werte habenz.B. //*[@style=‚display:none‘] für alle versteckten Elementez.B. //a[@rel=‚nofollow‘]/@href für alle per nofollow verlinkten URLs
Lesart ist einfacher von hinten: gib mir alle @ttribute namens href von allen Anchor-Tags, dessen @ttribut namens „rel“ den Wert „nofollow“ hat
Nur Elemente, dessen Attributwerte mit einem bestimmten Text beginnenz.B. //div[starts-with(@class, „heading“)] für alle div, deren class mit „heading“ starten, also class=„heading1“, class=„heading2“ etc.
Nur Elemente, die bestimmte Worte im Text besitzenz.B. //h2[re:test(., ‘Kapitel|Abschnitt', 'i')] für alle H2-Überschriften, in denen die Worte „Kapitel“ oder „Abschnitt“ vorkommen. „Kapitel|Abschnitt“ ist dabei der reguläre Ausdruck und kann alles beinhalten, was wir im vorigen Kapitel gelernt haben (ohne die einschließenden Schrägstriche!). Das anschließende „i“ ist der bekannte Modifier „/i“ für Case Insensitivity.
Nicht nur für Dummies: Firebug&Chrome
Firefox: gewünschten Text markieren -> rechte Maustaste -> Element mit Firebug untersuchen -> dort rechte Maustaste auf Auswahl -> XPath kopieren
Chrome: gewünschten Text markieren -> rechte Maustaste -> Element untersuchen -> rechte Maustaste auf Auswahl -> Copy XPath
Aber Vorsicht! Beide verwenden numerierte Angaben, z.B. /html/body/div[3]/div[3]/div[4]/p[21]. Funktioniert über mehrere Seiten hinweg also nur dann, wenn die Struktur wirklich immer gleich ist. Kommt bei einer anderen Seite ein Abschnitt dazu oder fehlt, stimmen diese Nummern nicht mehr!
XPath-ReferenzenBücher sind anders als bei den Regulären Ausdrücken leider immer für Programmierer von XSLT und XQuery Anwendungen ausgelegt. XPath ist da immer nur Nebensache und dementsprechend schlecht dokumentiert.Passable Adressen: http://manual.calibre-ebook.com/xpath.html und http://hbraemer.de/XQuery/tutorial/xpath/index.jsp
Scraping ToolsWie komme ich an den Inhalt von Websites?
Scraping Ehrenkodex
Vermeide DOS-Verhalten!100 Threads gleichzeitig auf einer Website sind ein Denial-Of-Service-Angriff.
Teste oft – scrape einmal!Mach immer 10-15 Stichproben und prüfe, ob wirklich das rauskommt, was Du willst, bevor Du auf eine Website losgehst.
Rechne mit Abbrüchen!Merke Dir abgearbeitete URLs. Bricht das Scraping ab, fang nicht einfach wieder von vorne an.
Scrape. In. Häppchen.Geh bei großen Websites Unterverzeichnis für Unterverzeichnis durch, um Abbrüche zu minimieren.
Tu‘s niemals „ohne“!Wann immer Du automatisiert Websites abfragst, benutze IMMER einen Proxy! Wechsle am besten die Proxies alle X Minuten.
ScrapeboxDer Name ist NICHT Programm!
Hat bezüglich Scraping nur einen einzigen Anwendungszweck: URLs aus den Google-SERPs zu ziehen, macht das aber dafür perfekt
Article Wizard von Pascal LandauScraping ist im Beta-Stadium, aber schon sehr robust und zuverlässig. Anleitung: http://bit.ly/YlweS9Kann neben RegExes auch XPATH.Empfehlenswert bis zu einigen tausend URLs.
UbotEher ein Automatisierungstool, um Aufgaben durchzuführen. Für einfache Scrapes von Tabellen oder ähnlichen Strukturen aber ausreichend.
Eierlegende Wollmilchsau:Outwit Hub ProIch habe noch NIE ein schlechter dokumentiertes Stück Software gesehen!Dennoch mit Abstand mächtigstes Scraping-Werkzeug, das man sich out of the box kaufen kann (50$). Dank voller AJAX-Unterstützung und vieler kleiner Spezialfeatures in dieser Disziplin sogar deutlich mächtiger als Ubot. Verwendet eigene Marker-Logik, kann aber natürlich auch RegExes. Empfehlenswert bis zu einigen tausend URLs.
Für Hardcore-Scrapes: wget
wget --recursive--no-clobber--html-extension--domains vogue.de--no-parentwww.vogue.de/mode/mode-trends/
Speichert den Quelltext aller Seiten entsprechend ihrer URL-Struktur als Datei auf die Festplatte.
Praxistipp: verwende immer die Option „html-extension“, auch wenn die Seiten eigentlich ohne Endung ausgeliefert werden. Sonst wird wget scheitern, wenn es versucht, domain.de/ordner/seite zu schreiben, nachdem es schon domain.de/ordner als datei und nicht als Ordner angelegt hat.
VorteileSehr robust: saugt sogar de.wikipedia.org komplett, wenn der Plattenspeicher reicht
Unattended: kann mit Hilfe von „screen“ auf einer Linux-Kiste laufen und laufen und laufen und laufen
NachteileSeiten werden nur gespeichert. RegEx-Matching muss in einem späteren Schritt (PERL?) erfolgen.
Kann nur statisches HTML, kein AJAX-Gedöns – sieht damit aber auch nur das, was Google sieht
Single Threaded: es wird nur immer eine einzige Anfrage gleichzeitig gestartet, daher langsam
AnwendungsbeispieleWas kann ich alles scrapen und wozu?
Ist alles verpixelt?Google Analytics, IVW, AdSense, AdServer...Bestes Tool hierfür: Custom Filter in Screaming Frog
Sind meine Inhalte vertaggt?Redakteure „vergessen“ gerne mal, Artikel zu vertaggenBestes Tool: je nach Aufbau des Quellcodes entweder Article Wizard oder Outwit Hub Pro
Graphen in Zahlen umwandelnEs nervt, wenn jemand tolle Kurven zeigt, aber die Daten dazu verschweigt.
Wikipedia-DatenSuper Gastartikel dazu von Pascal Landau: http://www.seokai.com/html-scraping-article-spinning-praxisbeispiel/
Wie ranken meine Seitentypen?Tipp: bau in den Quellcode HTML-Kommentare ein, in der Du den Seitentyp, das verwendete Template, die View oder sonstige Kriterien ausgibst. Scrape diese und setze sie über SVERWEISE (siehe Campixx-Vortrag 2012) in Beziehung zu Platzierungen oder Traffic. Rankt irgendein Seitentyp auffallend häufiger oder schlechter? Warum?
wdf*idf en masseScrape doch einfach mal alle wdf*idf-Werte aller Artikel eines Verzeichnisses. Was man damit anstellen kann? Siehe SEOdioten-Vortrag auf der Campixx 2014... ;o)
Letzte WorteA (F)Uhl with a tool......still a fool?