Extraktion von eMail-Adressen

Oftmals möchte man die auf Webseiten angegebenen eMail-Adressen automatisiert auslesen, z.B. um eine größere Menge Ansprechpartner für einen Linktausch zu finden oder auch einfach nur, um möglichst schnell möglichst viele SPAMbare Adressen zu erhalten. Das lässt sich mit Regulären Ausdrücken einfach realisieren. Dies soll keine Aufforderung zum Spammen sein, es geht hier lediglich um ein Anwendungsbeispiel. SPAM nervt uns sicher genauso stark wie Sie.

Vorüberlegungen

Vorab müssen wir uns überlegen, was wir genau machen wollen. Wir wollen den Inhalt einer URL auslesen und im Text enthaltene eMail-Adressen extrahieren. Die gesuchten Adressen können entweder als Verweis oder als normaler Text auftreten - was hier aber quasi keine Rolle spielt.

Für eMail-Adressen gibt es genau Vorgaben, welche Zeichen in ihnen Verwendung finden dürfen. Ein kurzer Blick in die RFC 2822 sagt uns, dass in dem Teil vor dem @ (dem sogenannten local-part) nur Buchstaben, Ziffern und folgende Sonderzeichen erlaubt sind: .!#$%&'*+-/=?^_`{|}~. Laut Definition dürfen noch weitere Sonderzeichen vorkommen, die entweder in " eingeschlossen oder durch einen Backslash maskiert werden müssen. Der Teil nach dem @ (der sogenannte domain-part) darf nur aus Buchstaben, Ziffern und den Zeichen - und . bestehen.

Ob es sich bei den extrahierten Adressen wirklich um gültige eMail-Adressen handelt, ließe sich auch feststellen - indem man z.B. eine entsprechende Anfrage an den jeweiligen Server stellt - dies soll hier aber nicht das Thema sein.

Ein wenig Realismus

Bei genauerer Betrachtung fallen in oben stehender Definition ein paar Rattenschwänze auf. Viele der im local-part erlaubten Zeichen kommen in 99% aller eMail-Adressen gar nicht vor, im Gegenteil: Würden wir sie als gültige Zeichen betrachten, würden wir unter Umständen mehr falsche Adressen auslesen, als uns verloren gingen, wenn wir diese seltenen Zeichen nicht beachten würden. Auf weitere Ausführungen dieses Aspektes sei hier verzichtet, da diese den Rahmen dieses Artikel sprengen würden. Ähnliche Überlegungen kann man übrigens auch für den domain-part anstellen.

Wir einigen uns also auf folgendes: Wir werden für den local-part neben Buchstaben und Ziffern lediglich die Zeichen -, _ und . (wobei der Punkt weder am Ende noch am Anfang stehen darf) erlauben. Für den domain-part legen wir folgende Konventionen fest: Er besteht aus der Domain, für die oben genannte Regeln gelten, gefolgt von einem . und der TLD, die im Normalfall aus mindestens zwei Buchstaben besteht.

Vorgehensweise

Um überhaupt Adressen extrahieren zu können, müssen wir erst einmal den Inhalt der jeweiligen Webseite auslesen. Dies lässt sich recht einfach mit Hilfe der PHP-Funktion file_get_contents bewerkstelligen. Damit lässt sich der Inhalt einer Datei - oder in unsere Falle - einer URL einlesen. Bitte beachten Sie dazu auch die Hinweise im PHP-Manual, manche Server erlauben das Einlesen von URLs nicht.

Auslesen der URL

Folgender Code liefert uns den gewünschten Inhalt: <?PHP // // URL der Seite, die eingelesen werden soll // $url 'http://nophia.de'; // // Inhalt einlesen // $inhalt file_get_contents($url); ?> Da wir jetzt den Inhalt der Webseite haben, können wir uns überlegen, wie der Reguläre Ausdruck aussehen muss, den wir zur Extraktion der Adressen verwenden wollen. Wir gehen dabei Schritt für Schritt vor.

Aufstellen des grundlegenden Suchmusters

Zuerst stellen wir in groben Zügen unser Suchmuster zusammen. Es besteht vorerst nur aus den Delimitern und dem @ in der Mitte der Adresse: # ... @ ... #i Da in eMail-Adressen durchaus auch Großbuchstaben vorkommen können, setzen wir den Modifier i.

Der vordere Teil

Da wir eindeutig definiert haben, welche Zeichen in eMail-Adressen vorkommen dürfen, fällt es uns sehr leicht, ein passendes Suchmuster aufzustellen. Wir brauchen lediglich eine Zeichenklasse definieren, die die erlaubten Zeichen enthält: #[a-z0-9.\-_]@ ... #i Eventuell in Zeichenklassen gültige Metazeichen (z.B. den Bindestrich) müssen wir maskieren.

Da der Teil vor dem @ quasi beliebig lang sein kann, setzen wir hinter die Zeichenklasse noch den Quantifier +. Um sicherzustellen, dass am Anfang und am Ende des local-part kein Punkt vorkommt, definieren wir jeweils noch eine Zeichenklasse, die alle erlaubten Zeichen enthält, den Punkt aber ausschließt. Diese versehen wir jeweils noch mit dem Quantifier ?, da es sonst bei kurzen Adressen zu Problemen käme.

Unser Ausdruck sieht jetzt also so aus: #[a-z0-9\-_]?[a-z0-9.\-_]+[a-z0-9\-_]?@ ... #i

Der hintere Teil

Für den hinteren Teil können wir ähnlich vorgehen. Wir definieren wiederum eine Zeichenklasse, die die erlaubten Zeichen enthält, gefolgt vom Quantifier +. Dahinter folgt dann, durch einen Punkt verbunden, die Definition für die TLD, so dass der Ausdruck jetzt so aussieht: #[a-z0-9\-_]?[a-z0-9.\-_]+[a-z0-9\-_]?@[a-z.-]+\.[a-z]{2,}#i Der Bindestrich in der ersten Zeichenklasse braucht nicht zusätzlich maskiert sein, da er am Ende der Zeichenklasse steht und somit keinen Zeichenbereich definiert.

Das war es dann quasi schon, unser Regulärer Ausdruck ist damit vollständig, wir können ihn nun auf den ausgelesenen Text anwenden.

Extraktion per PHP

Den entwickelten Regulären Ausdruck können wir jetzt per PHP auf den Text anwenden. Da wir alle eMail-Adressen extrahieren wollen, benutzen wir preg_match_all(): <?PHP // // RegExp auf Inhalt anwenden // $results preg_match_all('#[a-z0-9\-_]?[a-z0-9.\-_]+[a-z0-9\-_]?@[a-z.-]+\.[a-z]{2,}#i'$inhalt$subpattern); ?> Die Rückgabe von preg_match_all() weisen wir einer Variablen zu, um später einen Überblick zu haben, wie viel Adressen extrahiert wurden.

Die gefundenen Adressen liegen jetzt in der Variable $subpattern in folgender Form vor: Array ( [0] => Array ( [0] => Adresse 1 [1] => Adresse 2 [2] => ... ) ) Zur Weiterverwendung wollen wir sie jetzt noch in ein eigenes Array packen. Wir durchlaufen also das erste Element des Rückgabe-Arrays (Index 0) per foreach()-Schleife und fügen die Adressen dann einem neuen Array hinzu. <?PHP // // Neues Array initialisieren // $emails = array(); // // Rückgabe durchlaufen // foreach($subpattern[0] as $email) { $emails[] = $email; } ?> Damit haben wir unser Ziel fast erreicht, wir müssen nur noch vorhandene Duplikate entfernen und die extrahierten eMail-Adressen ausgeben: <?PHP // // Duplikate entfernen // $emails array_unique($emails); // // Ausgabe // echo '<p>Extrahierte Adressen: '.$results.'</p>'; echo '<p>Einzigartige Adressen: '.count($emails).'</p>'; echo '<pre>'.print_r($emailsTRUE).'</pre>'; ?> Viel Spaß beim Spammen.

Anmerkungen

Sowohl die Tatsache, dass die aufgerufene URL nicht erreichbar sein könnte, als auch, dass die Seite keinerlei Adressen beinhalten könnte, wurden hier ignoriert. Die Überprüfung dieser Fehler sei dem Leser überlassen. Sollten Sie einen Fehler gefunden haben oder Vorschläge oder Anregungen haben, können Sie uns das gerne mitteilen.

Vollständiger Quellcode

Hier fnden Sie den vollständigen Quellcode für dieses Beispiel: <?PHP // // URL der Seite, die eingelesen werden soll // $url 'http://nophia.de'; // // Inhalt einlesen // $inhalt file_get_contents($url); // // RegExp auf Inhalt anwenden // $results preg_match_all('#[a-z0-9\-_]?[a-z0-9.\-_]+[a-z0-9\-_]?@[a-z.-]+\.[a-z]{2,}#i'$inhalt$subpattern); // // Neues Array initialisieren // $emails = array(); // // Rückgabe durchlaufen // foreach($subpattern[0] as $email) { $emails[] = $email; } // // Duplikate entfernen // $emails array_unique($emails); // // Ausgabe // echo '<p>Extrahierte Adressen: '.$results.'</p>'; echo '<p>Einzigartige Adressen: '.count($emails).'</p>'; echo '<pre>'.print_r($emailsTRUE).'</pre>'; ?>
Sie können den Quellcode auch als Datei herunterladen. Um die Datei verwenden zu können, müssen sie die Dateiendung .txt entfernen - sie wurde hier lediglich angehängt, um einen Download zu ermöglichen.

Verwandte Themen
Kapitelnavigation