web-dev-qa-db-fra.com

Comment écrire un robot?

J'ai pensé à écrire un simple robot qui pourrait explorer et produire une liste de ses résultats pour les sites Web et le contenu de notre OBNL.

Quelqu'un at-il des réflexions sur la façon de procéder? Où pointez-vous le robot pour commencer? Comment renvoie-t-il ses résultats et continue-t-il à ramper? Comment sait-il ce qu'il trouve, etc, etc.

61
Jason

Vous réinventerez la roue, c'est sûr. Mais voici les bases:

  • Une liste d'URL non consultées - ajoutez-y une ou plusieurs pages de départ
  • Une liste des URL visitées - pour ne pas tourner en rond
  • Un ensemble de règles pour les URL qui ne vous intéressent pas - donc vous n'indexez pas tout Internet

Mettez-les dans un stockage persistant, afin de pouvoir arrêter et démarrer le robot sans perdre son état.

L'algorithme est:

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

La partie compliquée d'un robot est que vous souhaitez l'adapter à un grand nombre de sites Web/demandes. Dans cette situation, vous devrez faire face à certains problèmes tels que:

  • Impossibilité de conserver toutes les informations dans une seule base de données.

  • Pas assez RAM pour faire face aux énormes index)

  • Performances multithread et simultanéité

  • Pièges du robot (boucle infinie créée en changeant les URL, les calendriers, les identifiants de session ...) et le contenu dupliqué.

  • Explorer à partir de plusieurs ordinateurs

  • Codes HTML mal formés

  • Erreurs HTTP constantes des serveurs

  • Bases de données sans compression, ce qui augmente votre besoin d'espace d'environ 8 fois.

  • Réexploitez les routines et les priorités.

  • Utilisez les requêtes avec compression (Deflate/gzip) (bon pour tout type de robot).

Et certaines choses importantes

  • Respectez robots.txt

  • Et un délai pour chaque robot pour ne pas étouffer les serveurs Web.

29
lexmooze

Crawler Web multithread

Si vous souhaitez explorer un site Web de grande taille, vous devez écrire un robot à plusieurs threads. se connecter, récupérer et écrire des informations analysées dans des fichiers/base de données - ce sont les trois étapes de l'exploration, mais si vous utilisez un seul thread, votre CPU et l'utilisation du réseau seront versées.

Un robot d'indexation multithread a besoin de deux structures de données: linksVisited (cela doit être implémenté sous forme de hashmap ou trai) et linksToBeVisited (c'est une file d'attente).

Le robot d'indexation Web utilise BFS pour parcourir le World Wide Web.

Algorithme d'un robot d'exploration de base: -

  1. Ajoutez une ou plusieurs URL de départ à linksToBeVisited. La méthode pour ajouter une URL à linksToBeVisited doit être synchronisée.
  2. Pop un élément de linksToBeVisited et ajoutez-le à linksVisited. Cette méthode pop pour extraire l'url de linksToBeVisited doit être synchronisée.
  3. Récupérez la page sur Internet.
  4. Analyser le fichier et ajouter tout lien jusqu'à présent non visité trouvé dans la page à linksToBeVisited. Les URL peuvent être filtrées si nécessaire. L'utilisateur peut donner un ensemble de règles pour filtrer les URL à analyser.
  5. Les informations nécessaires trouvées sur la page sont enregistrées dans une base de données ou un fichier.
  6. répétez les étapes 2 à 5 jusqu'à ce que la file d'attente soit linkToBeVisited vide.

    Voici un extrait de code sur la façon de synchroniser les 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

Les robots sont de conception simple.

Vous obtenez une page racine via un HTTP GET, analysez-la pour trouver des URL et mettez-les dans une file d'attente à moins qu'elles n'aient déjà été analysées (vous avez donc besoin d'un enregistrement global des pages que vous avez déjà analysées).

Vous pouvez utiliser l'en-tête Content-type pour connaître le type de contenu et limiter votre robot d'exploration à l'analyse syntaxique des types HTML uniquement.

Vous pouvez supprimer les balises HTML pour obtenir le texte brut, sur lequel vous pouvez effectuer une analyse de texte (pour obtenir des balises, etc., la viande de la page). Vous pouvez même le faire sur les balises alt/title pour les images si vous avez avancé.

Et en arrière-plan, vous pouvez avoir un pool de threads mangeant les URL de la file d'attente et faisant de même. Vous voulez bien sûr limiter le nombre de threads.

5
JeeBee

Si les sites de votre OBNL sont relativement grands ou complexes (ayant des pages dynamiques qui créeront effectivement un `` trou noir '' comme un calendrier avec un lien `` le lendemain ''), vous feriez mieux d'utiliser un véritable robot d'exploration Web, comme Héritrix.

Si les sites totalisent un certain nombre de pages, vous pouvez vous en sortir en utilisant simplement curl ou wget ou le vôtre. N'oubliez pas s'ils commencent à devenir gros ou si vous commencez à rendre votre script plus complexe pour simplement utiliser un vrai robot ou au moins regardez sa source pour voir ce qu'ils font et pourquoi.

Quelques problèmes (il y en a plus):

  • Trous noirs (comme décrit)
  • Nouvelle tentative (et si vous obtenez un 500?)
  • Redirige
  • Contrôle de flux (sinon vous pouvez être un fardeau sur les sites)
  • implémentation de robots.txt
5
Vinko Vrsalovic

Wikipedia a un bon article sur robots d'exploration Web , couvrant de nombreux algorithmes et considérations.

Cependant, je ne prendrais pas la peine d'écrire mon propre robot. C'est beaucoup de travail, et comme vous n'avez besoin que d'un "simple robot", je pense que tout ce dont vous avez vraiment besoin est un robot standard . Il existe de nombreux robots d'exploration gratuits et open-source qui feront probablement tout ce dont vous avez besoin, avec très peu de travail de votre part.

4
Derek Park

Vous pouvez faire une liste de mots et créer un fil de discussion pour chaque mot recherché sur google.
Ensuite, chaque fil crée un nouveau fil pour chaque lien qu'il trouve dans la page.
Chaque thread doit écrire ce qu'il trouve dans une base de données. Lorsque chaque thread a fini de lire la page, il se termine.
Et là, vous avez une très grande base de données de liens dans votre base de données.

2
Gero

J'utilise le serveur de recherche ouvert pour la recherche interne de mon entreprise, essayez ceci: http://open-search-server.com c'est aussi ouvert soruce.

1
Sathishkumar

Utilisez wget, effectuez une succion Web récursive, qui videra tous les fichiers sur votre disque dur, puis écrivez un autre script pour parcourir tous les fichiers téléchargés et les analyser.

Edit: ou peut-être curl au lieu de wget, mais je ne suis pas familier avec curl, je ne sais pas s'il fait des téléchargements récursifs comme wget.

0
whatsisname

j'ai fait un simple robot d'indexation en utilisant une extension réactive dans .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);
    }
}

et vous pouvez l'utiliser comme suit:

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