Perl: Suche auf Website

Hallo,

ich habe ein Script, dass es ermöglich, Webseiten nach bestimmten Ausdrücken zu durchsuchen; das Problem: auch die HTML-Tags werden durchsucht, Z.B. die Metatags.

Wie kann ich es (mit reg_ex?) realisieren, dass alles, was zwischen spitzen Klammern steht, nicht mit durchsucht wird??

Ich wäre auch für einen Tipp in die richtige Richtung schon dankbar :smile:

Doris

Hallo,

ich habe ein Script, dass es ermöglich, Webseiten nach
bestimmten Ausdrücken zu durchsuchen; das Problem: auch die
HTML-Tags werden durchsucht, Z.B. die Metatags.

Wie kann ich es (mit reg_ex?) realisieren, dass alles, was
zwischen spitzen Klammern steht, nicht mit durchsucht
wird??

Du musst die HTML-Tags entfernen. Das Modul HTML::Strip http://search.cpan.org/~kilinrax/HTML-Strip-1.06/Str… scheint das zu tun, ein „poor man’s approach“ wäre eine Regex dieser art:

$html =~ s/]\*\>/g;

oder auch

$html =~ s//g;/

    
    wobei beides z.B. Probleme mit nicht geschlossenen, kaputten HTML-Tags hat.
    
    Wenn du das ganze Zeugs erstmal entfernt hast, kannst du einfach reguläre Ausdrücke darauf loslassen.
    
    Grüße,
    Moritz 

Hallo Moritz,

das ist ja super, es hat auf Anhieb geklappt! :smile:

Das einzige (allerdings unwesentliche) Problem, das jetzt noch besteht:
bisher wurde der „title“ (also das, was zwischen den title-tags steht) als Suchergebnis ausgegeben, der ist natürlich jetzt weg (mit HTML::Strip); mal sehen, was ich da mache…

Vielen Dank auf jeden Fall, ich hatte schon in anderen Foren deswegen angefragt und bin froh, jetzt mal eine funktionierende Antwort bekommen zu haben!

Doris

Hallo,

das ist ja super, es hat auf Anhieb geklappt! :smile:

Freut mich :wink:

Das einzige (allerdings unwesentliche) Problem, das jetzt noch
besteht:
bisher wurde der „title“ (also das, was zwischen den
title-tags steht) als Suchergebnis ausgegeben, der ist
natürlich jetzt weg (mit HTML::Strip); mal sehen, was ich da
mache…

Bevor du HTML::Strip darauf los gehst, kannst den Titel extrahieren:

my $tmp\_html = $html;
my $title = "";
if ($tmp\_html =~ m/(.\*?)/i){
 $title = $1;
}

Funktioniert zwar sicher nicht immer, ist aber schon mal viel besser als nichts.

Grüße,
Mo „regexp“ ritz

Hallo Moritz,

habe jetzt gerade erst deine 2. Antwort hier gesehen, vielen Dank!
inzwischen hatte ich das auch so (ungefähr) hinbekommen, also den Titel zuvor einfach abgespeichert.
Jetzt habe ich noch ein kleines Problem:
diese Suchfunktion durchsucht auch Unterordner, die sie nicht durchsuchen soll… wie könnte man ihr das abgewöhnen? :smile:
Eigentlich wäre es gut, wenn man die Ordner angeben könnte, sie sollte das Hauptverzeichnis durchsuchen und noch ein oder zwei andere.

Schöne Grüße
Doris

Hallo,

Jetzt habe ich noch ein kleines Problem:
diese Suchfunktion durchsucht auch Unterordner, die sie nicht
durchsuchen soll… wie könnte man ihr das abgewöhnen? :smile:

In dem Teil des Programms, das die Dateien einliest. Über den weiß ich aber nichts, kann dir deswegen nicht helfen.

Grüße,
Moritz

Hallo,

Entschuldigung, ich dachte, ich hätte den Code hier schon gepostet…
hier kommt er:

######################
use strict;
use File::Find;
use CGI qw(:standard);
use HTML::Strip;
my $query = param(„query“);
print header();
print start_html();
print „\n Für das Suchwort $query gab es folgende Ergebnisse: \n
\n“;
undef $/;

find( sub
{
return if($_ =~ /^./);
return unless(($_ =~ /.htm/i) || ($_ =~ /.html/i) || ($_ =~ /.php/i));
stat $File::Find::name;
return if -d;
return unless -r;

open(FILE, ";

my $title=„test“;
if ($string =~ /(.*?)/is)
{
$title = $1;
}

my $hs = HTML::Strip->new();
my $clean_string = $hs->parse( $string );
close (FILE);

return unless ($clean_string =~ /\Q$query\E/i);

print „1. $title
\n“;
},
‚…apache/xampp/htdocs/…‘);

print „\n“;
print end_html();
##########################

wär schön, wenn du mir einen Tipp geben könntest:smile:

schönen Gruß
Doris

Hallo Doris

use CGI qw(:standard);
use HTML::Strip;
my $query = param(„query“);


[Quelltext]

wär schön, wenn du mir einen Tipp geben könntest:smile:

Ich hab mal versucht, die Probleme anzugehen. Im Einzelnen,
die „Suchverzeichnisse“ werden (bei meiner Lösung)
einfach über eine Umgebungsvariable eingestellt:

SET SEARCHDIRS=„c:/apache/xampp/htdocs/dir1;c:/apache/xampp/htdocs/dir2“

also immer mit Semikolon getrennt. Es werden dann *genau* diese
durchsucht. Desweiteren könnte man noch darauf bauen, dass die
DOCUMENT_ROOT als CGI-Umgebungsvariable zur verfügung steht,
denn man muss ja die „Resultate“ wieder in die html-Pfade
übersetzen. Ich hab das mal mit eingebaut.

Ich habe ausserdem „no_chdir => 1“ in der find()-Routine verwendet,
dann ist in der aufgerufenen Sub $_ gleich File::Find::Name …

Das wäre meine Idee (Quelltext etwas gestrafft):

 use strict;

 use CGI qw();
 use File::Find;
 use HTML::Strip;
 
 my @dirlist = split ';', $ENV{SEARCHDIRS}; # SET Variable before run
 my $docroot = $ENV{DOCUMENT\_ROOT}; # truncate link path before output
 
 my $cgi = new CGI;
 my $query = quotemeta $cgi-\>param("query");
 
 print $cgi-\>header(), $cgi-\>start\_html(),
 $cgi-\>p("Für das Suchwort $query gab es folgende Ergebnisse:");
 
 print "\n
";  
 find( { wanted =\> \&findsome, no\_chdir =\> 1 }, @dirlist );  
 print "\n", $cgi-\>end\_html();

#####################

sub findsome {
 if( -d ) { # do not descend further into dirs and/or return
 $File::Find::stuck\_out\_tongue:rune = $File::Find::name unless grep(/^$File::Find::name$/, @dirlist);
 return
 }
 return unless -r && /(\.html?|\.php\d?)$/; # $\_ == File::Find::name!
 open my $fh, ' }; # use perl5 slurp idiom
 close $fh;

 my $title = $1 if $string =~ /(.+?)/si;
 my $clean = HTML::Strip-\>new()-\>parse( $string );
 if( $clean =~ /$query/i ) {
 (my $rel\_loc = $File::Find::name) =~ s/$docroot//; # truncate to doc\_root
 print $cgi-\>li( $cgi-\>a( {href =\> $rel\_loc}, $title||'notitle' ) )
 }
} 

Grüße

CMБ

Hallo und vielen Dank für deine genauen Erklärungen!

Leider bekomm ich noch diese Fehlermeldung:

invalid top directory at XXX/xampp/perl/lib/File/Find.pm line 585.

Ich weiß nicht genau, wie ich die Variable SEARCHDIRS füllen muss, sieht jetzt so aus und ist wahrscheinlich falsch:

my @SEARCHDIRS=(„XXX/xampp/htdocs/dir1;XXX/xampp/htdocs/dir1/dir2“);

my @dirlist = split ‚;‘, $ENV{SEARCHDIRS}; # SET Variable before run
my $docroot = $ENV{DOCUMENT_ROOT}; # truncate link path before output

Doris

Hallo

Leider bekomm ich noch diese Fehlermeldung:
invalid top directory at XXX/xampp/perl/lib/File/Find.pm line
585.
Ich weiß nicht genau, wie ich die Variable SEARCHDIRS füllen
muss, sieht jetzt so aus und ist wahrscheinlich falsch:
my
@SEARCHDIRS=(„XXX/xampp/htdocs/dir1;XXX/xampp/htdocs/dir1/dir2“);

Jo, falsch.

Entweder in der c:\autoexec.bat
SET SEARCHDIRS =„c:/temp;c:/xampp/htdocs/doc“
(je Neustart erforderlich)

oder in WinXP:
Start->Einstellungen->Systemsteuerung->System->Erweitert
->Umgebungsvariablen->Systemvariablen->Neu
[Name] SEARCHDIRS
[Wert] c:/XAMPP/htdocs/suche1;c:/XAMPP/htdocs/suche2

oder im Programm kurz vorher:

$ENV{SEARCHDIRS} = "c:/temp;c:/xampp/htdocs/doc1";

oder wo auch immer. Das sind praktisch die
Standard-Umgebungsvariablen für alle Prozesse.

Grüße

CMБ

Wow - klappt hervorragend!! Vielen Dank!!!

Ich bin wieder mal platt, wie wenig Code Perl braucht, um ein doch ziemlich umfangreiches Programm zu absolvieren… ich hab schon so lange mit Perl nichts mehr gemacht, weil ich ständig mit PHP zu tun hatte, aber eigentlich ist Perl doch die viel schönere Sprache :smile:

Schöne Grüße
Doris

Hallo noch mal,

es funktioniert doch noch nicht richtig:
es wird nur das 1. Verzeichnis aus @dirlist durchsucht… (?)

Doris

Hallo noch mal,

es funktioniert doch noch nicht richtig:
es wird nur das 1. Verzeichnis aus @dirlist durchsucht… (?)

Poste bitte mal den genauen Sourcecode,
dann kann man mal prüfen …

Grüße

CMБ

use strict;

use CGI qw(:standard);
use File::Find;
use HTML::Strip;
use CGI::Carp(‚fatalsToBrowser‘, ‚set_message‘);

$ENV{SEARCHDIRS} = „E:/apache/xampp/htdocs/xxx;E:/apache/xampp/htdocs/xxx/dir1;E:/apache/xampp/htdocs/xxx/dir2“;

my @dirlist = split ‚;‘, $ENV{SEARCHDIRS}; # SET Variable before run
my $docroot = $ENV{DOCUMENT_ROOT}; # truncate link path before output

my $cgi = new CGI;
my $query = quotemeta $cgi->param(„query“);

print $cgi->header(), $cgi->start_html(),
$cgi->p(„Für das Suchwort $query gab es folgende Ergebnisse:“);

print "\n
";
find( { wanted => &findsome, no_chdir => 1 }, @dirlist );
print „\n“, $cgi->end_html();

#####################

sub findsome {
if( -d ) { # do not descend further into dirs and/or return
$File::Find::stuck_out_tongue:rune = $File::Find::name unless grep(/^$File::Find::name$/, @dirlist);
return
}
return unless -r && /(.htm?|.php\d?)$/; # $_ == File::Find::name!
open my $fh, ’ }; # use perl5 slurp idiom
close $fh;

my $title = $1 if $string =~ /(.+?)/si;
my $clean = HTML::Strip->new()->parse( $string );
if( $clean =~ /$query/i ) {
(my $rel_loc = $File::Find::name) =~ s/$docroot//; # truncate to doc_root
print $cgi->li( $cgi->a( {href => $rel_loc}, $title||‚notitle‘ ) )
}
}


Danke für deine Mühe!

Gruß
Doris

Hallo Doris,

ich habe hier mal ein paar Verzeichnisse angelegt
und es klappt so weit o.k. - ich habe noch
einige kleine Änderungen vorgenommen (Du
brauchst nichts aus dem CGI-Namensraum zu
importieren, wenn Du das objektorientierte
Interface $cgi->… benutzt).

Jetzt wird noch angezeigt, in welches Verzeichnis
die Suchroutine geht (ausserdem hab ich das
$ENV{SEARCHSTRING} rausgenommen, da Du das
wahrscheinlich nicht brauchst).

Bei mir wurden die gefundenen Files/Directories
sauber angezeigt. Sind die Verzeichnisse tatsächlich
auch lesbar? Ich hab den Verzeichnischeck mal auf /i
(case insensitive) umgestellt. Probier doch noch mal …

use strict;

use CGI qw();
use CGI::Carp('fatalsToBrowser', 'set\_message');
use File::Find;
use HTML::Strip;

my @dirlist = qw{
 Y:/xampp/htdocs/xxx
 Y:/xampp/htdocs/xxx/dir1
 Y:/xampp/htdocs/xxx/dir2
}; # SET Variable before run

my $docroot = $ENV{DOCUMENT\_ROOT}; # truncate link path before output

my $cgi = new CGI;
my $query = quotemeta $cgi-\>param("query");

print $cgi-\>header(), $cgi-\>start\_html(),
$cgi-\>p("Für das Suchwort $query gab es folgende Ergebnisse:");

print "\n
";  
find( { wanted =\> \&findsome, no\_chdir =\> 1 }, @dirlist );  
print "\n", $cgi-\>end\_html();

#####################

sub findsome {
 if( -d ) { # do not descend further into dirs and/or return
 $File::Find::stuck\_out\_tongue:rune = $File::Find::name unless grep(/^$File::Find::name$/i, @dirlist);
 print "
descending into $\_\n";
 return
 }
 return unless -r && /(\.html?|\.php\d?)$/; # $\_ == File::Find::name!
 open my $fh, ' }; # use perl5 slurp idiom
 close $fh;

 my $title = $1 if $string =~ /(.+?)/si;
 my $clean = HTML::Strip-\>new()-\>parse( $string );
 if( $clean =~ /$query/i ) {
 (my $rel\_loc = $File::Find::name) =~ s/$docroot//i; # truncate to doc\_root
 print $cgi-\>li( $cgi-\>a( {href =\> $rel\_loc}, $title||'notitle' ) )
 }
}

Grüße

CMБ

Hallo Semjon,

ich bin echt dankbar für deine Hilfe, denn jetzt bin ich schon wieder ein ganzes Stück vorangekommen. Es gibt aber noch 2 kleine Probleme:

Die Suche soll im Hauptverzeichnis der Website und in einem Unterverz. stattfinden, wenn ich das so angebe:

my @dirlist = qw{
E:/apache/xampp/htdocs/hautpverzeichnis
E:/apache/xampp/htdocs/hauptverzeichnis/unterverzeichnis
};

dann werden die Dateien im Unterverzeichnis doppelt ausgegeben - ist mir nicht klar, warum, ich komm nicht drauf:frowning:

wenn ich zum Test nur das Unterverz. angebe:

my @dirlist = qw{
E:/apache/xampp/htdocs/hauptverzeichnis/unterverzeichnis
};

werden die Dateien richtig, d.h. jeweils 1x ausgegeben

Das 2. Problem sind die Umlaute:
wenn ich z.B. nach „Gaststätte“ suche, lautet das Ergebnis:

Für das Suchwort Gastst\ätte gab es folgende Ergebnisse:

  • wobei es dann kein Ergebnis gibt, obwohl das Wort vorhanden ist.

Wenn man „Gastst & a u m l ; tte“ eingibt (was ja aber niemand macht!)[die Leerzeichen sind jetzt nur da, damit es hier richtig angezeigt wird], kommt als Ergebnis:

Für das Suchwort Gastst\ä;tte gab es folgende Ergebnisse:

  • und die richtigen Seiten werden angezeigt.

Vielleicht gibt es dafür eine einfache Lösung? Auf Webseiten sind nun mal die deutschen Umlaute meistens nicht als einfache Umlaute geschrieben…

Gruß
Doris

Hallo Doris

… werden die Dateien im Unterverzeichnis doppelt
ausgegeben
- ist mir nicht klar, warum, ich komm nicht
drauf:frowning:

Ein „Logik-Fehler“ in der Implementierung (grep
gegen Verzichnisliste + Rekusrion in File::Find).

Im Grunde braucht man File::Find hier gar
nicht, es führt nur zu den beschriebenen
Problemen. Wenn man weiss, wo man sucht,
kann man die Verzeichnisse von Hand öffnen.

Das 2. Problem sind die Umlaute:
wenn ich z.B. nach „Gaststätte“ suche, lautet das Ergebnis:
Für das Suchwort Gastst\ätte gab es folgende
Ergebnisse:

  • wobei es dann kein Ergebnis gibt, obwohl das Wort vorhanden
    ist.
    Wenn man „Gastst & a u m l ; tte“ eingibt (was ja aber niemand
    macht!)[die Leerzeichen sind jetzt nur da, damit es hier
    richtig angezeigt wird], kommt als Ergebnis:
    Für das Suchwort Gastst\ä;tte gab es folgende
    Ergebnisse:
  • und die richtigen Seiten werden angezeigt.

Hmmm, hier wird es dann interessant. Da muss man
wohl mit ‚locale‘ arbeiten und sich genau überlegen,
was man wie vergleicht. Ich habe da eine Idee, wie
man das machen könnte (use encoding „iso8859-1“).

Man müsste erstmal alle Zeichen (incl. Umlaute)
auf eine Weise transformieren (z.B. in Kleinbuchstaben),
dass man später wieder gegen Kleinbuchstaben prüfen kann,
dazu gibt es diese p{CHAR}-Designatoren.

An dieser Stelle ist es sicher gut, das Progrämmchen
in einzelne Funktionen zu zerlegen, da hat man
dann schon mal ein paar subs, die man nicht mehr anzufassen
braucht. Ausserdem hab ich mit map{} um mich
geworfen, da das ein kompaktes Layout ermöglicht :wink:

Worum geht es bei Deinem problem eigentlich?
Intranet? Lokaler Rechner?

Achtung: wenn kein vorhanden ist,
gebe ich den absoluten Pfad aus.

Bei mir funktioniert das jetzt sogar :wink: ==>

use strict;
use encoding "iso8859-1";

use CGI qw();
use CGI::Carp('fatalsToBrowser', 'set\_message');
use File::Find; # braucht man nicht mehr
use HTML::Strip;

my $docroot = $ENV{DOCUMENT\_ROOT}; # truncate link path before output
my $pattern = qr/(?:\.html?|\.php\d?)$/i;
my @dirlist = qw{
 E:/apache/xampp/htdocs/hautpverzeichnis
 E:/apache/xampp/htdocs/hauptverzeichnis/unterverzeichnis
}; 

my $cgi = new CGI;
my $query = $cgi-\>param("query");

print $cgi-\>header(),
 $cgi-\>start\_html(),
 $cgi-\>p("Für das Suchwort $query gab es folgende Ergebnisse:");

$query =~ s/(\p{IsUpper}+)/lc $1/ge; # iso8859-1-Umlaute + Zeichen klein machen!

my @hits =
 map $cgi-\>a( {href =\> $\_-\>{LINK}}, $\_-\>{TITLE} ), # 3) Links basteln
 map processfiles( $\_, $pattern, $query, $docroot ), # 2) untersuchen und
 @dirlist; # 1) Verzeichnisse

print $cgi-\>ol( $cgi-\>li( [@hits] ) ), $cgi-\>end\_html(); # ordered list, mit
 # [@array] (CGI doku)
#####################

 sub processfiles
{
 my ($dir, $pattern, $query, $root) = @\_;
 my ($title, @result);
 for my $fname ( getdircontent($dir, $pattern) ) {
 push @result, { LINK=\>$fname, TITLE=\>$title } # { Hash ref } erzeugen
 if inspect( $fname, $query, \$title ) # wenn Hit erzielt
 }
 map { $\_-\>{LINK} =~ s/$root//i; $\_ } @result; # Liste mit ~htdoc/ }; 
 close $fh;
 
 $$t\_ref = $1 if $string =~ /(.+?)/si; # tatsaechlicher Titel
 $string =~ s/(\p{IsUpper})/lc $1/ge; # iso8859-1 LC Transl.
 my $bare = HTML::Strip-\>new()-\>parse( $string ); # Tags/Entities raus
 return $bare =~ /$query/; # Suche ? 1 : 0
}
#####################

Grüße

CMБ

Bei mir funktioniert das jetzt sogar :wink: ==>

na, dafür gibt’s bei mir jetzt gar nix aus, nicht mal eine Fehlermeldung, nicht mal etwas im error-log :frowning:

ich hab jetzt leider gerade keine Zeit, muss mich später mal damit beschäftigen, vielen Dank!

Doris

Hallo,

also: die Suche funktioniert, nur mit Umlauten nicht.
gibt man ein Wort mit „ß“ ein, z.B. „groß“, funktioniert es, aber bei Wörtern mit „ä“, „ü“ usw. gibt es keine Suchergenisse.

Das Script ist inzwischen so kompliziert, dass ich selbst nicht mehr durchblicke, das ist schade, ich würde gern alles verstehen…

Doris