Ein Crawler ist im Grunde sehr simpel und schnell programmiert. Wir senden eine Anfrage für eine bestimmte URL an einen Server und warten auf die Antwort. Die Antwort speicher wir ab und fertig ist der erste Request. Jetzt extrahieren wir nur noch die Links aus der Seite, senden neue Requests und fertig ist der Crawler.

Der Teufel steckt jedoch im Detail und eines dieser Details ist das verantwortungsvolle und höfliche Crawling (crawling politely). Es gibt einige Verhaltensregeln im Internet, an die sich ein Crawler halten sollte. Diese wollen wir in diesem Artikel näher beleuchten und ein Scrapy-Projekt entsprechend einrichten.

Weise deinen Crawler korrekt aus

Wenn Programme Anfragen an einen Web-Server senden, schicken sie dabei in der Regel eine Kennung über sich selbst mit. Bei Endanwender-Programmen wie Browsern dient dies teilweise dazu, dem Server mitzuteilen, welches Programm der Nutzer verwendet und welche Funktionen dieses hat. So kann der Server verschiedene Antworten je nach Funktionsumfang des Browsers schicken. Dieser Wert wird im sogenannten User-Agent gesendet.

Crawler hingegen sollten sich als Bot kenntlich machen, indem sie einen eigenen User-Agent verwenden. Dieser sollte den Namen des Crawlers sowie einen URL für weitere Informationen beinhalten. Auf dieser Seite sollten das Projekt und der Crawler kurz beschrieben sein, sowie eine Kontaktmöglichkeit für Probleme genannt werden. Somit können Website-Betreiber euch Hinweise zu Problemen mit dem Crawler schicken, bevor sie euch blockieren.

Für den Namen des Crawlers gibt es keine besonderen Richtlinien. Teilweise wird die Konvention genannt, dass Bot im Namen enthalten sein sollte, allerdings weist bereits Yahoo seinen Crawler als “Yahoo! Slurp” aus.

Viele Suchmaschinenbetreiber inkludieren in ihrem User-Agent auch die Keywords Mozilla/<version> und compatible. Dies weist darauf hin, dass dieser User-Agent kompatibel zur ehemaligen Mozilla-Engine ist. Das hat historische Gründe und wird von den Suchmaschinen angeliefert, weil manche Websites ihren Inhalt andernfalls nicht ausliefern. Wer auf solche Websites verzichten kann, kann das Stichwort Mozilla weglassen.

Der User-Agent sollte also idealerweise einer der folgenden beiden Konventionen folgen:

Mozilla/5.0 (compatible; Examplebot/1.0; +http://example.org/examplebot.html)
Examplebot/1.0 (+http://example.org/examplebot.html)

Damit können Website-Betreiber dich in ihren Logs identifizieren und auf der Website dein Zweck deines Bots nachlesen oder dich auf mögliche Probleme hinweisen.

Überlaste die Websites nicht

Ein Programm kann viele Anfragen gleichzeitig schicken, viel mehr als ein Mensch. Selbst von einer Standard-DSL-Internetanbindung können problemlos mehrere Anfragen pro Sekunde versendet werden, wenn man mit Threading arbeitet. Mit einer Gigabit-Server-Anbindung entsprechend mehr. Wenn man hier nicht aufpasst, kann man einen kleineren Web-Server schnell überlasten und dies wird keinen Seitenbetreiber erfreuen.

Deshalb sollten wir die Anzahl an Anfragen an dieselbe Domain pro Zeit limitieren. Üblicherweise wird dabei ein Faktor auf die Antwortzeit des Servers aufgerechnet. Das heißt, wenn der Server innerhalb von 0,9 Sekunden antwortet und wir einen Verzögerungsfaktor von 3 etabliert haben, dürfte die nächste Anfrage für dieselbe Domain erst nach 2,7 Sekunden stattfinden. Als neuer, unbekannter Crawler sollte man den Faktor lieber höher als niedriger wählen, da die Hemmschwelle für eine Blockade bei Seitenbetreibern hier sehr viel niedriger ist als z.B. beim Googlebot. Auch Faktoren von 30 sind üblich.

Anstatt auf Domain-Ebene kann man diese Verzögerung natürlich auch auf IP-Ebene etablieren. Dazu muss man allerdings zunächst die Domains auf IPs auflösen.

Theoretisch ist es auch möglich, dass der Betreiber einer Website selbst ein Crawl-Delay bestimmt. Hierfür kann er die Direktive Crawl-Delay in seine robots.txt eintragen. Dies wird allerdings eher selten verwendet. Wenn diese Direktive vorhanden ist, kann man ihr natürlich folgen. Viel wichtiger ist jedoch, dass der Crawler von sich aus die Geschwindigkeit reduziert.

Beachte die robots.txt

Die Datei robots.txt wurde bereits angesprochen. robots.txt ist eine Datei, die direkt unter /robots.txt liegen muss (also z.B. http://example.com/robots.txt) und in welcher der Betreiber einer Website angibt, welche Seiten von maschinellen Besuchern nicht aufgerufen werden sollen. Mit der Direktive User-agent kann dies auch auf einzelne Bots eingeschränkt werden. Eine robots.txt, die jeden Zugriff erlaubt, sieht so aus:

User-agent: *
Disallow:

Disallow ist leer und damit ist nichts verboten. Umgekehrt verbietet folgende Einstellung den Besuch jeglicher Seiten für alle Crawler:

User-agent: *
Disallow: /

Wikipedia hat eine sehr detailliert ausgearbeitete robots.txt mit Regeln für verschiedene Crawler. Dies ist ein Ausschnitt:

# advertising-related bots:
User-agent: Mediapartners-Google*
Disallow: /

# Wikipedia work bots:
User-agent: IsraBot
Disallow:

# Crawlers that are kind enough to obey, but which we'd rather not have
# unless they're feeding search engines.
User-agent: UbiCrawler
Disallow: /

User-agent: DOC
Disallow: /

# Some bots are known to be trouble, particularly those designed to copy
# entire sites. Please obey robots.txt.
User-agent: sitecheck.internetseer.com
Disallow: /

User-agent: Zealbot
Disallow: /

#
# Sorry, wget in its recursive mode is a frequent problem.
# Please read the man page and use it properly; there is a
# --wait option you can use to set the delay between hits,
# for instance.
#
User-agent: wget
Disallow: /

#
# Hits many times per second, not acceptable
# http://www.nameprotect.com/botinfo.html
User-agent: NPBot
Disallow: /

User-agent: *
Allow: /w/api.php?action=mobileview&
Allow: /w/load.php?
Allow: /api/rest_v1/?doc
Disallow: /w/
Disallow: /api/
Disallow: /trap/

Wir wir hier sehen können, gibt es verschiedene Gründe Crawler von einer Seite auszuschließen. Zunächt werden “advertising-related bots” ausgeschlossen. Wikipedia-eigene Bots erhalten hingegen Zugriff auf alle Seiten. Anschließend folgen klare Begründungen, warum bestimmte Bots ausgeschlossen werden. UbiCrawler und DOC werden nicht aus impoliteness ausgeschlossen, sondern weil Wikipedia ihre Ziele nicht unterstützt. sitecheck.internetseer.com und Zealbot hingegen werden ganz klar ausgeschlossen, weil sie die Datei robots.txt ignoriert haben. wget wiederum wird laut Kommentar nicht kategorisch ausgeschlossen, allerdings sollen es nur Leute benutzen, die entsprechende Erfahrung haben, die Parameter richtig zu setzen. NPBot wurde ausgeschlossen, weil er viele Anfragen pro Sekunde schickt.

Erst danach folgt der generelle Block an Befugnissen und Verboten für alle übrigen Crawler.

Neben User-agent und Disallow gibt es noch weitere Direktiven, die allerdings nicht mehr so wichtig sind und auch nicht von allen Crawlern unterstützt werden. Dies wären:

  • Allow: Um Unterseiten von verbotenen Teilbereichen doch wieder zu erlauben
  • Crawl-delay: Angabe des Website, wie lange zwischen einzelnen Anfragen gewartet werden soll (selten genutzt)
  • Sitemap: Verweis auf eine Sitemap-Datei

Befolge die noindex- und nofollow-Direktiven

Neben der robots.txt-Datei können Websites auch direkt im HTML-Code Anweisungen an Crawler geben, welchen Links gefolgt und welche Seiten indiziert werden sollen. nofollow und noindex werden in das meta-Tag mit dem Namen robots geschrieben und weisen den Crawler an, keinen Links von dieser Seite aus zu folgen bzw. diese Seite nicht zu indizieren. Umgekehrt gibt es auch follow und index. Der Standard ist index, follow, möglich sind also diese weiteren Kombinationen:

<meta name="robots" content="noindex, nofollow"/>
<meta name="robots" content="index, nofollow"/>
<meta name="robots" content="noindex, follow"/>

Der Crawler sollte außerdem flexibel genug sein, um auch eine Einstellung allein zu verarbeiten und die fehlende dann als index bzw. follow anzunehmen.

<meta name="robots" content="nofollow"/>
<meta name="robots" content="noindex"/>

nofollow erstreckt sich dabei logischerweise nur auf Links von dieser Seite, wenn andere Seiten dieselben Links beinhalten (aber keine nofollow-Anweisung), dann darf unser Crawler diesen Links folgen.

nofollow kann auch in das rel-Attribut von Links geschrieben werden. Für diesen Fall ist das Verhalten des Crawlers jedoch offener. Eingeführt wurde dieses Attribut mit dem Aufkommen von Blogs und Kommentaren unter Blog-Artikeln. Um Blog-Spam zu verhindern, wurde rel="nofollow" eingeführt. Diese Links fanden anschließend keinen Einfluss mehr in das Ranking der Suchergebnisse. In diesem Fall darf man dem Link allerdings weiterhin folgen.

<a href="http://example.com/spammy-site" rel="nofollow">Link</a>

Umsetzung mit Scrapy

Schauen wir uns nun noch die Umsetzung dieser Punkte für Scrapy an. Die Datei robots.txt zu befolgen ist in neueren Versionen von Scrapy bereits Standard und wird mit der Einstellung ROBOTSTXT_OBEY gesetzt:

ROBOTSTXT_OBEY = True

Den User-Agent des Crawlers stellt man mit USER_AGENT ein:

USER_AGENT = 'Examplebot (+http://example.com/examplebot.html)'

Überlastung von Webseiten kann man mit Scrapy ebenfalls einfach verhindern, indem man DOWNLOAD_DELAY setzt. Dieses gibt den Wert in Sekunden an, der zwischen erneuten Zugriffen gewartet werden soll. Weil Scrapy aus dem Web-Scraping stammt und damit verhindern will, dass es als Robot erkannt wird, ist dieser Wert allerdings randomisiert mit Faktor 0,5 bis 1,5.

# wait between 2.5 and 7.5 seconds (0.5 * 5 and 1.5 * 5)
DOWNLOAD_DELAY = 5 

Will man die Randomisierung deaktivieren, muss man RANDOMIZE_DOWNLOAD_DELAY = False setzen.

In neueren Versionen unterstützt Scrapy auch ein Download-Delay basierend auf der Antwortdauer des Servers (wie zuvor beschrieben). Hierbei wird DOWNLOAD_DELAY immer noch als Minimum verwendet, d.h. Requests können nicht häufiger werden als von DOWNLOAD_DELAY definiert.

DOWNLOAD_DELAY = 5
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 5
AUTOTHROTTLE_MAX_DELAY = 60
AUTOTHROTTLE_TARGET_CONCURRENCY = 0.25

Der Faktor AUTOTHROTTLE_TARGET_CONCURRENCY bei Scrapy ist jedoch invers zu unserer vorherigen Definition. Scrapy arbeitet mit einem Concurrency-Faktor, d.h. wenn wir bei Scrapy AUTOTHROTTLE_TARGET_CONCURRENCY als 0,25 definieren, bedeutet dies einen Verzögerungsfaktor von 4.

Für die noindex- und nofollow-Einstellungen im HTML-Code gibt es keine direkten Optionen in Scrapy, diese müssen wir in unserer eigenen Verarbeitungslogik befolgen.

Somit haben wir mit wenigen Einstellungen aus Scrapy einen verantwortungsvollen und höflichen Webcrawler gemacht.

I do not maintain a comments section. If you have any questions or comments regarding my posts, please do not hesitate to send me an e-mail to blog@stefan-koch.name.