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.
Vous réinventerez la roue, c'est sûr. Mais voici les bases:
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
}
}
}
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.
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: -
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;
}
}
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.
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):
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.
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.
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.
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.
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"));