it-swarm.com.de

Wie schreibe ich einen Crawler?

Ich habe überlegt, einen einfachen Crawler zu schreiben, der crawlen und eine Liste seiner Ergebnisse für die Websites und Inhalte unserer NPO erstellen könnte.

Hat jemand irgendwelche Gedanken darüber, wie man das macht? Wohin zeigen Sie den Crawler, um loszulegen? Wie sendet es seine Ergebnisse zurück und kriecht immer noch? Woher weiß es, was es findet usw.

61
Jason

Sie werden das Rad sicherlich neu erfinden. Aber hier sind die Grundlagen:

  • Eine Liste nicht besuchter URLs - versehen Sie diese mit einer oder mehreren Startseiten
  • Eine Liste der besuchten URLs - damit Sie nicht im Kreis herumlaufen
  • Eine Reihe von Regeln für URLs, an denen Sie nicht interessiert sind - Sie indizieren also nicht das gesamte Internet

Speichern Sie diese in einem permanenten Speicher, damit Sie den Crawler stoppen und starten können, ohne den Status zu verlieren.

Algorithmus ist:

while(list of unvisited URLs is not empty) {
    take URL from list
    remove it from the unvisited list and add it to the visited list
    fetch content
    record whatever it is you want to about the content
    if content is HTML {
        parse out URLs from links
        foreach URL {
           if it matches your rules
              and it's not already in either the visited or unvisited list
              add it to the unvisited list
        }
    }
}
146
slim

Der komplizierte Teil eines Crawlers ist, wenn Sie ihn auf eine große Anzahl von Websites/Anforderungen skalieren möchten. In dieser Situation müssen Sie sich mit folgenden Problemen befassen:

  • Unmöglichkeit, alle Informationen in einer Datenbank zu speichern.

  • Nicht genug RAM für große Indizes)

  • Multithread-Leistung und Parallelität

  • Crawler-Traps (Endlosschleife, die durch Ändern von URLs, Kalendern, Sitzungs-IDs usw. erstellt wird) und duplizierter Inhalt.

  • Crawl von mehr als einem Computer

  • Fehlerhafte HTML-Codes

  • Konstante http-Fehler von Servern

  • Datenbanken ohne Komprimierung, die Ihren Platzbedarf um das 8-fache erhöhen.

  • Routinen und Prioritäten neu durchforsten.

  • Verwenden Sie Anforderungen mit Komprimierung (Deflate/gzip) (für alle Arten von Crawlern geeignet).

nd einige wichtige Dinge

  • Respektieren Sie robots.txt

  • Und eine Crawler-Verzögerung bei jeder Anforderung, Webserver nicht zu ersticken.

29
lexmooze

Multithread-Webcrawler

Wenn Sie eine große Website crawlen möchten, sollten Sie einen Multithread-Crawler schreiben. Verbinden, Abrufen und Schreiben von durchforsteten Informationen in Dateien/Datenbanken - dies sind die drei Durchforstungsschritte. Wenn Sie jedoch einen einzelnen Thread verwenden, wird die CPU- und Netzwerkauslastung erhöht.

Ein Multithread-Webcrawler benötigt zwei Datenstrukturen: linksVisited (dies sollte als Hashmap oder Trai implementiert werden) und linksToBeVisited (dies ist eine Warteschlange).

Der Webcrawler verwendet BFS, um das World Wide Web zu durchlaufen.

Algorithmus eines grundlegenden Webcrawlers: -

  1. Fügen Sie linksToBeVisited eine oder mehrere Start-URLs hinzu. Die Methode zum Hinzufügen einer URL zu linksToBeVisited muss synchronisiert werden.
  2. Pop ein Element aus linksToBeVisited und fügen Sie dies linksVisited hinzu. Diese pop-Methode zum Aufrufen der URL von linksToBeVisited muss synchronisiert werden.
  3. Holen Sie sich die Seite aus dem Internet.
  4. Analysieren Sie die Datei und fügen Sie einen noch nicht besuchten Link auf der Seite zu linksToBeVisited hinzu. URLs können bei Bedarf gefiltert werden. Der Benutzer kann eine Reihe von Regeln festlegen, um zu filtern, welche URL gescannt werden soll.
  5. Die auf der Seite gefundenen erforderlichen Informationen werden in einer Datenbank oder Datei gespeichert.
  6. wiederholen Sie die Schritte 2 bis 5, bis die Warteschlange linksToBeVisited leer ist.

    Hier ist ein Code-Snippet zum Synchronisieren der Threads ....

     public void add(String site) {
       synchronized (this) {
       if (!linksVisited.contains(site)) {
         linksToBeVisited.add(site);
         }
       }
     }
    
     public String next() {
        if (linksToBeVisited.size() == 0) {
        return null;
        }
           synchronized (this) {
            // Need to check again if size has changed
           if (linksToBeVisited.size() > 0) {
              String s = linksToBeVisited.get(0);
              linksToBeVisited.remove(0);
              linksVisited.add(s);
              return s;
           }
         return null;
         }
      }
    
8
alienCoder

Crawler haben ein einfaches Konzept.

Sie erhalten eine Root-Seite über ein HTTP-GET, analysieren sie, um URLs zu finden, und stellen sie in eine Warteschlange, es sei denn, sie wurden bereits analysiert (Sie benötigen also einen globalen Datensatz von Seiten, die Sie bereits analysiert haben).

Sie können den Inhaltstyp-Header verwenden, um den Inhaltstyp zu ermitteln, und Ihren Crawler darauf beschränken, nur die HTML-Typen zu analysieren.

Sie können die HTML-Tags entfernen, um den einfachen Text zu erhalten, mit dem Sie eine Textanalyse durchführen können (um Tags usw., das Fleisch der Seite, zu erhalten). Sie könnten das sogar für die Alt/Title-Tags für Bilder tun, wenn Sie so weit fortgeschritten wären.

Und im Hintergrund können Sie einen Pool von Threads haben, die URLs aus der Warteschlange essen und dasselbe tun. Sie möchten die Anzahl der Threads natürlich begrenzen.

5
JeeBee

Wenn die Websites Ihres NPO relativ groß oder komplex sind (mit dynamischen Seiten, die effektiv ein „Schwarzes Loch“ wie einen Kalender mit einem Link für den nächsten Tag erzeugen), ist es besser, einen echten Webcrawler zu verwenden, z. B. Heritrix.

Wenn die Seiten ein paar Seiten umfassen, können Sie einfach mit Locken, Wolle oder Ihren eigenen davonkommen. Denken Sie daran, wenn sie zu groß werden oder wenn Sie Ihr Skript komplexer machen, um nur einen echten Crawler zu verwenden, oder schauen Sie sich zumindest die Quelle an, um zu sehen, was sie tun und warum.

Einige Probleme (es gibt mehr):

  • Schwarze Löcher (wie beschrieben)
  • Wiederholungen (Was ist, wenn Sie eine 500 bekommen?)
  • Weiterleitungen
  • Flusskontrolle (sonst können Sie die Websites belasten)
  • robots.txt-Implementierung
5
Vinko Vrsalovic

Wikipedia hat einen guten Artikel über Webcrawler , der viele der Algorithmen und Überlegungen abdeckt.

Ich würde mir jedoch nicht die Mühe machen, meinen eigenen Crawler zu schreiben. Es ist eine Menge Arbeit, und da Sie nur einen "einfachen Crawler" benötigen, denke ich, dass alles, was Sie wirklich brauchen, ein handelsüblicher Crawler ist. Es gibt eine Menge kostenloser und Open-Source-Crawler, die wahrscheinlich alles tun, was Sie brauchen, und dabei nur sehr wenig Arbeit leisten.

4
Derek Park

Sie können eine Liste von Wörtern erstellen und einen Thread für jedes bei Google gesuchte Wort erstellen.
Dann erstellt jeder Thread einen neuen Thread für jeden Link, den er auf der Seite findet.
Jeder Thread sollte schreiben, was er in einer Datenbank findet. Wenn jeder Thread das Lesen der Seite beendet hat, wird er beendet.
Und dort haben Sie eine sehr große Datenbank von Links in Ihrer Datenbank.

2
Gero

Ich verwende Open Search Server für die unternehmensinterne Suche. Versuchen Sie Folgendes: http://open-search-server.com Es ist auch Open Search Server.

1
Sathishkumar

Verwenden Sie wget, führen Sie einen rekursiven Web-Suck durch, der alle Dateien auf Ihrer Festplatte ablegt, und schreiben Sie dann ein weiteres Skript, um alle heruntergeladenen Dateien zu durchsuchen und zu analysieren.

Bearbeiten: oder vielleicht locken statt wget, aber ich bin nicht vertraut mit locken, ich weiß nicht, ob es rekursive Downloads wie wget macht.

0
whatsisname

ich habe einen einfachen Web-Crawler mit reaktiver Erweiterung in .net.

https://github.com/Misterhex/WebCrawler

public class Crawler
    {
    class ReceivingCrawledUri : ObservableBase<Uri>
    {
        public int _numberOfLinksLeft = 0;

        private ReplaySubject<Uri> _subject = new ReplaySubject<Uri>();
        private Uri _rootUri;
        private IEnumerable<IUriFilter> _filters;

        public ReceivingCrawledUri(Uri uri)
            : this(uri, Enumerable.Empty<IUriFilter>().ToArray())
        { }

        public ReceivingCrawledUri(Uri uri, params IUriFilter[] filters)
        {
            _filters = filters;

            CrawlAsync(uri).Start();
        }

        protected override IDisposable SubscribeCore(IObserver<Uri> observer)
        {
            return _subject.Subscribe(observer);
        }

        private async Task CrawlAsync(Uri uri)
        {
            using (HttpClient client = new HttpClient() { Timeout = TimeSpan.FromMinutes(1) })
            {
                IEnumerable<Uri> result = new List<Uri>();

                try
                {
                    string html = await client.GetStringAsync(uri);
                    result = CQ.Create(html)["a"].Select(i => i.Attributes["href"]).SafeSelect(i => new Uri(i));
                    result = Filter(result, _filters.ToArray());

                    result.ToList().ForEach(async i =>
                    {
                        Interlocked.Increment(ref _numberOfLinksLeft);
                        _subject.OnNext(i);
                        await CrawlAsync(i);
                    });
                }
                catch
                { }

                if (Interlocked.Decrement(ref _numberOfLinksLeft) == 0)
                    _subject.OnCompleted();
            }
        }

        private static List<Uri> Filter(IEnumerable<Uri> uris, params IUriFilter[] filters)
        {
            var filtered = uris.ToList();
            foreach (var filter in filters.ToList())
            {
                filtered = filter.Filter(filtered);
            }
            return filtered;
        }
    }

    public IObservable<Uri> Crawl(Uri uri)
    {
        return new ReceivingCrawledUri(uri, new ExcludeRootUriFilter(uri), new ExternalUriFilter(uri), new AlreadyVisitedUriFilter());
    }

    public IObservable<Uri> Crawl(Uri uri, params IUriFilter[] filters)
    {
        return new ReceivingCrawledUri(uri, filters);
    }
}

und Sie können es wie folgt verwenden:

Crawler crawler = new Crawler();
IObservable observable = crawler.Crawl(new Uri("http://www.codinghorror.com/"));
observable.Subscribe(onNext: Console.WriteLine, 
onCompleted: () => Console.WriteLine("Crawling completed"));
0
Misterhex