Ich möchte ein Befehlszeilenprogramm, das den Titel einer Website druckt. Zum Beispiel:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
sollte geben:
Why Are Bad Words Bad?
Sie geben ihm die URL und es druckt den Titel aus.
Ich möchte ein Befehlszeilenprogramm, das den Titel einer Website druckt. Zum Beispiel:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
sollte geben:
Why Are Bad Words Bad?
Sie geben ihm die URL und es druckt den Titel aus.
Antworten:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Sie können es an GNU weiterleiten, recode
wenn es Dinge wie <
diese gibt:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
recode html..
So entfernen Sie das - youtube
Teil:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)(?: - youtube)?\s*<\/title/si'
Um auf einige der Einschränkungen hinzuweisen:
Es gibt keinen Standardbefehl für HTTP-Abfragen. Vor ein paar Jahrzehnten hätte ich lynx -source
stattdessen hier empfohlen . Aber heutzutage wget
ist es portabler, da es standardmäßig auf den meisten GNU-Systemen (einschließlich der meisten Linux-basierten Desktop- / Laptop-Betriebssysteme) zu finden ist. Andere ziemlich portable sind der GET
Befehl perl
libwww, der häufig lynx -source
und in geringerem Umfang installiert wird curl
. Andere gemeinsam diejenigen umfassen links -source
, elinks -source
, w3m -dump_source
, lftp -c cat
...
wget
erhält möglicherweise nicht die gleiche Seite wie die, die zum Beispiel firefox
angezeigt werden würde. Der Grund dafür ist, dass HTTP-Server basierend auf den Informationen in der vom Client gesendeten Anforderung möglicherweise eine andere Seite senden.
Die von wget / w3m / GET ... gesendete Anfrage unterscheidet sich von der von firefox. Wenn dies ein Problem ist, können Sie das wget
Verhalten ändern, um die Art und Weise zu ändern, in der die Anforderung mit Optionen gesendet wird.
Die wichtigsten in dieser Hinsicht sind:
Accept
und Accept-language
: Hiermit wird dem Server mitgeteilt, in welcher Sprache und in welchem Zeichensatz der Client die Antwort erhalten möchte. wget
Standardmäßig wird keine Antwort gesendet, sodass der Server normalerweise mit den Standardeinstellungen sendet. firefox
am anderen Ende ist wahrscheinlich konfiguriert, um Ihre Sprache anzufordern.User-Agent
: Gibt die Clientanwendung gegenüber dem Server an. Einige Websites senden unterschiedliche Inhalte basierend auf dem Client (obwohl dies hauptsächlich auf Unterschiede zwischen den Interpretationen der Javascript-Sprache zurückzuführen ist) und lehnen es möglicherweise ab, Sie zu bedienen, wenn Sie einen Benutzeragenten vom Robotertyp wie verwenden wget
.Cookie
: Wenn Sie diese Seite schon einmal besucht haben, verfügt Ihr Browser möglicherweise über permanente Cookies. wget
wird nicht.wget
wird den Weiterleitungen folgen, wenn sie auf der HTTP-Protokollebene durchgeführt werden, aber da es nicht um den Inhalt der Seite geht, nicht um die von Javascript oder ähnlichen Dingen <meta http-equiv="refresh" content="0; url=http://example.com/">
.
Hier haben wir aus Faulheit perl
den gesamten Inhalt im Speicher gelesen, bevor wir nach dem <title>
Tag gesucht haben. Da sich der Titel in dem <head>
Abschnitt befindet, der sich in den ersten Bytes der Datei befindet, ist dies nicht optimal. Ein besserer Ansatz, wenn GNU awk
auf Ihrem System verfügbar ist, könnte sein:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
gawk -v IGNORECASE=1 -v RS='</title' 'RT{gsub(/.*<title[^>]*>/,"");print;exit}'
Auf diese Weise hört awk nach dem ersten Lesen auf </title
und führt beim Verlassen dazu, dass wget
der Download abgebrochen wird.
Hier wird wget
die Seite beim Herunterladen geschrieben. Gleichzeitig perl
schlürft output ( -0777 -n
) als Ganzes in den Speicher und druckt dann den HTML-Code, der zwischen den ersten Vorkommen von <title...>
und gefunden wird </title
.
Das funktioniert für die meisten HTML-Seiten mit einem <title>
Tag, aber es gibt Fälle, in denen es nicht funktioniert.
Im Gegensatz dazu analysiert die Lösung von coffeeMug die HTML-Seite als XML und gibt den entsprechenden Wert für zurück title
. Richtiger ist es, wenn garantiert wird, dass die Seite gültiges XML ist . HTML muss jedoch kein gültiges XML sein (ältere Sprachversionen waren dies nicht), und da die meisten Browser mild sind und falschen HTML-Code akzeptieren, gibt es sogar viele falsche HTML-Codes.
Sowohl meine Lösung als auch die von coffeeMug scheitern bei einer Vielzahl von Eckfällen , manchmal gleich, manchmal nicht.
Zum Beispiel wird meine am scheitern:
<html><head foo="<title>"><title>blah</title></head></html>
oder:
<!-- <title>old</title> --><title>new</title>
Während sein wird scheitern:
<TITLE>foo</TITLE>
(gültiges HTML, nicht XML) oder:
oder:
<title>...</title>
...
<script>a='<title>'; b='</title>';</script>
(wieder gültige html
, fehlende <![CDATA[
Teile, um es als gültiges XML zu kennzeichnen).
<title>foo <<<bar>>> baz</title>
(Falsches HTML, aber immer noch bekannt und von den meisten Browsern unterstützt)
Diese Lösung gibt den Rohtext zwischen <title>
und aus </title>
. Normalerweise sollten keine HTML-Tags enthalten sein, möglicherweise sind Kommentare vorhanden (obwohl dies von einigen Browsern wie Firefox nicht so wahrscheinlich ist). Möglicherweise ist noch eine HTML-Codierung vorhanden:
$ wget -qO- 'http://www.youtube.com/watch?v=CJDhmlMQT60' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Wallace & Gromit - The Cheesesnatcher Part 1 (claymation) - YouTube
Um was kümmert sich GNU recode
:
$ wget -qO- 'http://www.youtube.com/watch?v=CJDhmlMQT60' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
recode html..
Wallace & Gromit - The Cheesesnatcher Part 1 (claymation) - YouTube
Ein Web-Client ist jedoch auch dazu gedacht, den Code beim Anzeigen des Titels stärker zu transformieren (z. B. einige der Leerzeichen zu komprimieren, die führenden und nachfolgenden zu entfernen). Es ist jedoch unwahrscheinlich, dass dies erforderlich sein wird. Wie in den anderen Fällen müssen Sie entscheiden, ob sich die Mühe lohnt.
Vor UTF-8 war iso8859-1 der bevorzugte Zeichensatz im Web für Nicht-ASCII-Zeichen, obwohl genau genommen geschrieben werden musste é
. Neuere Versionen von HTTP und der HTML-Sprache haben die Möglichkeit hinzugefügt, den Zeichensatz in den HTTP-Headern oder in den HTML-Headern anzugeben, und ein Client kann die Zeichensätze angeben, die er akzeptiert. UTF-8 ist heutzutage der Standardzeichensatz.
Das bedeutet also, dass Sie dort draußen é
als é
, als é
, als UTF-8 é
, (0xc3 0xa9), als iso-8859-1 (0xe9), mit den 2 letzten, manchmal die Informationen auf dem Zeichensatz finden in den HTTP-Headern oder den HTML-Headern (in verschiedenen Formaten) manchmal nicht.
wget
Erhält nur die Rohbytes, kümmert sich nicht um deren Bedeutung als Zeichen und informiert den Webserver nicht über den bevorzugten Zeichensatz.
recode html..
kümmert sich darum, das é
oder é
in die richtige Folge von Bytes für den auf Ihrem System verwendeten Zeichensatz umzuwandeln , aber im übrigen ist das schwieriger.
Wenn Ihr Systemzeichensatz utf-8 ist, ist dies wahrscheinlich die meiste Zeit in Ordnung, da dies in der Regel der Standardzeichensatz ist, der heutzutage verwendet wird.
$ wget -qO- 'http://www.youtube.com/watch?v=if82MGPJEEQ' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Noir Désir - L'appartement - YouTube
Das é
oben war ein UTF-8 é
.
Aber wenn Sie noch einmal andere Zeichensätze abdecken möchten, müssten Sie sich darum kümmern.
Es sollte auch beachtet werden, dass diese Lösung für UTF-16- oder UTF-32-codierte Seiten überhaupt nicht funktioniert.
Idealerweise benötigen Sie hier einen echten Webbrowser, der Ihnen die Informationen liefert. Das heißt, Sie müssen die HTTP-Anforderung mit den richtigen Parametern ausführen, die HTTP-Antwort richtig interpretieren, den HTML-Code vollständig interpretieren, wie es ein Browser tun würde, und den Titel zurückgeben.
Da ich glaube, dass dies mit den Browsern, die ich kenne, auf der Kommandozeile nicht möglich ist (obwohl ich diesen Tricklynx
jetzt sehe ), muss man auf Heuristiken und Annäherungen zurückgreifen, und die obige ist so gut wie jede andere.
Vielleicht möchten Sie auch Leistung, Sicherheit usw. berücksichtigen, um alle Fälle abzudecken (z. B. eine Webseite, auf der Javascript von einer Website eines Drittanbieters abgerufen wurde, auf der der Titel oder die Weiterleitung zu einer anderen Seite in einer Website festgelegt ist) onload hook) müssen Sie möglicherweise einen realen Browser mit dom- und javascript-Modulen implementieren, der möglicherweise Hunderte von Abfragen für eine einzelne HTML-Seite ausführen muss, von denen einige versuchen, Schwachstellen auszunutzen ...
Während die Verwendung von regulären Ausdrücken zum Parsen von HTML häufig verpönt ist , ist hier ein typischer Fall, in dem es für die Aufgabe (IMO) gut genug ist.
<
da für Titel keine End-Tags garantiert sind und jedes andere Tag die Beendigung erzwingen sollte. Möglicherweise möchten Sie auch neue Leitungen entfernen.
Sie können hxselect
(aus HTML-XML-Utils ) wget
auch Folgendes versuchen :
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' | hxselect -s '\n' -c 'title' 2>/dev/null
Sie können installieren hxselect
Verwendung in Debian - basierten Distributionen:
sudo apt-get install html-xml-utils
.
Die STDERR-Umleitung dient zum Vermeiden der Input is not well-formed. (Maybe try normalize?)
Nachricht.
Um "- YouTube" loszuwerden, leiten Sie die Ausgabe des obigen Befehls an awk '{print substr($0, 0, length($0)-10)}'
.
sudo apt-get install html-xml-utils
hxselect
.
Sie können dazu auch curl
und grep
verwenden. Sie benötigen die Verwendung von gewinnen PCRE (Perl Compatible Regular Expressions) in grep
erhalten den Blick hinter und Vorgriff Einrichtungen , so dass wir die finden <title>...</title>
Tags.
$ curl 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -so - | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
Why Are Bad Words Bad? - YouTube
Die curl
Schalter:
-s
= leise-o -
= Ausgabe an STDOUT sendenDie grep
Schalter:
-i
= Groß- / Kleinschreibung-o
= Nur den Teil zurückgeben, der passt-P
= PCRE-ModusDas Muster zu grep
:
(?<=<title>)
= suche nach einer Zeichenkette, die links davon beginnt(?=</title>)
= suche nach einer Zeichenkette, die rechts davon endet(.*)
= alles dazwischen <title>..</title>
.Wenn es sich <title>...</titie>
über mehrere Zeilen erstreckt, wird es von den oben genannten nicht gefunden. Sie können diese Situation abmildern, indem Sie tr
beliebige \n
Zeichen löschen , z tr -d '\n'
.
Beispieldatei.
$ cat multi-line.html
<html>
<title>
this is a \n title
</TITLE>
<body>
<p>this is a \n title</p>
</body>
</html>
Und ein Probelauf:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
tr -d '\n' | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
this is a \n title
Wenn der <title>
so eingestellt ist, müssen <title lang="en">
Sie ihn entfernen, bevor grep
Sie ihn verwenden können. Das Tool sed
kann dazu verwendet werden:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
tr -d '\n' | \
sed 's/ lang="\w+"//gi' | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
this is a \n title
Oben wird die Zeichenfolge ohne Berücksichtigung der Groß- und Kleinschreibung lang=
gefolgt von einer Wortfolge ( \w+
) gefunden. Es wird dann ausgezogen.
Irgendwann gelingt es regex nicht mehr, diese Art von Problem zu lösen. In diesem Fall möchten Sie wahrscheinlich einen echten HTML / XML-Parser verwenden. Ein solcher Parser ist Nokogiri . Es ist in Ruby als Gem verfügbar und kann folgendermaßen verwendet werden:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
ruby -rnokogiri -e \
'puts Nokogiri::HTML(readlines.join).xpath("//title").map { |e| e.content }'
this is a \n title
Das obige analysiert die Daten, die über curl
as HTML ( Nokogiri::HTML
) kommen. Die Methode xpath
sucht dann im HTML nach Knoten (Tags), die Blattknoten ( //
) mit dem Namen sind title
. Für jedes gefundene Objekt möchten wir dessen Inhalt zurückgeben ( e.content
). Das puts
druckt sie dann aus.
Ähnliches können Sie auch mit Perl und dem HTML :: TreeBuilder :: XPath- Modul tun .
$ cat title_getter.pl
#!/usr/bin/perl
use HTML::TreeBuilder::XPath;
$tree = HTML::TreeBuilder::XPath->new_from_url($ARGV[0]);
($title = $tree->findvalue('//title')) =~ s/^\s+//;
print $title . "\n";
Sie können dieses Skript dann folgendermaßen ausführen:
$ ./title_getter.pl http://www.jake8us.org/~sam/multi-line.html
this is a \n title
<title>Unix\nLinux</title>
soll sein Unix Linux
, nicht UnixLinux
.
Die Verwendung von einfachem Regex zum Parsen von HTML ist naiv. ZB mit Zeilenumbrüchen und Ignorieren der in der Datei angegebenen Sonderzeichencodierung. Tun Sie das Richtige und analysieren Sie die Seite wirklich mit einem der anderen echten Parser, die in den anderen Antworten aufgeführt sind, oder verwenden Sie den folgenden Zeilenumbruch:
python -c "import bs4, urllib2; print bs4.BeautifulSoup(urllib2.urlopen('http://www.crummy.com/software/BeautifulSoup/bs4/doc/')).title.text"
(Das Obige enthält ein Unicode-Zeichen).
BeautifulSoup handhabt auch eine Menge von falschem HTML (z. B. fehlende schließende Tags), was eine völlig vereinfachte Regex-Darstellung zur Folge hätte. Sie können es in einem Standard-Python installieren, indem Sie Folgendes verwenden:
pip install beautifulsoup4
oder wenn nicht pip
, mit
easy_install beautifulsoup4
Einige Betriebssysteme wie Debian / Ubuntu haben es auch gepackt ( python-bs4
Paket unter Debian / Ubuntu).
bs4
ist nicht in der Python-Standardbibliothek. Sie müssen es mit easy_install beautfulsoup4
(nicht easyinstall bs4
) installieren .
Vielleicht ist es "Betrug", aber eine Option ist pup, ein HTML-Parser für die Befehlszeile .
Hier sind zwei Möglichkeiten:
Verwendung des meta
Feldes mit property="og:title
Attribut
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'meta[property=og:title] attr{content}'
Why Are Bad Words Bad?
und eine andere Möglichkeit, das title
Feld direkt zu verwenden (und dann die - YouTube
Zeichenfolge am Ende zu entfernen ).
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'title text{}' | sed 's/ - YouTube$//'
Why Are Bad Words Bad?
--plain
Option pup verwenden .
lynx
Mit diesem Trick ( zsh
, bash
Syntax) scheint es möglich zu sein :
lynx -cfg=<(printf '%s\n' 'PRINTER:P:printf "%0s\\n" "$LYNX_PRINT_TITLE">&3:TRUE'
) lynx 3>&1 > /dev/null -nopause -noprint -accept_all_cookies -cmd_script <(
printf '%s\n' "key p" "key Select key" "key ^J" exit
) 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc'
Da es sich um einen echten Webbrowser handelt, leidet er nicht unter den Einschränkungen, die ich in meiner anderen Antwort erwähne .
Hier verwenden wir die Tatsache, dass lynx
die $LYNX_PRINT_TITLE
Umgebungsvariable beim Drucken der Seite auf den Titel der aktuellen Seite gesetzt wird.
Oben sehen Sie eine Konfigurationsdatei (als Pipe), die einen Lynx - "Drucker" definiert P
, der nur den Inhalt dieser Variablen an den Dateideskriptor ausgibt 3
(dieser Dateideskriptor wird mit an lynx
die Standardausgabe umgeleitet, 3>&1
während lynx stdout selbst umgeleitet wird nach / dev / null).
Dann verwenden wir die lynx
Scripting-Funktion, um das Drücken des Benutzers p
und die End
Tasten (aka select) und Enter
( ^J
) zu simulieren .
-accept_all_cookies
da ansonsten lynx den benutzer für jedes cookie um bestätigung bitten würde.
Einfacher Weg:
curl -s example.com | grep -o "<title>[^<]*" | tail -c+8
Einige Alternativen:
curl -s example.com | grep -o "<title>[^<]*" | cut -d'>' -f2-
wget -qO- example.com | grep -o "<title>[^<]*" | sed -e 's/<[^>]*>//g'
Ich mochte die Idee von Stéphane Chazelas, Lynx und LYNX_PRINT_TITLE zu verwenden, aber dieses Skript funktionierte unter Ubuntu 14.04.5 nicht für mich.
Ich habe eine vereinfachte Version davon erstellt, indem ich Lynx ausgeführt und im Voraus vorkonfigurierte Dateien verwendet habe.
Fügen Sie die folgende Zeile zu /etc/lynx-cur/lynx.cfg hinzu (oder wo immer sich Ihre lynx.cfg befindet):
PRINTER:P:printenv LYNX_PRINT_TITLE>/home/account/title.txt:TRUE:1000
Diese Zeile weist Sie an, den Titel während des Druckvorgangs unter "/home/account/title.txt" zu speichern. Sie können einen beliebigen Dateinamen auswählen. Sie fordern SEHR große Seiten an. Erhöhen Sie den obigen Wert von "1000" auf eine beliebige Anzahl von Zeilen pro Seite. Andernfalls gibt Lynx eine zusätzliche Aufforderung aus, "wenn Sie ein Dokument drucken, das eine sehr große Anzahl von Seiten enthält".
Erstellen Sie dann die Datei /home/account/lynx-script.txt mit folgendem Inhalt:
key p
key Select key
key ^J
exit
Führen Sie dann Lynx mit den folgenden Befehlszeilenoptionen aus:
lynx -term=vt100 -display_charset=utf-8 -nopause -noprint -accept_all_cookies -cmd_script=/home/account/lynx-script.txt "http://www.youtube.com/watch?v=Dd7dQh8u4Hc" >/dev/nul
Nach Abschluss dieses Befehls wird die Datei /home/account/title.txt mit dem Titel Ihrer Seite erstellt.
Kurz gesagt, hier ist eine PHP-Funktion, die einen Seitentitel basierend auf der angegebenen URL zurückgibt oder im Fehlerfall false.
function GetUrlTitle($url)
{
$title_file_name = "/home/account/title.txt";
if (file_exists($title_file_name)) unlink($title_file_name); // delete the file if exists
$cmd = '/usr/bin/lynx -cfg=/etc/lynx-cur/lynx.cfg -term=vt100 -display_charset=utf-8 -nopause -noprint -accept_all_cookies -cmd_script=/home/account/lynx-script.txt "'.$url.'"';
exec($cmd, $output, $retval);
if (file_exists($title_file_name))
{
$title = file_get_contents($title_file_name);
unlink($title_file_name); // delete the file after reading
return $title;
} else
{
return false;
}
}
print GetUrlTitle("http://www.youtube.com/watch?v=Dd7dQh8u4Hc");
Mit nokogiri kann man eine einfache CSS-basierte Abfrage verwenden, um den inneren Text des Tags zu extrahieren:
$ nokogiri -e 'puts $_.at_css("title").content'
Why Are Bad Words Bad? - YouTube
So extrahieren Sie den Wert des Attributs "content" des Tags:
$ nokogiri -e 'puts $_.at_css("meta[name=title]").attr("content")'
Why Are Bad Words Bad?