/[Search-Estraier]/trunk/scripts/est-spider
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/scripts/est-spider

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 77 by dpavlin, Mon Jan 16 21:34:14 2006 UTC revision 197 by dpavlin, Fri Jan 5 22:19:01 2007 UTC
# Line 3  use strict; Line 3  use strict;
3  use File::Find;  use File::Find;
4  use Getopt::Long;  use Getopt::Long;
5  use File::Which;  use File::Which;
 use HyperEstraier;  
6  use Search::Estraier;  use Search::Estraier;
7  use Text::Iconv;  use Text::Iconv;
8  #use File::MMagic;  #use File::MMagic;
9  use File::MMagic::XS qw/:compat/;  use File::MMagic::XS qw/:compat/;
10    use Time::HiRes qw/time/;
11  # do we use Node API?  use HTML::TreeBuilder;
12  my $node_url;  use Data::Dump qw/dump/;
13    
14  my $collection;         # name which will be inserted  my $collection;         # name which will be inserted
15  my $path_add;           # add additional info in path  my $path_add;           # add additional info in path
# Line 20  my $exclude; Line 19  my $exclude;
19  #$verbose = 1;  #$verbose = 1;
20  my $debug = 0;  my $debug = 0;
21  my $force = 0;  my $force = 0;
22  my $native = 0;  my $all = 0;
23    my $skip_images = 0;
24    
25  my $result = GetOptions(  my $result = GetOptions(
26          "collection=s" => \$collection,          "collection=s" => \$collection,
# Line 28  my $result = GetOptions( Line 28  my $result = GetOptions(
28          "verbose!" => \$verbose,          "verbose!" => \$verbose,
29          "debug!" => \$debug,          "debug!" => \$debug,
30          "exclude=s" => \$exclude,          "exclude=s" => \$exclude,
         "node=s" => \$node_url,  
31          "force!" => \$force,          "force!" => \$force,
32          "native!" => \$native,          "all!" => \$all,
33            "skip-images!" => \$skip_images,
34  );  );
35    
36  my $dir = shift @ARGV || die "usage: $0 [dir]";  my ($node_url,$dir) = @ARGV;
37    
38    die <<"_END_OF_USAGE_" if (! $node_url || ! $dir);
39    usage: $0 http://localhost:1978/node/my_dir /path/to/directory
40    
41    options:
42            --collection="name of collection"
43            --path=/path/to/add/at/end
44            --exclude=regex_to_exclude
45            --skip-images
46            --verbose
47            --force
48            --debug
49            --all   save placeholders for all files
50    _END_OF_USAGE_
51    
52  if (! -e $dir) {  if (! -e $dir) {
53          warn "directory $dir doesn't exist, skipping\n";          warn "directory $dir doesn't exist, skipping\n";
# Line 44  if (! -e $dir) { Line 58  if (! -e $dir) {
58  #$basedir =~ s,/[^/]+$,/,;  #$basedir =~ s,/[^/]+$,/,;
59  #require "$basedir/filter.pm";  #require "$basedir/filter.pm";
60    
61  my $pdftotext = which('pdftotext');  my $docs = 0;
62    my $start_t = time();
63    
64    my $filter;
65    foreach my $f (qw/pdftotext pstotext/) {
66            my $w = which($f);
67            if ($w) {
68                    $filter->{$f} = $w;
69                    print STDERR "using $f filter at $w\n" if ($verbose);
70            }
71    }
72    
73  #my $mm = new File::MMagic('/usr/share/misc/file/magic');  #my $mm = new File::MMagic('/usr/share/misc/file/magic');
74  my $mm = new File::MMagic::XS();  my $mm = new File::MMagic::XS();
# Line 54  my $iconv = new Text::Iconv('iso-8859-2' Line 78  my $iconv = new Text::Iconv('iso-8859-2'
78  select(STDERR); $|=1;  select(STDERR); $|=1;
79  select(STDOUT); $|=1;  select(STDOUT); $|=1;
80    
81  print STDERR "using $pdftotext to convert pdf into html\n" if ($pdftotext && $verbose);  my $db = new Search::Estraier::Node(
82            url => $node_url,
83            user => 'admin',
84            passwd => 'admin',
85            croak_on_error => 1,
86            create => 1,
87    );
88    
89    #
90    # check if hhc file exists, and if it does, extract information from it
91    #
92    
93    my $hhc_file;
94    # try to find hhc
95    find({ wanted => sub {
96                    return unless( m!\.hhc$!i );
97                    $hhc_file = $_;
98                    warn "using $hhc_file for tree structure\n";
99            },
100            follow => 1,
101            follow_skip => 2,
102            no_chdir => 1,
103    }, $dir);
104    
105  my $db;  my $meta;
106  if ($node_url) {  
107          if ($native) {  if ($hhc_file) {
108                  $db = HyperEstraier::Node->new($node_url);  
109          } else {          sub param {
110                  $db = new Search::Estraier::Node;                  my ($el) = @_;
111                  $db->set_url($node_url);  
112                    my $n;
113                    foreach my $p ( $el->find('param') ) {
114                            $n->{ $p->attr('name') } = $p->attr('value');
115                    }
116    
117                    if ( ! defined($n->{Local}) ) {
118                            warn "### skipped = ",dump($n),$/;
119                            return;
120                    }
121    
122                    my $path = $dir . '/' . $n->{Local};
123                    $path =~ s!//!/!g;
124                    $path = lc($path);
125    
126                    $n->{path} = $path;
127    
128                    my $nr = $n->{ImageNumber} || return $n;
129    
130                    if ($nr == 27) {
131                            $meta->{title} = $n->{Name};
132                            $meta->{index_path} = $path;
133                    } elsif ($nr == 21) {
134                            $meta->{toc_path} = $path;
135                    } elsif ($nr == 1) {
136                            $meta->{foreword_path} = $path;
137                    } elsif ($nr == 11) {
138                            # nop
139                    } else {
140                            warn "unknown ImageNumber: $nr\n";
141                    }
142    
143                    return $n;
144          }          }
145          $db->set_auth('admin', 'admin');  
146  } else {          my $tree = HTML::TreeBuilder->new;
147          # open the database          $tree->parse_file($hhc_file);
148          $db = HyperEstraier::Database->new();  
149          $db->open('/tmp/casket', $HyperEstraier::Database::DBWRITER | $HyperEstraier::Database::DBCREAT);          my $prefix = $collection ? ( $collection . ' :: ' ) : '';
150    
151          sub signal {          my @prefix;
152                  my($sig) = @_;          my $depth = 0;
153                  print "\nCaught a SIG$sig--syncing database and shutting down\n";  
154                  $db->sync();          foreach my $e ( $tree->look_down( sub { $_[0]->tag =~ m/(object)/ } ) ) {
155                  exit(0);  
156    #               printf("%05s %s\n", $e->parent->address(), $e->as_HTML() );
157    
158                    my $l = ($e->depth() / 2) - 1;
159    
160                    $prefix[ 0 ] = $meta->{title} || '';
161    
162                    my $n = param($e);
163                    $prefix[ $l ] = $n->{Name};
164    
165                    next unless ($n->{path});
166    
167                    my $t = '';
168                    my @p;
169                    foreach my $i ( 0 .. $l ) {
170                            push @p, $prefix[ $i ] if ($prefix[ $i ]);
171                    }
172                    $t = join(' :: ', @p ) if (@p);
173    
174                    $meta->{path2title}->{ $n->{path} } = $t;
175    
176          }          }
177    
178          $SIG{'INT'}  = \&signal;          $tree->delete;
179          $SIG{'QUIT'} = \&signal;  
180  }  }
181    
182    
183  find({ wanted => \&file,  find({ wanted => \&file,
184          follow => 1,          follow => 1,
185          follow_skip => 2,          follow_skip => 2,
186          no_chdir => 1,          no_chdir => 1,
187  }, $dir);  }, $dir);
188    
189  unless ($node_url) {  my $dur = (time() - $start_t) || 1;
190          print "--- sync\n";  printf STDERR "%d documents in %.2fs [%.2f docs/s]\n", $docs, $dur, ($docs / $dur);
191          $db->sync();  
192    $db->master(
193            action => 'sync'
194    );
195    
196    
         print "--- optimize...\n";  
         $db->optimize(0);  
 }  
197  exit;  exit;
198    
199  sub dump_contents($$$$) {  sub dump_contents {
200          my ($db,$contents,$mtime,$path) = @_;          my ($db,$contents,$mtime,$path,$size) = @_;
201    
202          return unless ($contents);      # don't die on empty files          return unless (defined($contents));     # don't die on empty files
203    
204          if ($exclude && $path =~ m/$exclude/i) {          if ($exclude && $path =~ m/$exclude/i) {
205                  print STDERR "skip: $path\n" if ($verbose);                  print STDERR "skip: $path\n" if ($verbose);
# Line 107  sub dump_contents($$$$) { Line 207  sub dump_contents($$$$) {
207          }          }
208    
209          use bytes;          use bytes;
210          my $size = length $contents;          if (! $size) {
211                    $size = length $contents;
212            }
213    
214          print STDERR " [$size]" if ($verbose);          print STDERR " [$size]" if ($verbose);
215    
216          # create a document object          # create a document object
217          my $doc;          my $doc = new Search::Estraier::Document;
218          if ($native) {  
219                  $doc = HyperEstraier::Document->new;          my $title;
220    
221            if ( defined($meta->{path2title}->{lc($path)}) ) {
222                    $title = $meta->{path2title}->{lc($path)};
223                    warn " $title\n";
224          } else {          } else {
                 $doc = new Search::Estraier::Document;  
         }  
225    
226          my $title = $1 if ($contents =~ m#<title>(.+?)</title>#is);                  $title = $1 if ($contents =~ m#<title>(.+?)</title>#is);
227    
228          # chop long titles to 100 chars                  # chop long titles to 100 chars
229          $title = substr($title, 0, 100) . '...' if ($title && length($title) > 100);                  $title = substr($title, 0, 100) . '...' if ($title && length($title) > 100);
230          # use path if no title is found                  # use path if no title is found
231          $title ||= $path;                  $title ||= $path;
232            
233            }
234    
235          # add attributes to the document object          # add attributes to the document object
236          $doc->add_attr('@uri', "file:///$path");          $doc->add_attr('@uri', "file:///$path");
# Line 132  sub dump_contents($$$$) { Line 238  sub dump_contents($$$$) {
238          $doc->add_attr('@size', $size);          $doc->add_attr('@size', $size);
239          $doc->add_attr('@mtime', $mtime);          $doc->add_attr('@mtime', $mtime);
240    
241          # html2text          if ($contents) {
242          $contents =~ s#<[^>]+/*>##gs;                  # html2text
243          $contents =~ s#\s\s+# #gs;                  $contents =~ s#<script.*?</script>##gis;
244                    $contents =~ s#<[^>]+/*>##gs;
245                    $contents =~ s#\s\s+# #gs;
246    
247          $doc->add_text($iconv->convert($contents));                  $doc->add_text($iconv->convert($contents));
   
 #       print $doc->dump_draft if ($verbose);  
   
         # register the document object to the database  
         if ($node_url) {  
                 $db->put_doc($doc);  
         } else {  
                 $db->put_doc($doc, $HyperEstraier::Database::PDCLEAN);  
248          }          }
249            # store path
250            $doc->add_hidden_text($path);
251            # boost title
252            $doc->add_hidden_text($title);
253    
254  }          print $doc->dump_draft if ($debug);
   
 sub file {  
   
         my $path = $_;  
         my $contents;  
   
         return if (! $force && -l $path || $path =~ m#/.svn# || $path =~ m/(~|.bak)$/);  
   
         my $mtime = (stat($path))[9] || -1;  
         my $mtime_db = $db->get_doc_attr_by_uri("file:///$path", '@mtime') || -2;  
   
         if ($mtime == $mtime_db) {  
                 print STDERR "# same: $path $mtime\n" if ($verbose);  
                 return unless($force);  
         } else {  
                 print STDERR "# changed: $path $mtime != $mtime_db\n" if ($debug);  
         }  
255    
256          # skip files on which File::MMagic::XS croaks          # register the document object to the database
257          return if ($path =~ m#\.au$#);          $db->put_doc($doc);
258    
259          my $type = $mm->checktype_filename($path);          $docs++;
         $type =~ s/\s+/ /gs;  
260    
261          print STDERR "# $path $type\n" if ($debug);  }
262    
263          if ($pdftotext && -f $path && $type =~ m/pdf/i) {  sub filter_to_pages {
264                    my ($path, $mtime, $command) = @_;
265    
266                  print STDERR "$path {converting}" if ($verbose);                  print STDERR "$path {converting}" if ($verbose);
267    
268                  open(F,"$pdftotext -htmlmeta \"$path\" - |") || die "can't open $pdftotext with '$path'";                  open(F,"$command |") || die "can't open $command with '$path': $!";
269                  my $html;                  my $html;
270                  while(<F>) {                  while(<F>) {
                         # XXX why pdftotext barks if I try to use this is beyond me.  
                         #$contents .= $_;  
   
271                          $html .= $_;                          $html .= $_;
272                  }                  }
273                  close(F);                  close(F);
# Line 216  sub file { Line 300  sub file {
300                          $page_nr++;                          $page_nr++;
301                  }                  }
302    
303    
304    
305    }
306    
307    sub file {
308    
309            my $path = $_;
310            my $contents;
311    
312            return if (! $force && -l $path || $path =~ m#/.svn# || $path =~ m/(~|.bak|.gif)$/);
313            return if (! $all && -d $path);
314    
315            my $mtime = (stat($path))[9] || -1;
316            my $mtime_db;
317            eval { $db->get_doc_attr_by_uri("file:///$path", '@mtime') } unless ($force);
318            $mtime_db ||= -2;
319    
320            if ($mtime == $mtime_db) {
321                    print STDERR "# same: $path $mtime\n" if ($verbose);
322                    return unless($force);
323            } else {
324                    print STDERR "# changed: $path $mtime != $mtime_db\n" if ($debug);
325            }
326    
327            # skip files on which File::MMagic::XS croaks
328            if ($path =~ m#\.au$#) {
329                    warn "skipped '$path' to prevent File::MMagic::XS bug\n" if ($debug);
330                    return;
331            }
332    
333            my $type = $mm->checktype_filename($path);
334            $type =~ s/\s+/ /gs;
335    
336            print STDERR "# $path $type\n" if ($debug);
337    
338            if ($type =~ m/pdf/i) {
339                    if ($filter->{pdftotext}) {
340                            filter_to_pages($path, $mtime, qq( $filter->{pdftotext} -htmlmeta "$path" - ));
341                    } else {
342                            warn "skipping '$path', no pdftotext filter\n" if ($verbose);
343                            return;
344                    }
345            } elsif ($type eq 'application/postscript') {
346                    if ($filter->{pstotext}) {
347                            filter_to_pages($path, $mtime, qq( $filter->{pstotext} "$path" ));
348                    } else {
349                            warn "skipping '$path', no pstotext filter\n" if ($verbose);
350                            return;
351                    }
352            } elsif ($type =~ m!^image/! && $skip_images) {
353                    warn "skipping image '$path'\n" if ($verbose);
354                    return; # don't index images
355          } else {          } else {
356    
357  #               return if (! -f $path || ! m/\.(html*|php|pl|txt|info|log|text)$/i);  #               return if (! -f $path || ! m/\.(html*|php|pl|txt|info|log|text)$/i);
358                  if (-f $path && $type =~ m/html/ ||                  if (-f $path &&
359                          ($type !~ m#text# && $path =~ m/\.(php|pl|txt|info|log|text)$/io)                          $type !~ m/html/ &&
360                            $path !~ m/\.(php|pl|txt|info|log|text)$/io
361                  ) {                  ) {
362                          dump_contents($db, "<title>$path</title> $type", $mtime, $path);                          dump_contents($db, '', $mtime, $path, -s $path) if ($all);
363                            return;
364                  }                  }
365    
366                  # skip index files                  # skip index files
367                  return if (m/index_[a-z]\.html*/i || m/index_symbol\.html*/i);                  return if ($path =~ m/index_(?:[a-z]+|symbol)\.html*/i);
368    
369                  open(F,"$path") || die "can't open file: $path";                  open(F,"$path") || die "can't open file: $path";
370                  print STDERR "$path ($type)" if ($verbose);                  print STDERR "$path ($type)" if ($verbose);

Legend:
Removed from v.77  
changed lines
  Added in v.197

  ViewVC Help
Powered by ViewVC 1.1.26