/[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 89 by dpavlin, Wed Jan 25 23:38:57 2006 UTC revision 197 by dpavlin, Fri Jan 5 22:19:01 2007 UTC
# Line 7  use Search::Estraier; Line 7  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    use HTML::TreeBuilder;
12    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 16  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 $all = 0;
23    my $skip_images = 0;
24    
25  my $result = GetOptions(  my $result = GetOptions(
26          "collection=s" => \$collection,          "collection=s" => \$collection,
# Line 24  my $result = GetOptions( Line 29  my $result = GetOptions(
29          "debug!" => \$debug,          "debug!" => \$debug,
30          "exclude=s" => \$exclude,          "exclude=s" => \$exclude,
31          "force!" => \$force,          "force!" => \$force,
32            "all!" => \$all,
33            "skip-images!" => \$skip_images,
34  );  );
35    
36  my ($node_url,$dir) = @ARGV;  my ($node_url,$dir) = @ARGV;
# Line 35  options: Line 42  options:
42          --collection="name of collection"          --collection="name of collection"
43          --path=/path/to/add/at/end          --path=/path/to/add/at/end
44          --exclude=regex_to_exclude          --exclude=regex_to_exclude
45            --skip-images
46          --verbose          --verbose
47          --force          --force
48          --debug          --debug
49            --all   save placeholders for all files
50  _END_OF_USAGE_  _END_OF_USAGE_
51    
52  if (! -e $dir) {  if (! -e $dir) {
# Line 49  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 59  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 $meta;
106    
107    if ($hhc_file) {
108    
109            sub param {
110                    my ($el) = @_;
111    
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    
146            my $tree = HTML::TreeBuilder->new;
147            $tree->parse_file($hhc_file);
148    
149            my $prefix = $collection ? ( $collection . ' :: ' ) : '';
150    
151            my @prefix;
152            my $depth = 0;
153    
154            foreach my $e ( $tree->look_down( sub { $_[0]->tag =~ m/(object)/ } ) ) {
155    
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            $tree->delete;
179    
180    }
181    
 my $db = new Search::Estraier::Node;  
 $db->set_url($node_url);  
 $db->set_auth('admin', 'admin');  
182    
183  find({ wanted => \&file,  find({ wanted => \&file,
184          follow => 1,          follow => 1,
# Line 71  find({ wanted => \&file, Line 186  find({ wanted => \&file,
186          no_chdir => 1,          no_chdir => 1,
187  }, $dir);  }, $dir);
188    
189    my $dur = (time() - $start_t) || 1;
190    printf STDERR "%d documents in %.2fs [%.2f docs/s]\n", $docs, $dur, ($docs / $dur);
191    
192    $db->master(
193            action => 'sync'
194    );
195    
196    
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 85  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 = new Search::Estraier::Document;          my $doc = new Search::Estraier::Document;
218    
219          my $title = $1 if ($contents =~ m#<title>(.+?)</title>#is);          my $title;
220    
221          # chop long titles to 100 chars          if ( defined($meta->{path2title}->{lc($path)}) ) {
222          $title = substr($title, 0, 100) . '...' if ($title && length($title) > 100);                  $title = $meta->{path2title}->{lc($path)};
223          # use path if no title is found                  warn " $title\n";
224          $title ||= $path;          } else {
225    
226                    $title = $1 if ($contents =~ m#<title>(.+?)</title>#is);
227    
228                    # chop long titles to 100 chars
229                    $title = substr($title, 0, 100) . '...' if ($title && length($title) > 100);
230                    # use path if no title is found
231                    $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 105  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));
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 ($verbose);          print $doc->dump_draft if ($debug);
255    
256          # register the document object to the database          # register the document object to the database
257          $db->put_doc($doc);          $db->put_doc($doc);
258    
259  }          $docs++;
   
 sub file {  
260    
261          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);  
         }  
   
         # skip files on which File::MMagic::XS croaks  
         return if ($path =~ m#\.au$#);  
   
         my $type = $mm->checktype_filename($path);  
         $type =~ s/\s+/ /gs;  
   
         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 185  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.89  
changed lines
  Added in v.197

  ViewVC Help
Powered by ViewVC 1.1.26