64

NPO の Web サイトやコンテンツをクロールしてその結果のリストを作成する単純なクローラーを作成しようと考えました。

これを行う方法について誰か考えがありますか?クローラーを開始するためにどこに向けますか? 調査結果を送り返し、クロールを続けるにはどうすればよいでしょうか? 見つけたものをどのように知るかなど。

4

10 に答える 10

150

確かに、車輪を再発明することになります。しかし、ここに基本があります:

  • 未訪問の URL のリスト - 1 つ以上の開始ページでこれをシードします
  • 訪問した URL のリスト - ぐるぐる回らないように
  • 興味のない URL の一連のルール - インターネット全体をインデックスに登録する必要はありません

これらを永続ストレージに配置して、状態を失うことなくクローラーを停止および開始できるようにします。

アルゴリズムは次のとおりです。

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
        }
    }
}
于 2008-09-19T15:25:22.133 に答える
30

クローラーの複雑な部分は、クローラーを膨大な数のWebサイト/リクエストに拡張する場合です。この状況では、次のようないくつかの問題に対処する必要があります。

  • すべての情報を1つのデータベースに保持することは不可能です。

  • 巨大なインデックスを処理するのに十分なRAMがありません

  • マルチスレッドのパフォーマンスと並行性

  • クローラートラップ(URL、カレンダー、セッションIDを変更することによって作成される無限ループ...)および複製されたコンテンツ。

  • 複数のコンピューターからクロールする

  • 不正な形式のHTMLコード

  • サーバーからの一定のhttpエラー

  • 圧縮されていないデータベースでは、必要なスペースが約8倍大きくなります。

  • ルーチンと優先順位を再クロールします。

  • 圧縮(Deflate / gzip)でリクエストを使用します(あらゆる種類のクローラーに適しています)。

そしていくつかの重要なこと

  • robots.txtを尊重する

  • また、Webサーバーを窒息させないように要求するたびにクローラーが遅延します。

于 2011-12-19T13:45:21.893 に答える
8

マルチスレッド Web クローラー

大規模な Web サイトをクロールする場合は、マルチスレッド クローラーを作成する必要があります。クロールされた情報をファイル/データベースに接続、取得、書き込み - これらはクロールの 3 つのステップですが、シングル スレッドを使用すると CPU とネットワークの使用率が高くなります。

マルチスレッド Web クローラーには、2 つのデータ構造が必要です。

Web クローラーは、BFS を使用してワールド ワイド Web をトラバースします。

基本的な Web クローラーのアルゴリズム:-

  1. linksToBeVisited に 1 つ以上のシード URL を追加します。linksToBeVisited に URL を追加するメソッドは同期する必要があります。
  2. linksToBeVisited から要素をポップし、これを linksVisited に追加します。linksToBeVisited から URL をポップするこの pop メソッドは、同期する必要があります。
  3. インターネットからページを取得します。
  4. ファイルを解析し、ページ内で見つかったまだアクセスしていないリンクを linksToBeVisited に追加します。必要に応じて URL をフィルタリングできます。ユーザーは、スキャンする URL をフィルタリングする一連のルールを指定できます。
  5. ページで見つかった必要な情報は、データベースまたはファイルに保存されます。
  6. キューが linksToBeVisited が空になるまで、ステップ 2 から 5 を繰り返します。

    スレッドを同期する方法のコード スニペットを次に示します。

     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;
         }
      }
    

于 2012-12-12T15:40:05.093 に答える
5

クローラーの概念は単純です。

HTTP GET 経由でルート ページを取得し、それを解析して URL を見つけ、まだ解析されていない限り、それらをキューに入れます (そのため、既に解析したページのグローバル レコードが必要です)。

Content-type ヘッダーを使用して、コンテンツのタイプを確認し、クローラーを HTML タイプのみの解析に制限できます。

HTMLタグを取り除いてプレーンテキストを取得し、テキスト分析を実行できます(タグなどを取得して、ページの肉を取得します)。高度な知識があれば、画像の alt/title タグでそれを行うこともできます。

バックグラウンドでは、キューから URL を食べて同じことを行うスレッドのプールを持つことができます。もちろん、スレッドの数を制限したい。

于 2008-09-19T15:19:01.743 に答える
5

NPO のサイトが比較的大きいか複雑である場合 (「翌日」リンクのあるカレンダーのような「ブラック ホール」を効果的に作成する動的ページがある場合)、Heritrix などの実際の Web クローラーを使用することをお勧めします。

サイトの合計ページ数が少ない場合は、curl、wget、または独自のものを使用するだけで済みます。それらが大きくなり始めたり、実際のクローラーを使用するためにスクリプトをより複雑にしたりし始めたり、少なくともそのソースを見て、それらが何をしているのか、そしてその理由を確認してください.

いくつかの問題 (他にもあります):

  • ブラックホール(説明どおり)
  • 再試行 (500 を取得した場合はどうなりますか?)
  • リダイレクト
  • フロー制御 (そうしないと、サイトの負担になる可能性があります)
  • robots.txt の実装
于 2008-09-19T15:19:44.097 に答える
4

ウィキペディアにはWeb クローラーに関する優れた記事があり、アルゴリズムと考慮事項の多くをカバーしています。

ただし、わざわざ独自のクローラーを作成するつもりはありません。たいへんな作業ですし、必要なのは「単純なクローラー」だけなので、本当に必要なのは既製のクローラーだけだと思います。無料でオープンソースのクローラーがたくさんあり、ユーザーがほとんど手を加えることなく、必要なすべてのことを実行してくれる可能性があります。

于 2008-09-19T15:19:25.283 に答える
2

単語のリストを作成し、Google で検索された単語ごとにスレッドを作成できます。
次に、各スレッドは、ページ内で見つかったリンクごとに新しいスレッドを作成します。
各スレッドは、データベースで見つけたものを書き込む必要があります。各スレッドは、ページの読み取りを完了すると終了します。
そして、データベースには非常に大きなリンクのデータベースがあります。

于 2008-09-19T15:17:56.690 に答える
0

wget を使用し、すべてのファイルをハードドライブにダンプする再帰的な Web サックを実行してから、別のスクリプトを記述して、ダウンロードしたすべてのファイルを調べて分析します。

編集:または、wgetの代わりにcurlかもしれませんが、curlに慣れていないため、wgetのように再帰的なダウンロードを行うかどうかわかりません。

于 2008-09-19T15:13:08.950 に答える
0

私は会社の内部検索にオープン検索サーバーを使用しています。これを試してください:http: //open-search-server.comもオープンソースです。

于 2012-06-29T12:42:27.937 に答える
0

.net でリアクティブ拡張機能を使用して単純な Web クローラーを作成しました。

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);
    }
}

次のように使用できます。

Crawler crawler = new Crawler();
IObservable observable = crawler.Crawl(new Uri("http://www.codinghorror.com/"));
observable.Subscribe(onNext: Console.WriteLine, 
onCompleted: () => Console.WriteLine("Crawling completed"));
于 2013-06-07T06:16:26.287 に答える