Voglio un programma da riga di comando che stampa il titolo di un sito Web. Ad esempio:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
dovrebbe dare:
Why Are Bad Words Bad?
Gli dai l'url e stampa il titolo.
Voglio un programma da riga di comando che stampa il titolo di un sito Web. Ad esempio:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
dovrebbe dare:
Why Are Bad Words Bad?
Gli dai l'url e stampa il titolo.
Risposte:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Puoi inviarlo a GNU recode
se ci sono cose come <
:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
recode html..
Per rimuovere la - youtube
parte:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)(?: - youtube)?\s*<\/title/si'
Per evidenziare alcune delle limitazioni:
Non esiste un comando standard / portatile per eseguire query HTTP. Qualche decennio fa, avrei raccomandato lynx -source
invece qui. Ma al giorno d'oggi, wget
è più portatile in quanto può essere trovato di default sulla maggior parte dei sistemi GNU (incluso la maggior parte dei sistemi operativi desktop / laptop basati su Linux). Altri abbastanza portabili includono il GET
comando che viene fornito con perl
il libwww che viene spesso installato e lynx -source
, in misura minore curl
. Altri comuni quelli includono links -source
, elinks -source
, w3m -dump_source
, lftp -c cat
...
wget
potrebbe non avere la stessa pagina di quella visualizzata ad esempio firefox
. Il motivo è che i server HTTP possono scegliere di inviare una pagina diversa in base alle informazioni fornite nella richiesta inviata dal client.
La richiesta inviata da wget / w3m / GET ... sarà diversa da quella inviata da Firefox. Se questo è un problema, puoi modificare il wget
comportamento per cambiare il modo in cui invia la richiesta con le opzioni.
I più importanti qui a questo proposito sono:
Accept
e Accept-language
: questo indica al server in quale lingua e set di caratteri il client vorrebbe ottenere la risposta. wget
Non ne invia nessuna per impostazione predefinita, quindi il server in genere invia con le sue impostazioni predefinite. firefox
dall'altro lato è probabilmente configurato per richiedere la tua lingua.User-Agent
: identifica l'applicazione client sul server. Alcuni siti inviano contenuti diversi in base al client (anche se ciò è principalmente per le differenze tra le interpretazioni del linguaggio javascript) e possono rifiutare di servirti se stai utilizzando un agente utente di tipo robot come wget
.Cookie
: se hai già visitato questo sito, il tuo browser potrebbe avere cookie permanenti per questo. wget
no.wget
seguiranno i reindirizzamenti quando saranno eseguiti a livello di protocollo HTTP, ma poiché non guarda il contenuto della pagina, non quelli fatti da JavaScript o cose del genere <meta http-equiv="refresh" content="0; url=http://example.com/">
.
Qui, per pigrizia, abbiamo perl
letto l'intero contenuto in memoria prima di iniziare a cercare il <title>
tag. Dato che il titolo si trova nella <head>
sezione che si trova nei primi byte del file, non è ottimale. Un approccio migliore, se GNU awk
è disponibile sul tuo sistema potrebbe essere:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
gawk -v IGNORECASE=1 -v RS='</title' 'RT{gsub(/.*<title[^>]*>/,"");print;exit}'
In questo modo, awk smette di leggere dopo il primo </title
e, uscendo, fa wget
interrompere il download.
Qui, wget
scrive la pagina mentre la scarica. Allo stesso tempo, perl
assorbe l' -0777 -n
intero output ( ) in memoria e quindi stampa il codice HTML che si trova tra le prime occorrenze di <title...>
e </title
.
Funzionerà con la maggior parte delle pagine HTML che hanno un <title>
tag, ma ci sono casi in cui non funzionerà.
Al contrario, la soluzione di coffeeMug analizzerà la pagina HTML come XML e restituirà il valore corrispondente per title
. È più corretto se la pagina è garantita come XML valido . Tuttavia, non è necessario che l'HTML sia un codice XML valido (non lo erano le versioni precedenti della lingua) e poiché la maggior parte dei browser là fuori sono indulgenti e accettano codice HTML errato, c'è anche un sacco di codice HTML errato là fuori.
Sia la mia soluzione che quella di CoffeeMug falliranno per una varietà di casi angolari, a volte uguali, a volte no.
Ad esempio, il mio fallirà su:
<html><head foo="<title>"><title>blah</title></head></html>
o:
<!-- <title>old</title> --><title>new</title>
Mentre la sua volontà fallirà:
<TITLE>foo</TITLE>
(html valido, non xml) o:
o:
<title>...</title>
...
<script>a='<title>'; b='</title>';</script>
(di nuovo, parti html
mancanti <![CDATA[
e valide per renderlo XML valido).
<title>foo <<<bar>>> baz</title>
(HTML non corretto, ma ancora scoperto e supportato dalla maggior parte dei browser)
Tale soluzione genera il testo non elaborato tra <title>
e </title>
. Normalmente, non dovrebbero esserci tag HTML, potrebbero esserci dei commenti (anche se non gestiti da alcuni browser come Firefox in modo molto improbabile). Potrebbe esserci ancora della codifica HTML:
$ 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
Di cui si occupa 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
Ma un client web ha anche lo scopo di fare più trasformazioni su quel codice quando visualizza il titolo (come condensare alcuni degli spazi vuoti, rimuovere quelli iniziali e finali). Tuttavia è improbabile che ce ne sia bisogno. Quindi, come negli altri casi, sta a te decidere se valga la pena.
Prima di UTF-8, iso8859-1 era il set di caratteri preferito sul web per i caratteri non ASCII anche se a rigor di termini dovevano essere scritti come é
. Versioni più recenti di HTTP e del linguaggio HTML hanno aggiunto la possibilità di specificare il set di caratteri nelle intestazioni HTTP o nelle intestazioni HTML e un client può specificare i set di caratteri che accetta. Oggi UTF-8 tende a essere il set di caratteri predefinito.
Quindi, ciò significa che là fuori troverai é
scritte come é
, come é
, come UTF-8 é
, (0xc3 0xa9), come iso-8859-1 (0xe9), con per le ultime 2, a volte le informazioni sul set di caratteri nelle intestazioni HTTP o nelle intestazioni HTML (in diversi formati), a volte no.
wget
ottiene solo i byte grezzi, non si preoccupa del loro significato come caratteri e non dice al server web il set di caratteri preferito.
recode html..
si occuperà di convertire é
o é
nella sequenza corretta di byte per il set di caratteri utilizzato nel sistema, ma per il resto è più complicato.
Se il tuo set di caratteri di sistema è utf-8, è probabile che vada bene per la maggior parte del tempo in quanto tende ad essere il set di caratteri predefinito usato al giorno d'oggi.
$ 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
Quello é
sopra era un UTF-8 é
.
Ma se vuoi coprire per altri set di caratteri, ancora una volta, dovrebbe essere curato.
Va anche notato che questa soluzione non funzionerà affatto per le pagine codificate UTF-16 o UTF-32.
Idealmente, quello che ti serve qui, è un vero browser web per darti le informazioni. Cioè, è necessario qualcosa per eseguire la richiesta HTTP con i parametri corretti, interpretare correttamente la risposta HTTP, interpretare completamente il codice HTML come farebbe un browser e restituire il titolo.
Dato che non credo che ciò possa essere fatto sulla riga di comando con i browser che conosco (anche se vedi ora questo trucco conlynx
), devi ricorrere a euristiche e approssimazioni, e quella sopra è buona come una qualsiasi.
Potresti anche prendere in considerazione le prestazioni, la sicurezza ... Ad esempio, per coprire tutti i casi (ad esempio, una pagina web che ha un javascript estratto da un sito di terze parti che imposta il titolo o reindirizza a un'altra pagina in un onload hook), potresti dover implementare un browser di vita reale con i suoi motori dom e javascript che potrebbero dover fare centinaia di query per una singola pagina HTML, alcune delle quali cercano di sfruttare le vulnerabilità ...
Mentre l' utilizzo di regexps per analizzare l'HTML è spesso disapprovato , ecco un caso tipico in cui è abbastanza buono per l'attività (IMO).
<
poiché non è garantito che i titoli abbiano tag di fine e qualsiasi altro tag dovrebbe forzarne la chiusura. Potresti anche voler eliminare nuove righe.
Puoi anche provare hxselect
(da HTML-XML-Utils ) wget
come segue:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' | hxselect -s '\n' -c 'title' 2>/dev/null
È possibile installare hxselect
in distribuzioni basate su Debian utilizzando:
sudo apt-get install html-xml-utils
.
Il reindirizzamento STDERR è per evitare il Input is not well-formed. (Maybe try normalize?)
messaggio.
Per eliminare "- YouTube", reindirizzare l'output del comando sopra awk '{print substr($0, 0, length($0)-10)}'
.
sudo apt-get install html-xml-utils
hxselect
.
Puoi anche usare curl
e grep
fare questo. Avrete bisogno di arruolare l'uso di PCRE (Perl Compatible Regular Expressions) in grep
per ottenere l'aspetto e le strutture dietro guardare avanti in modo che possiamo trovare i <title>...</title>
tag.
$ curl 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -so - | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
Why Are Bad Words Bad? - YouTube
Gli curl
interruttori:
-s
= silenzioso-o -
= invia output a STDOUTGli grep
interruttori:
-i
= insensibilità al caso-o
= Restituisce solo la parte corrispondente-P
= Modalità PCRELo schema per grep
:
(?<=<title>)
= cerca una stringa che inizia con questa alla sua sinistra(?=</title>)
= cerca una stringa che termina con questa alla sua destra(.*)
= tutto in mezzo <title>..</title>
.Se si <title>...</titie>
estende su più righe, non verrà trovato quanto sopra. È possibile mitigare questa situazione utilizzando tr
, per eliminare qualsiasi \n
carattere, ad es tr -d '\n'
.
File di esempio.
$ cat multi-line.html
<html>
<title>
this is a \n title
</TITLE>
<body>
<p>this is a \n title</p>
</body>
</html>
E una corsa di esempio:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
tr -d '\n' | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
this is a \n title
Se l' <title>
opzione è impostata in questo modo, <title lang="en">
dovrai rimuoverla prima di grep
inserirla. Lo strumento sed
può essere usato per fare questo:
$ 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
Quanto sopra trova la stringa insensibile al maiuscolo lang=
seguita da una sequenza di parole ( \w+
). Viene quindi rimosso.
Ad un certo punto regex non riuscirà a risolvere questo tipo di problema. In tal caso, ti consigliamo di utilizzare un vero parser HTML / XML. Uno di questi parser è Nokogiri . È disponibile in Ruby come gemma e può essere utilizzato in questo modo:
$ 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
Quanto sopra sta analizzando i dati che arrivano via curl
come HTML ( Nokogiri::HTML
). Il metodo xpath
quindi cerca i nodi (tag) nell'HTML che sono nodi foglia, ( //
) con il nome title
. Per ogni trovato vogliamo restituire il suo contenuto ( e.content
). L' puts
poi li stampa.
Puoi anche fare qualcosa di simile con Perl e il modulo HTML :: TreeBuilder :: XPath .
$ 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";
È quindi possibile eseguire questo script in questo modo:
$ ./title_getter.pl http://www.jake8us.org/~sam/multi-line.html
this is a \n title
<title>Unix\nLinux</title>
è pensato per essere Unix Linux
, no UnixLinux
.
L'uso di regex semplice per analizzare HTML è ingenuo. Ad esempio con newline e ignorando la codifica dei caratteri speciali specificata nel file. Fai la cosa giusta e analizza davvero la pagina usando uno degli altri parser reali menzionati nelle altre risposte o usa la seguente riga:
python -c "import bs4, urllib2; print bs4.BeautifulSoup(urllib2.urlopen('http://www.crummy.com/software/BeautifulSoup/bs4/doc/')).title.text"
(Quanto sopra include un carattere Unicode).
BeautifulSoup gestisce anche molti HTML non corretti (ad es. Tag di chiusura mancanti), che eliminerebbero completamente la regexing semplicistica. Puoi installarlo in un pitone standard usando:
pip install beautifulsoup4
o se non ce l'hai pip
, con
easy_install beautifulsoup4
Alcuni sistemi operativi come Debian / Ubuntu hanno anche pacchetti ( python-bs4
pacchetto su Debian / Ubuntu).
bs4
non si trova nella libreria standard di Python. Devi installarlo usando easy_install beautfulsoup4
(non easyinstall bs4
).
Forse è "imbroglione" ma un'opzione è pup, un parser HTML da riga di comando .
Ecco due modi per farlo:
Utilizzo del meta
campo con property="og:title
attributo
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'meta[property=og:title] attr{content}'
Why Are Bad Words Bad?
e in un altro modo usando title
direttamente il campo (e poi staccando la - YouTube
stringa alla fine).
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'title text{}' | sed 's/ - YouTube$//'
Why Are Bad Words Bad?
--plain
opzione pup .
Sembra essere possibile lynx
usando questo trucco ( zsh
, bash
sintassi):
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'
Poiché si tratta di un browser Web reale, non presenta molti dei limiti che menziono nell'altra mia risposta .
Qui, stiamo usando il fatto che lynx
imposta la $LYNX_PRINT_TITLE
variabile di ambiente sul titolo della pagina corrente quando si stampa la pagina.
Sopra, stiamo dando un file di configurazione (come una pipe) che definisce una "stampante" di lince chiamata P
che invia semplicemente il contenuto di quella variabile al descrittore di file 3
(quel descrittore di file viene reindirizzato allo lynx
stdout con 3>&1
mentre lo stdout di lince viene reindirizzato a / dev / null).
Quindi usiamo la funzione di lynx
scripting per simulare la pressione dell'utente p
, e End
(aka select) e Enter
( ^J
).
-accept_all_cookies
come altrimenti lynx chiederebbe all'utente la conferma di ogni cookie.
Modo semplice:
curl -s example.com | grep -o "<title>[^<]*" | tail -c+8
Poche alternative:
curl -s example.com | grep -o "<title>[^<]*" | cut -d'>' -f2-
wget -qO- example.com | grep -o "<title>[^<]*" | sed -e 's/<[^>]*>//g'
Mi è piaciuta l'idea di Stéphane Chazelas di usare Lynx e LYNX_PRINT_TITLE, ma quello script non ha funzionato per me con Ubuntu 14.04.5.
Ne ho realizzato una versione semplificata usando Lynx e usando i file preconfigurati in anticipo.
Aggiungi la seguente riga a /etc/lynx-cur/lynx.cfg (o ovunque risieda il tuo lynx.cfg):
PRINTER:P:printenv LYNX_PRINT_TITLE>/home/account/title.txt:TRUE:1000
Questa riga indica di salvare il titolo, durante la stampa, in "/home/account/title.txt" - puoi scegliere qualsiasi nome di file desideri. Richiedete pagine MOLTO grandi, aumentate il valore di cui sopra da "1000" a qualsiasi numero di righe per pagina desiderate, altrimenti Lynx farà ulteriori richieste "durante la stampa di documenti contenenti un numero molto elevato di pagine".
Quindi creare il file /home/account/lynx-script.txt con i seguenti contenuti:
key p
key Select key
key ^J
exit
Quindi eseguire Lynx utilizzando le seguenti opzioni della riga di comando:
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
Al completamento di questo comando, il file /home/account/title.txt verrà creato con il titolo della tua pagina.
Per farla breve, ecco una funzione PHP che restituisce il titolo di una pagina in base all'URL indicato o false in caso di errore.
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");
Utilizzando nokogiri, è possibile utilizzare una semplice query basata su CSS per estrarre il testo interno del tag:
$ nokogiri -e 'puts $_.at_css("title").content'
Why Are Bad Words Bad? - YouTube
Allo stesso modo, per estrarre il valore dell'attributo "contenuto" del tag:
$ nokogiri -e 'puts $_.at_css("meta[name=title]").attr("content")'
Why Are Bad Words Bad?