webForumDet fria alternativet

Hämta ut Title ur en HTML fil, går det?

Perl & Ruby

17 svar · 1 778 visningar · startad av haider

Medlem sedan jan. 2003956 inlägg
Frågan#1

Hej kära tomma Perl-forumet. :-)

Jag har ett attribut som heter $title = och sedan bland annat följande kodsnutt:

$query = $ENV{'QUERY_STRING'};
($name, $value) = split(/==/, $query);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;

genom att printa ut $FORM{url} så kan jag få med filnamnet på den fil som anges i query strängen.
Kan man utläsa <title> taggen ur samma fil, och använda den till B]$title = som jag nämner ovan?

Tacksam för svar - man kan ju alltid hoppas på att det spökar här i CGI-forumet :p

Medlem sedan juni 20004 308 inlägg
#2

Nej, du måste först läsa in dokumentet. Kommer du bara åt det via http kan du använda lwp för att läsa det och html::headparser för att läsa i head;

use LWP::Simple;
use HTML::HeadParser;
my $p = HTML::HeadParser->new;
$p->parse(get($FORM{'url'}));

print $p->header('Title');

... om du har en komplett url i $FORM{'url'}.

Medlem sedan jan. 2003956 inlägg
#3

Tack Johan! När landet står tomt, så är du den som är kvar o vallar oss vilsna själar till rätta :p

Alltså, när du skriver "om du har en komplet url i $FORM{'url'}" - så förutsätter jag att jag får det, när jag har en sökväg i stil med:

https://www.sidan.se/cgi-bin/link.cgi?url==/en_sida.html

Eller?

Var någonstans ska jag klämma in din kod i förhållande till:

print "Content-type:text/html\n\n";

$query = $ENV{'QUERY_STRING'};
($name, $value) = split(/==/, $query);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;

print "<HTML>\n<HEAD>\n<meta name=\"description\" content=\"$meta_desc\">\n";
print "<meta name=\"keywords\" content=\"$meta_keywords\">\n<TITLE>$title</TITLE>\n</HEAD>\n";
print "<frameset cols=\"*,1000,*\"  frameborder=\"no\" border=\"0\" framespacing=\"0\">\n<frame src=\"\">\n";
print "<frameset rows=\"*,$frame_height\" frameborder=\"no\" border=\"0\" framespacing=\"0\">\n";
print "  <frame src=\"$FORM{url}\" name=\"mainFrame\" scrolling=\"yes\">\n";
print "  <frame src=\"$static_frame\" name=\"bottomFrame\" scrolling=\"No\" noresize=\"noresize\">\n";
print "</frameset>\n<frame src=\"\">\n</frameset>\n";
print "<noframes>\nSorry your browser does not support frames please<a href=\"$FORM{url}\">click here</a>.\n";
print "</NOFRAMES>\n</html>\n\n";

exit;

För övrigt, jag är mycket bristfällig i CGI; jag begriper det inte lika mkt som JS:

Angående "print $p->header('Title');", betyder det att jag ska strunta i att printa ut <TITLE>$title</TITLE>

Observera att $title och andra variabler anges lite tidigare i CGI-scriptet i stil med:

$title = "En titel";

tack för att du tar dig tiden.

Medlem sedan juni 20004 308 inlägg
#4

Vi kan ju enklast modifiera mitt exempel så du bara kan lägga in det i din kod:

print "Content-type:text/html\n\n";

$query = $ENV{'QUERY_STRING'};
($name, $value) = split(/==/, $query);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$FORM{$name} = $value;

[b]use LWP::Simple;
use HTML::HeadParser;
my $p = HTML::HeadParser->new;
$p->parse(get($FORM{'url'}));
$title=$p->header('Title');[/b]

print "<HTML>\n<HEAD>\n<meta name=\"description\" content=\"$meta_desc\">\n";
print "<meta name=\"keywords\" content=\"$meta_keywords\">\n<TITLE>$title</TITLE>\n</HEAD>\n";
print "<frameset cols=\"*,1000,*\"  frameborder=\"no\" border=\"0\" framespacing=\"0\">\n<frame src=\"\">\n";
print "<frameset rows=\"*,$frame_height\" frameborder=\"no\" border=\"0\" framespacing=\"0\">\n";
print "  <frame src=\"$FORM{url}\" name=\"mainFrame\" scrolling=\"yes\">\n";
print "  <frame src=\"$static_frame\" name=\"bottomFrame\" scrolling=\"No\" noresize=\"noresize\">\n";
print "</frameset>\n<frame src=\"\">\n</frameset>\n";
print "<noframes>\nSorry your browser does not support frames please<a href=\"$FORM{url}\">click here</a>.\n";
print "</NOFRAMES>\n</html>\n\n";

exit;

... och din URL ser komplett ut, antar att du har http:// före.

Medlem sedan jan. 2003956 inlägg
#5

problem

Du, måste url:en vara helt komplett?
Så som jag körde innan, så räckte det med att URLen var utformad enligt tex: "/dir/file.html" så funkade det i detta sammanhang.

Jag kör alltid den korta versionen, för att spara på adressen.
Kanske ska man skriva in "http://www.domänen.se" manuellt så att den skrivs ut i cgi-scriptet?

För kanske de kommandon du har i din kod kräver en komplett URL?

tillägg: jag får nämligen ett Internal Server Error

Medlem sedan feb. 2000438 inlägg
#6

LWP::Simple fungerar ungefär som en webbläsare, det vill säga att den kräver en komplett url. Om du istället läser in filen i en variabel kan du få <title> genom (om $document innehåller hela htmlfilen):

my ($title) = $document =~ m{<title>([^<]*?)</title>}i;
Medlem sedan jan. 2003956 inlägg
#7

Csson: Kanske du kan förklara hur jag kombinerar samman din kod med Jojoxx?

Det betyder väl att jag inte kör med $title=$p->header('Title');, men att bara ersätta raden med din kod räcker inte heller?

Hur gör man för att foga samman allt?

Medlem sedan feb. 2000438 inlägg
#8

Om du i $FORM{'url'} har en fungerande sökväg till en lokal fil kan du byta ut det fetstilta i Jojoxx inlägg från igår till:

open my $htmlfile, '<', $FORM{'url'} or die $!;
    my $document = do { local $/; <$htmlfile> };
close $htmlfile or die $!;

my ($title) = $document =~ m{<title>([^<]*?)</title>}i;

Helt otestat men det borde funka :).

Medlem sedan juni 20004 308 inlägg
#9

haider skrev:

tillägg: jag får nämligen ett Internal Server Error

Det kan vara så att någon av modulerna saknas. Kolla i loggen och se vad du har för felmeddelande.

Tar vi bort HTML::HeadParser (vet inte hur vanlig den är) och kombinerar med Cssons exempel:

use LWP::Simple;
my $document = get($FORM{'url'});
my ($title) = $document =~ m{<title>([^<]*?)</title>}i;
Medlem sedan jan. 2003956 inlägg
#10

Jag tror inte jag kan se loggen, för jag har ju mina filer på ett webbhotell. Eller kan jag?

Så snart jag har med raden use LWP::Simple; så blir det problem.
Tar jag bort den, så kommer inte "Internal Server Error 500", men det händer heller inte mycket mer.

Jag håller på med en parallell lösning, med JS, kanske kommer jag att satsa på javascript istället.

Medlem sedan juni 20004 308 inlägg
#11

Webhotell brukar ge tillgång till loggfiler på olika sätt, vanligast via ftp eller ett admin-interface via http.

Då kan du i princip vara säker på att modulen lwp::simple inte finns installerad. Fråga ditt webhotell om du inte kan lägga till den. Den är rättså smidig att ha.

Medlem sedan jan. 2003956 inlägg
#12

Eine Idee doch!

Du verkar övertygad, och allt lutar åt det hållet som du nämner.

Men krävs det verkligen att man har lwp::simple installerad?
Om jag som amatör i CGI gör en jämförelse med JS, så kan man ganska lätt lösa title-grejen i JS.

Anledningen till att jag skulle vilja se det lösas i CGi är för att CGI är det som körs allra först.

Förresten, kan CGI avläsa referrer-data och "ta med sig den" vidare så att sidor skapta med CGI (som ovanstående process) kan ta del av referrer datan?

Alltså: position 1, Google > position 2, en sida, som location.replace-ar till CGI > position 3, ny sida med komplett frameset.

Jag fick ganska smarta tips av Nitro i JS sidan, men de byggde på att man lassade över referrer datan mellan position 1 o 3 genom att flytta referrer datan upp till URLen. Nu så har jag lagt hans tips på paus, eftersom detta här CGI scriptet inte kan separera URL datan från referrer datan.

Så ser URLen ut med JS lösningen:
www.domain.se/cgi-bin/link.cgi?url==/sidan.html**&referrer==www.google.se/blah**

Rött är alltså URL datan endast och blått är referrer datan.
Vad scriptet alltså gör, är att klämma in allting i $FORM{url} vilket ju inte var tanken.

Så, frågan är om CGI kan läsa ut referrer data...

Medlem sedan aug. 2000374 inlägg
#13

haider skrev:

[...] Anledningen till att jag skulle vilja se det lösas i CGi är för att CGI är det som körs allra först.

Tyvärr går det inte att lösa någonting i CGI, CGI är en standard (RFC 3875) för hur webservar kommunicerar med externa program, inte ett programmerings språk. Perl har inte mer gemensamt med CGI än C, C++, PHP eller andra programmerings språk.

haider skrev:

[...] Så, frågan är om CGI kan läsa ut referrer data...

Referer fältet är ett standard HTTP huvud fält definierat i RFC 2616 14.36. CGI standarden definierar detta fält som ett meta protokoll fält vilket innebär att det ska ha prefixet HTTP_ i miljö variabeln.

Notera att det är Referer inte Referrer, detta tack vare en felstavning i en tidigare HTTP specifikation.

my $referrer = $ENV{HTTP_REFERER};
Medlem sedan jan. 2003956 inlägg
#14

Tack Hansen.

Angående "Perl har inte mer gemensamt med CGI än ..." - kanske är det jag som i min brist på kunskap uttryckte mig fel? När jag säger "CGI" så menar jag förstås Perl, för det är väl alltid perl som används i script med ändelsen .pl, eller? Eller är det två skilda saker?

Angående:

my $referrer = $ENV{HTTP_REFERER};

Då betyder det att perl/cgi (herregud, nu vet jag inte vad jag ska kalla det för :) ) klarar att läsa ut referern (med ett R alltså)?
Eftersom scriptet skapar en ny sida, en sida med ett frameset - Isåfall, kan man på nåt sätt göra så att den referer som utlästes tidigare blir den skapta sidans referer? Så att ett js-script som kör "document.referrer" läser ut den datan?

Om du har en möjlighet att berätta för mig hur koden ser ut, så vore jag mycket tacksam, så kan jag bara implentera den i cgi-scriptet ovan.

Medlem sedan aug. 2000374 inlägg
#15

haider skrev:

[...] När jag säger "CGI" så menar jag förstås Perl

Det är inte ovanligt att dessa två blandas ihop, många tror att CGI är Perl och tvärtom, men det är fel. Som sagt tidigare CGI är simpel standard för hur webservern kommunicerar med externa program med hjälp av miljö variabler, standard input, standard output och standard error. Det går alldeles utmärkt att skapa CGI program med Perl, vilket du redan har gjort.

                HTTP                   CGI
+-----------+          +-----------+         +---------+
|           | -------> |           | ------> |         |
| webläsare |          | webserver |         | program |
|           | <------- |           | <------ |         |
+-----------+          +-----------+         +---------+

Webläsaren skickar en HTTP begäran till servern som omvandlar denna till en CGI begäran vilket programmet bearbetar enligt CGI standarden. Programmet svarar med en CGI respons som webservern omvandlar till en HTTP respons som webläsaren svaras med.

haider skrev:

[...] för det är väl alltid perl som används i script med ändelsen .pl, eller? Eller är det två skilda saker?

Perl program/script associeras ofta med filändelserna pl, plx, cgi och moduler med pm.

cgi används om det är ett CGI program, detta för a webservern ska kunna "veta" att det är ett program som "förstår" CGI. Värt att påpeka att cgi filändelsen inte är unik för Perl utan delas med alla programmerings språk.

haider skrev:

[...]Då betyder det att perl/cgi (herregud, nu vet jag inte vad jag ska kalla det för :) ) klarar att läsa ut referern (med ett R alltså)?

Korrekt :)

haider skrev:

Eftersom scriptet skapar en ny sida, en sida med ett frameset - Isåfall, kan man på nåt sätt göra så att den referer som utlästes tidigare blir den skapta sidans referer? Så att ett js-script som kör "document.referrer" läser ut den datan?

Om du har en möjlighet att berätta för mig hur koden ser ut, så vore jag mycket tacksam, så kan jag bara implentera den i cgi-scriptet ovan.

Visst kan jag hjälpa dig, men fört måste jag förstå vad du vill åstadkomma. Ta två steg tillbaka och förklara vad du vill åstadkomma istället för peka ut ett specifikt del problem.

Medlem sedan jan. 2003956 inlägg
#16

Hansen; tack för ditt schyssta svar. Tack för att du tog tid tiden. Nå, detta var långt större än jag trott, men din förklaring kastar lite ljus på problemet.

I grund och botten så ser problemet ut såhär:
På grund av ett system som jag använder till en webbshop tvingades jag byta över till framesystem. Webbshopmekanismen klarade inte att lagra köpen i cookies eller motsvarande, därför fick man inte lov att ladda om sidan (och shoppen) för då skulle varukorgen tömmas.
Så jag bytte alltså till frames.

Frames ledde till ett annat bekypper, men sökmotoroptimering och annat.
När en besökare går in i en sida som i själva verket ska finnas i ett frameset, så körs ett javascript. En if-sats som gör if self.location == top.location, så ersätts location med:

https://www.sidan.se/cgi-bin/link.cgi?url==/sidan.html

På så vis skapar scripet (sorry, men jag fattar tyvärr fortfarande inte till 100 om min ovanstående lösning är perl eller cgi :r ) en framemiljö och klämmer in sidan som angivits i URLen i någon av src (det framgår i scriptet som du säkert sett).

Tracker/statistics till sidan: En normal "Entry" in till sidan genom index-filen, är inte nåt problem för trackern, för jag kan ta fram referrern åt tracking-sciptet genom att läsa in det med parent.document.referrer (javascript).

Däremot, om jag kör CGI-sciptet och på ett visuellt sätt skapar ett frameset, så funkar inte parent längre, eftersom processen ser ut så:

1. Webben/google
2. Sida utanför frame (innehåller referrer-data), javascript körs för att anropa CGI-scriptet
3. framesettet färdigbyggt och sidan ligger tillrätta inne i någon frame

Lösningen rent teoretiskt skulle kunna vara att jag vid punkt 2, när jag kör CGI-scriptet, så lagrar CGI-scriptet referrer data som den "spottar" ut vid punkt 3, så att man vid punkt3 åter kan komma åt referrer med javascript.

Om du kan JS så kan du titta här för lite bakgrundsinfo som en parantes:
http://www.webforum.nu/showthread.php?p=1160307#post1160307
Här har Nitro gett mig ett tips där man ur URLen kan bryta ut information som man "gör om" till referrer-data.
Han hade med ett JS som jag inte testat ännu (pga en brist i mitt CGI script (jag kan berätta om problemet om du vill)) men jag gissar att det är till för att läsa ut data ur querysträngen.

Om teorin funkar, att man kan "lassa över" referrer-data så som jag beskriver, så bör det väl funka att läsa ut den med gammal hederlig document.referrer i javascript?
Om det går - gör det det? Det är du som är experten. Jag är bara en teknikgalning som oftast letar efter de mest dramatiska lösningar (tar mig vatten över huvudet ;) )

Snälla, skriv om jag är helt otydlig, eller nåt.

Medlem sedan aug. 2000374 inlägg
#17

Testa med detta scriptet:

#!/usr/bin/perl

use strict;
use warnings;

use CGI;

my $cgi     = CGI->new;
my $url     = $cgi->param('url')     || 'Inte angiven';
my $referer = $cgi->param('referer') || 'Inte angiven';

print $cgi->header( -type => 'text/html' );
print <<EOF;
<html>
  <head>
    <title>Testar CGI.pm</title>
  </head>
  <body>
     <p>url: $url</p>
     <p>referer: $referer</p>
  </body>
</html>
EOF

Anropa scriptet med något liknande:

http://host/cgi-bin/script.cgi?url=%2Fen_sida.html&referer=http%3A%2F%2Fwww.webforum.nu%2F

Det är viktigt att urlen är rätt kodad, använd JavaScripts encodeURI.

Något kortfattat svar, men har tyvärr lite bråttom. Testa och fråga om du undrar något eller stöter på problem.

Medlem sedan jan. 2003956 inlägg
#18

Jag fick det inte att funka.
Kan det vara så att dessa rader kräver nåt slags "tillägg" till CGI, precis som Jojoxx nämner en saknad modul tidigare?

use strict;
use warnings;

use CGI;

Nu fick jag visserligen inte riktigt svar på mina funderingar, om hurvida cgi/perl klarar av att ta en referrer (som man med javascript kan utläsa) och gör den tillgänglig "flera sidor senare", så att man återigen kan utläsa med javascript.

I väntan på att ovanstående besvaras (vare sig det går eller inte), så undrar jag hur detta kan lösas:

När sökvägen ser ut så här:
https://www.domain.se/cgi-bin/link.cgi?url==/sidan.html&referrer==www.google.se/blah
Så blir det problem med denna raden:

print "  <frame src=\"$FORM{url}\" name=\"mainFrame\" scrolling=\"yes\">\n";

eftersom $FORM{url} får strukturen "/sidan.html&referrer==www.google.se/blah" när jag endast behöver ha "/sidan.html".

Äni idea? Men om det går, så hjälp mig med ett förslag som inte ställer krav på moduler eller liknande... :r

270 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
117 ms — deklarationer (db)
0 ms — hämta statistik (cache)
145 ms — hämta tråd, inlägg och bilagor (db)
123 ms — ändringar (db)