crawlしてできるディレクトリの詳細 - Nutch調査録
-
概要
crawlした際に作成されるディレクトリをdumpしてどんな情報がいるか確認する。導入と一部内容が被るので、その辺は適宜読み飛ばしてください。
@Author mwSoft
@Date 2010/12/12
@Env Nutch1.2/Fedora14 -
データの用意
dumpする前にデータを用意しておく。
まず、injectするURLを用意
$ mkdir url_list $ touch url_list/urls.txt $ vi url_list/urls.txt http://www.yahoo.co.jp/ http://www.goo.ne.jp/ http://www.infoseek.co.jp/ http://www.livedoor.com/
とりあえずポータルサイト的なページのトップを貼っておく。
次にcrawlを3週ほどさせる。
$ bin/nutch crawl url_list -dir crawl -depth 3 -topN 10
これでそれなりにデータは揃ったと思うので、次項から各ディレクトリをdumpするコマンドを打ってどんな情報が格納されたかを見ていく。
-
crawldb
crawldbはクローラがどのURLをいつfetchしたか、次にクロールする時にはどのURLをfetchする必要があるかなどを格納している。
とりあえず結果をdumpしてみる。
$ bin/nutch readdb crawl/crawldb -dump dump $ vi dump/part-00000
これでcrawldbの内容がdumpされる。
こうすると以下のような情報が出力される。
http://autos.goo.ne.jp/ Version: 7 Status: 1 (db_unfetched) Fetch time: Sun Dec 12 18:37:32 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 0.01 Signature: null Metadata:
上記はhttp://autos.goo.ne.jp/というURLに対して、Statusがdb_unfetched(まだfetchしていない)で、Score(優先度)が0.01である状態。
既にfetchされたURLは以下のように格納されている。
http://blog.goo.ne.jp/ Version: 7 Status: 2 (db_fetched) Fetch time: Tue Jan 11 18:39:19 JST 2011 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 0.021828 Signature: 57d682bc15c030c2d24cbc1ce36f2d3a Metadata: _pst_: success(1), lastModified=0
Statusはdb_fetched(fetchした)で、スコアは0.021828。
Fetch timeは次にFetchする時期。この日付が未来だとFetch対象にならない。ここでは2011年1月11日になっているが、これを実行したのは2010年12月12日。つまり前回Fetchした時間にRetry intervalが加算されたのがFetch timeになる。
HTTPのリダイレクトが実行された場合はこんな感じ。
http://m.infoseek.co.jp/ Version: 7 Status: 4 (db_redir_temp) Fetch time: Tue Jan 11 18:39:20 JST 2011 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 0.020260569 Signature: null Metadata: _pst_: temp_moved(13), lastModified=0: http://k-tai.infoseek.co.jp/
これは、http://m.infoseek.co.jp/にリクエストしたら、http://k-tai.infoseek.co.jp/にリダイレクトされたよ、という意味。
このリダイレクト情報は、リダイレクト先のhttp://k-tai.infoseek.co.jp/にも記録されてる。こんな感じで。
http://k-tai.infoseek.co.jp/ Version: 7 Status: 1 (db_unfetched) Fetch time: Sun Dec 12 18:39:53 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 0.0 Signature: null Metadata: _pst_: temp_moved(13), lastModified=0: http://k-tai.infoseek.co.jp/_repr_: http://m.infoseek.co.jp/
この他にもdb_goneというステータスもいる。
http://www.livedoor.com/r/link_blog Version: 7 Status: 3 (db_gone) Fetch time: Wed Jan 26 18:37:37 JST 2011 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 3888000 seconds (45 days) Score: 0.04 Signature: null Metadata: _pst_: robots_denied(18), lastModified=0
ソースを見てみると、robots.txtに拒否された場合とか、リダイレクト回数が指定回数を超えた場合などに発生するようだ。
実際にlivedoorのrobots.txt(http://www.livedoor.com/robots.txt)を見ると、/r配下はDisallowになっている。ということで上記はrobots.txtで弾かれた結果っぽい。
あとはStatusが5(DB_REDIR_PERM)が発生することもある。これは多分、HTTP301(Moved Permanently)だと思われる。ちなみにStatus 4(db_redir_temp)は302 Found。
Status 6はdb_notmodified。304 Not Modified時に発生すると思われる。
-
segments
segmentsはクロールした結果を格納する。Fetchするたびにディレクトリが作られる。
今回は-depth 3でクロールしたので、ディレクトリは3つ出来ている。
$ ls crawl/segments 20101212183721 20101212183735 20101212183917
とりあえず、http://www.livedoor.com/のクロール結果を見てみる。livedoorのトップは最初にinjectしたURLだから、ここでは一番最初のディレクトリ(ls -1 crawl/segments | head -1)にいるはず。
segmentsはreadsegコマンドで内容をdumpできる。
$ s1=`ls -1 crawl/segments | head -1` $ bin/nutch readseg -get crawl/segments/$s1 http://www.livedoor.com/
これで指定したURLの本文、タイトル、リンク、テキスト部分の抽出結果などが取得できる。
readsegには以下の引数が指定できる。
引数 内容 -nocontent content(取得した生データ)を表示しない -nofetch fetch(Fetchした時のステータスとか)を表示しない -nogenerate generate結果(?)を表示しない -noparse parse(?)を表示しない -noparsedata parsedata(パースして得た情報)を表示しない -noparsetext parsetext(テキストのみ抽出した結果)を表示しない 実際に-noオプションをいろいろ付けて、中身を見てみる。
contentだけを出力する場合
$ bin/nutch readseg -get crawl/segments/$s1 http://www.livedoor.com/ -nofetch -nogenerate -noparse -noparsedata -noparsetext
上記は-nocontent以外は全部指定している。ということで、出力はcontentのみ。contentは取得したデータそのものなので文字コードもそのまんまで格納されている。
fetchだけを出力する場合
$ bin/nutch readseg -get crawl/segments/$s1 http://www.livedoor.com/ -nocontent -nogenerate -noparse -noparsedata -noparsetext SegmentReader: get 'http://www.livedoor.com/' Crawl Fetch:: Version: 7 Status: 33 (fetch_success) Fetch time: Sun Dec 12 18:37:25 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 1.0 Signature: null Metadata: _ngt_: 1292146638050_pst_: success(1), lastModified=0
上記のようにFetchした時の結果(fetch_success)なんかが格納されている。
リダイレクトした時はその情報も格納されている。
$ s3=`ls -1 crawl/segments | tail -1` $ bin/nutch readseg -get crawl/segments/$s3 http://m.infoseek.co.jp/ -nocontent -nogenerate -noparse -noparsedata -noparsetext SegmentReader: get 'http://m.infoseek.co.jp/' Crawl Fetch:: Version: 7 Status: 35 (fetch_redir_temp) Fetch time: Sun Dec 12 18:39:20 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 0.020260569 Signature: null Metadata: _ngt_: 1292146754503_pst_: temp_moved(13), lastModified=0: http://k-tai.infoseek.co.jp/
generateだけを出力する場合
$ bin/nutch readseg -get crawl/segments/$s1 http://www.livedoor.com/ -nocontent -nofetch -noparse -noparsedata -noparsetext SegmentReader: get 'http://www.livedoor.com/' Crawl Generate:: Version: 7 Status: 1 (db_unfetched) Fetch time: Sun Dec 12 18:37:14 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 1.0 Signature: null Metadata: _ngt_: 1292146638050
generateはinjectされたURLからクロール対象を生成する時に使うコマンド。なので、Fetchする際にgenerateされた情報ではないかと思われる。
parseだけを出力する場合
$ bin/nutch readseg -get crawl/segments/$s1 http://www.livedoor.com/ -nocontent -nofetch -nogenerate -noparse -noparsetext SegmentReader: get 'http://www.livedoor.com/' Crawl Parse:: Version: 7 Status: 65 (signature) Fetch time: Sun Dec 12 18:37:29 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 0 seconds (0 days) Score: 1.0 Signature: b2b3a4b0f46621553922502ce7c01575 Metadata:
なんだろ、これ。signature(署名)? 他にはINJECTED、LINKED、PARSE_METAなんかがいるっぽい。
parsedataだけを出力する場合
$ bin/nutch readseg -get crawl/segments/$s1 http://www.livedoor.com/ -nocontent -nofetch -nogenerate -noparse -noparsetext SegmentReader: get 'http://www.livedoor.com/' ParseData:: Version: 5 Status: success(1,0) Title: livedoor Outlinks: 100 outlink: toUrl: http://www.livedoor.com/r/link_blog anchor: outlink: toUrl: http://www.livedoor.com/r/link_blog anchor: outlink: toUrl: http://www.livedoor.com/r/link_blogmake anchor: outlink: toUrl: http://www.livedoor.com/r/link_blog anchor: (中略) outlink: toUrl: http://www.livedoor.com/text/javascript anchor: outlink: toUrl: http://www.livedoor.com/js/jquery-1.4.2.min.js anchor: Content Metadata: Content-Length=26430 _fst_=33 Set-Cookie=ucd_sig=ZK6OjXXo5nWXXSexhXXR%2FY6c1Bg%3X1292XX6623; domain=livedoor.com; path=/; expires=Fri, 10-Jun-2011 09:37:03 GMT nutch.segment.name=20101212183721 Connection=close Server=Apache _ftk_=1292146645169 Cache-Control=no-cache Pragma=no-cache nutch.content.digest=c1f8e405575b6848f4a6f225c36470be Date=Sun, 12 Dec 2010 09:37:03 GMT Vary=Accept-Encoding,User-Agent Content-Encoding=gzip nutch.crawl.score=1.0 X-XRDS-Location=https://auth.livedoor.com/openid/server.xrds Content-Type=text/html; charset=utf-8 Parse Metadata: CharEncodingForConversion=utf-8 OriginalCharEncoding=utf-8
outlinkのMAXは100に設定しているので、100個ちょうどのURLが抽出されている。タイトル、HTTPヘッダの情報なんかも表示されている。
ちなみに100個以上リンクを取りたい場合は、たぶんdb.max.outlinks.per.pageを変更するはず。
parsetextだけを出力する場合
$ bin/nutch readseg -get crawl/segments/$s1 http://www.livedoor.com/ -nocontent -nofetch -nogenerate -noparse -noparsedata SegmentReader: get 'http://www.livedoor.com/' ParseText:: livedoor livedoor 統合検索 | ウェブ | ブログ | 画像 | 動画 | まとめ | 登録サイト | その他 開く ニュース リアルタイム クチコミ トピック テーマ 商品 サービス一覧 検索 候補 検索 機能オフ サジェスト機能とは、検索キーワードの入力を補助する機能です。検索キーワードの一部を入力すると、関連性の高い検索キーワードが表示されます。 機能オン トピックワード: 滝井礼乃 海老蔵 M-1グランプリ 桜 稲垣早希 香川真司 設定 地図 翻訳 ゲーム ブログ ブログを作る Wiki グルメ Twitter 設定 主要 国内 政治 海外 経済 IT エンタメ 音楽 映画 スポーツ コラム 参加者の学歴高い (以下略)
こんな形でテキスト部分だけ抽出した結果が表示される。
尚、segmentsのデータをまとめてdumpしたい場合はこんな感じ。
$ bin/nutch readseg -dump crawl/segments/$s1 dump $ vi dump/dump
これで指定したsegmentsディレクトリの中身をまとめて出力したファイルが見られる。
-
linkdb
linkdbの内容はreadlinkdbで読むことができる。
$ bin/nutch readlinkdb crawl/linkdb -url http://blog.goo.ne.jp/ fromUrl: http://oshiete.goo.ne.jp/ anchor: ブログ fromUrl: http://tv.goo.ne.jp/index.html anchor: ブログ fromUrl: http://www.goo.ne.jp/ anchor: ブログ fromUrl: http://www.goo.ne.jp/ anchor: ブログ - 初めてでも簡単 fromUrl: http://transit.goo.ne.jp/ anchor: ブログ fromUrl: http://map.goo.ne.jp/ anchor: ブログ
上記のような感じで、fromUrl、つまり指定したURLがどこからリンクされているかを確認できる。toUrlはsegmentsのparseDataで見れるので、これでURLの双方向はとりあえず見れることがわかる。
linkdbを全部dumpしたい場合は、以下のような感じ。ディレクトリが被るとエラーになるのでさっきdumpした情報は削除しておく。
$ rm -rf dump $ bin/nutch readlinkdb crawl/linkdb -dump dump $ vi dump/part-00000
-
index
indexはLuceneのindexが普通に放りこまれている。JavaでIndexReaderにこのディレクトリを指定して検索を実行することもできる。
簡易にどういった情報が入っているかを見るにはLukeを使うと楽。
以下からlukeall-1.0.1.jarをダウンロードする。
http://code.google.com/p/luke/downloads/list
で、実行。
$ java -classpath lukeall-1.0.1.jar org.getopt.luke.Luke
出てきたPath to Index Directoryにcrawl/indexのディレクトリのフルパスを指定する。
そうすると、こんなインデックス情報が入っているよということを提示してくれる。
ストアされている情報
フィールド名 内容 例 boost ? 1.0 cache ? content segments segmentsのディレクトリ名 20101212183721 title 文書のタイトル livedoor tstamp 取得時のタイムスタンプ(UTC) 20101212093919801 url このコンテンツのURL http://www.livedoor.com/ 検索できる情報
フィールド名 内容 anchor segmentsのparsedataで表示されるアンカー? boost ? cache ? content 本文 digest ? host URLのホスト部分 segment 格納されているsegmentsのディレクトリ名 site ソースを見るとトークン化しないホストっぽい title ページのタイトル tstamp タイムスタンプ url 専用のパーサでトークン化されているっぽい 実際にどういう感じで検索ができるかは、NutchBeanを実行した際にクエリを生成しているParserクラスを直接実行すると割とわかる。
試しに「テスト」という言葉から検索用のフレーズを作成してもらう。
$ bin/nutch org.apache.nutch.searcher.Query Query: テスト Parsed: テ ス ト Translated: +(url:テ^4.0 anchor:テ^2.0 content:テ title:テ^1.5 host:テ^2.0) +(url:ス^4.0 anchor:ス^2.0 content:ス title:ス^1.5 host:ス^2.0) +(url:ト^4.0 anchor:ト^2.0 content:ト title:ト^1.5 host:ト^2.0) url:"テ ス ト"~5^4.0 anchor:"テ ス ト"~4^2.0 content:"テ ス ト"~5 title:"テ ス ト"~5^1.5 host:"テ ス ト"~5^2.0
なんかすごい検索クエリができあがっている。このへんのインデックスは独自のパーサ使ったりしてるっぽいので、馴染みのCJKAnalyzerでさらっと検索するようなことはできないっぽい。
プラグイン作ってカスタマイズすればこのへんはある程度思い通りになるはず。