Come posso ottenere un titolo di un sito Web utilizzando la riga di comando?


50

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.


2
Quando scarico quel titolo ottengo: "Why Are Bad Words Bad? - Youtube", vuoi che anche "- Youtube" venga troncato?
slm

Risposte:


44
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 recodese ci sono cose come &lt;:

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 - youtubeparte:

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:

portabilità

Non esiste un comando standard / portatile per eseguire query HTTP. Qualche decennio fa, avrei raccomandato lynx -sourceinvece 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 GETcomando che viene fornito con perlil 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...

Protocollo HTTP e gestione del reindirizzamento

wgetpotrebbe 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 wgetcomportamento per cambiare il modo in cui invia la richiesta con le opzioni.

I più importanti qui a questo proposito sono:

  • Accepte Accept-language: questo indica al server in quale lingua e set di caratteri il client vorrebbe ottenere la risposta. wgetNon ne invia nessuna per impostazione predefinita, quindi il server in genere invia con le sue impostazioni predefinite. firefoxdall'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. wgetno.

wgetseguiranno 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/">.

Performance / efficienza

Qui, per pigrizia, abbiamo perlletto 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 </titlee, uscendo, fa wgetinterrompere il download.

Analisi dell'HTML

Qui, wgetscrive la pagina mentre la scarica. Allo stesso tempo, perlassorbe l' -0777 -nintero 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 htmlmancanti <![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)

interpretazione del codice all'interno dei tag.

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 &amp; 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.

Set di caratteri

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 &eacute;. 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 &eacute;, come &#233;, 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 &eacute;o &#233;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&#39;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.

Per riassumere

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).


Scarica anche le immagini dalle pagine? Inoltre lascerà indietro i file html di posta indesiderata?
Ufoguy,

2
Probabilmente si desidera terminare il titolo nella prima istanza di <poiché non è garantito che i titoli abbiano tag di fine e qualsiasi altro tag dovrebbe forzarne la chiusura. Potresti anche voler eliminare nuove righe.
Brian Nickel

1
Non è consigliabile utilizzare espressioni regolari per analizzare HTML. Mai. Nemmeno in questo caso. È una cattiva abitudine. Utilizzare invece un vero parser. C'è una famosa risposta Stackoverflow umoristica su questo ...
Robin Green,

4
@RobinGreen Quel post riguardava l'uso di regex per analizzare una lingua non regolare. Ci sono avvertenze, ma questo è un problema che può essere facilmente ridotto a un linguaggio normale. Consiglio di usare regex per analizzare HTML. A volte. In questo caso.
Brian Nickel

2
E il numero di espressioni regolari che funzionano per quasi tutto è circa 0.
Robin Green

27

Puoi anche provare hxselect(da HTML-XML-Utils ) wgetcome segue:

wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' | hxselect -s '\n' -c  'title' 2>/dev/null

È possibile installare hxselectin 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)}'.


"hxselect" non sembra essere installato su Ubuntu per impostazione predefinita. Non riesco nemmeno a trovarlo nei miei archivi esistenti. Come lo installo?
Ufoguy,

7
sudo apt-get install html-xml-utils
coffeMug

Ottengo questo errore su Ubuntu 12.10 "L'input non è ben formato. (Forse provare a normalizzare?)"
slm

1
Non ho trovato cosa fare con il messaggio. sulla normalizzazione dell'output. Nessuna accensione hxselect.
slm

1
Per la gente di Mac OS X Homebrew ha una formula con hxselect al suo interno. Installa con brew install html-xml-utils.
Sukima,

18

Puoi anche usare curle grepfare questo. Avrete bisogno di arruolare l'uso di PCRE (Perl Compatible Regular Expressions) in grepper ottenere l'aspetto e le strutture dietro guardare avanti in modo che possiamo trovare i <title>...</title>tag.

Esempio

$ curl 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -so - | \
    grep -iPo '(?<=<title>)(.*)(?=</title>)'
Why Are Bad Words Bad? - YouTube

Dettagli

Gli curlinterruttori:

  • -s = silenzioso
  • -o - = invia output a STDOUT

Gli grepinterruttori:

  • -i = insensibilità al caso
  • -o = Restituisce solo la parte corrispondente
  • -P = Modalità PCRE

Lo 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>.

Situazioni più complesse

Se si <title>...</titie>estende su più righe, non verrà trovato quanto sopra. È possibile mitigare questa situazione utilizzando tr, per eliminare qualsiasi \ncarattere, ad es tr -d '\n'.

Esempio

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

lang = ...

Se l' <title>opzione è impostata in questo modo, <title lang="en">dovrai rimuoverla prima di grepinserirla. Lo strumento sedpuò 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.

Un vero parser HTML / XML - usando Ruby

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 curlcome HTML ( Nokogiri::HTML). Il metodo xpathquindi 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' putspoi li stampa.

Un vero parser HTML / XML - usando Perl

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 

1
Soluzione ordinata! :)
coffeMug

3
L'analisi di HTML con espressioni regolari non è così semplice. I tag scritti come "<TITLE>", "<title lang = en>", "<title \ n>" non corrisponderanno alla tua espressione. Ancora più grande problema, né "<title> \ noops \ n </title>" sarà.
arte

4
Tentare di analizzare HTML usando regex tende ad essere malvisto da queste parti .
user3490

1
@slm, <title>Unix\nLinux</title>è pensato per essere Unix Linux, no UnixLinux.
Stéphane Chazelas,

1
+1 per rubino + nokogiri. L'ho usato per tutti i tipi di web scraping, è fantastico!
Rob,

7

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-bs4pacchetto su Debian / Ubuntu).


2
bs4non si trova nella libreria standard di Python. Devi installarlo usando easy_install beautfulsoup4(non easyinstall bs4).
Anthon,

@Anthon ha incluso le tue informazioni
Zelda,

5

Forse è "imbroglione" ma un'opzione è pup, un parser HTML da riga di comando .

Ecco due modi per farlo:

Utilizzo del metacampo con property="og:titleattributo

$ 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 titledirettamente il campo (e poi staccando la - YouTubestringa alla fine).

$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'title text{}' | sed 's/ - YouTube$//'
Why Are Bad Words Bad?

Per evitare entità personaggio, gli utenti potrebbero voler utilizzare l' --plainopzione pup .
picco

3

Sembra essere possibile lynxusando questo trucco ( zsh, bashsintassi):

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 lynximposta la $LYNX_PRINT_TITLEvariabile 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 Pche invia semplicemente il contenuto di quella variabile al descrittore di file 3(quel descrittore di file viene reindirizzato allo lynxstdout con 3>&1mentre lo stdout di lince viene reindirizzato a / dev / null).

Quindi usiamo la funzione di lynxscripting 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.


3

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'

1
Questi sono gli unici che hanno funzionato per me!
Ahmad Awais,

1

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");

0

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?
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.