Quiero un programa de línea de comando que imprima el título de un sitio web. Por ejemplo:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
debería dar:
Why Are Bad Words Bad?
Le das la url e imprime el Título.
Quiero un programa de línea de comando que imprima el título de un sitio web. Por ejemplo:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
debería dar:
Why Are Bad Words Bad?
Le das la url e imprime el Título.
Respuestas:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Puede canalizarlo a GNU recode
si hay cosas como <
en él:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
recode html..
Para quitar 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'
Para señalar algunas de las limitaciones:
No hay un comando estándar / portátil para hacer consultas HTTP. Hace unas décadas, hubiera recomendado lynx -source
aquí. Pero hoy en día, wget
es más portátil, ya que se puede encontrar por defecto en la mayoría de los sistemas GNU (incluidos la mayoría de los sistemas operativos de escritorio / portátiles basados en Linux). Otros que son bastante portátiles incluyen el GET
comando que viene con perl
la libwww que a menudo se instala lynx -source
, y en menor medida curl
. Otros comunes los incluyen links -source
, elinks -source
, w3m -dump_source
, lftp -c cat
...
wget
es posible que no obtenga la misma página que la que, por ejemplo, firefox
se mostrará. La razón es que los servidores HTTP pueden elegir enviar una página diferente en función de la información proporcionada en la solicitud enviada por el cliente.
La solicitud enviada por wget / w3m / GET ... será diferente de la enviada por firefox. Si eso es un problema, puede modificar el wget
comportamiento para cambiar la forma en que envía la solicitud, aunque con opciones.
Los más importantes aquí a este respecto son:
Accept
y Accept-language
: eso le dice al servidor en qué idioma y conjunto de caracteres le gustaría al cliente obtener la respuesta. wget
no envía ninguno de manera predeterminada, por lo que el servidor generalmente enviará con su configuración predeterminada. firefox
en el otro extremo es probable que esté configurado para solicitar su idioma.User-Agent
: que identifica la aplicación del cliente para el servidor. Algunos sitios envían contenido diferente basado en el cliente (aunque eso es principalmente por diferencias entre las interpretaciones del lenguaje javascript) y pueden negarse a servirle si está utilizando un agente de usuario de tipo robotwget
.Cookie
: si ha visitado este sitio anteriormente, su navegador puede tener cookies permanentes. wget
No lo haré.wget
seguirá las redirecciones cuando se realicen en el nivel de protocolo HTTP, pero dado que no analiza el contenido de la página, no las realizadas por javascript o cosas por el estilo <meta http-equiv="refresh" content="0; url=http://example.com/">
.
Aquí, por flojera, hemos perl
leído todo el contenido en la memoria antes de comenzar a buscar la <title>
etiqueta. Dado que el título se encuentra en la <head>
sección que se encuentra en los primeros bytes del archivo, eso no es óptimo. Un mejor enfoque, si GNU awk
está disponible en su sistema podría ser:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
gawk -v IGNORECASE=1 -v RS='</title' 'RT{gsub(/.*<title[^>]*>/,"");print;exit}'
De esa manera, awk deja de leer después de la primera </title
y, al salir, hace wget
que se detenga la descarga.
Aquí, wget
escribe la página a medida que la descarga. Al mismo tiempo, perl
sorbe su salida ( -0777 -n
) completa en la memoria y luego imprime el código HTML que se encuentra entre las primeras apariciones de <title...>
y </title
.
Eso funcionará para la mayoría de las páginas HTML que tienen una <title>
etiqueta, pero hay casos en los que no funcionará.
Por el contrario, la solución de coffeeMug analizará la página HTML como XML y devolverá el valor correspondiente para title
. Es más correcto si se garantiza que la página sea XML válido . Sin embargo, no se requiere que HTML sea XML válido (las versiones anteriores del lenguaje no lo eran), y debido a que la mayoría de los navegadores son indulgentes y aceptarán códigos HTML incorrectos, incluso hay muchos códigos HTML incorrectos.
Tanto mi solución como coffeeMug fallarán en una variedad de casos de esquina, a veces lo mismo, a veces no.
Por ejemplo, el mío fallará en:
<html><head foo="<title>"><title>blah</title></head></html>
o:
<!-- <title>old</title> --><title>new</title>
Mientras que su fallará:
<TITLE>foo</TITLE>
(html válido, no xml) o:
o:
<title>...</title>
...
<script>a='<title>'; b='</title>';</script>
(de nuevo, válido html
, faltan <![CDATA[
partes para que sea válido XML).
<title>foo <<<bar>>> baz</title>
(HTML incorrecto, pero aún se encuentra allí y es compatible con la mayoría de los navegadores)
Esa solución genera el texto sin formato entre <title>
y </title>
. Normalmente, no debe haber ninguna etiqueta HTML allí, posiblemente puede haber comentarios (aunque algunos navegadores como Firefox no los manejan, por lo que es muy poco probable). Todavía puede haber algo de codificación 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
De lo que se ocupa 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
Pero un cliente web también está destinado a hacer más transformaciones en ese código al mostrar el título (como condensar algunos de los espacios en blanco, eliminar los iniciales y finales). Sin embargo, es poco probable que sea necesario. Entonces, como en los otros casos, depende de usted decidir si vale la pena el esfuerzo.
Antes de UTF-8, iso8859-1 solía ser el juego de caracteres preferido en la web para caracteres que no son ASCII, aunque estrictamente hablando tenían que escribirse como é
. Las versiones más recientes de HTTP y el lenguaje HTML han agregado la posibilidad de especificar el conjunto de caracteres en los encabezados HTTP o en los encabezados HTML, y un cliente puede especificar los conjuntos de caracteres que acepta. UTF-8 tiende a ser el juego de caracteres predeterminado en la actualidad.
Entonces, eso significa que, por ahí, encontrará é
escrito como é
, como é
, como UTF-8 é
, (0xc3 0xa9), como iso-8859-1 (0xe9), con los 2 últimos, a veces la información en el juego de caracteres en los encabezados HTTP o los encabezados HTML (en diferentes formatos), a veces no.
wget
solo obtiene los bytes sin procesar, no le importa su significado como caracteres y no le dice al servidor web sobre el juego de caracteres preferido.
recode html..
se encargará de convertir el é
o é
en la secuencia adecuada de bytes para el conjunto de caracteres utilizado en su sistema, pero para el resto, eso es más complicado.
Si el conjunto de caracteres de su sistema es utf-8, es probable que esté bien la mayor parte del tiempo, ya que tiende a ser el conjunto de caracteres predeterminado que se utiliza actualmente.
$ 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
Eso de é
arriba era un UTF-8 é
.
Pero si quieres cubrir otros charsets, una vez más, habrá que cuidarlo.
También debe tenerse en cuenta que esta solución no funcionará en absoluto para las páginas codificadas UTF-16 o UTF-32.
Idealmente, lo que necesita aquí es un navegador web real para brindarle la información. Es decir, necesita algo para hacer la solicitud HTTP con los parámetros adecuados, interpretar la respuesta HTTP correctamente, interpretar completamente el código HTML como lo haría un navegador y devolver el título.
Como no creo que se pueda hacer en la línea de comandos con los navegadores que conozco (aunque ahora vea este trucolynx
), debe recurrir a la heurística y las aproximaciones, y la anterior es tan buena como cualquiera.
También es posible que desee tener en cuenta el rendimiento, la seguridad ... Por ejemplo, para cubrir todos los casos (por ejemplo, una página web que tiene algunos javascript extraídos de un sitio de terceros que establece el título o redirige a otra página en un onload hook), puede que tenga que implementar un navegador de la vida real con sus motores dom y javascript que pueden tener que hacer cientos de consultas para una sola página HTML, algunas de las cuales intentan explotar vulnerabilidades ...
Si bien el uso de expresiones regulares para analizar HTML a menudo está mal visto , este es un caso típico en el que es lo suficientemente bueno para la tarea (IMO).
<
ya que no se garantiza que los títulos tengan etiquetas finales y cualquier otra etiqueta debería forzar su terminación. También es posible que desee quitar nuevas líneas.
También puede probar hxselect
(desde HTML-XML-Utils ) con wget
lo siguiente:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' | hxselect -s '\n' -c 'title' 2>/dev/null
Se puede instalar hxselect
en distribuciones basadas en Debian usando:
sudo apt-get install html-xml-utils
.
La redirección de STDERR es para evitar el Input is not well-formed. (Maybe try normalize?)
mensaje.
Para deshacerse de "- YouTube", canalice la salida del comando anterior a awk '{print substr($0, 0, length($0)-10)}'
.
sudo apt-get install html-xml-utils
hxselect
.
También puede usar curl
y grep
para hacer esto. Tendrá que recurrir a la utilización de PCRE (Perl Compatible Regular Expressions) en grep
conseguir la mirada detrás de las instalaciones y mirar hacia adelante para que podamos encontrar las <title>...</title>
etiquetas.
$ curl 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -so - | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
Why Are Bad Words Bad? - YouTube
Los curl
interruptores:
-s
= silencioso-o -
= enviar salida a STDOUTLos grep
interruptores:
-i
= insensibilidad a mayúsculas y minúsculas-o
= Devuelve solo la porción que coincide-P
= Modo PCREEl patrón para grep
:
(?<=<title>)
= busca una cadena que comience con esto a la izquierda de ella(?=</title>)
= busca una cadena que termine con esto a la derecha(.*)
= todo en el medio <title>..</title>
.Si <title>...</titie>
abarca varias líneas, entonces lo anterior no lo encontrará. Puede mitigar esta situación utilizando tr
, para eliminar cualquier \n
carácter, es decir tr -d '\n'
.
Archivo de muestra
$ cat multi-line.html
<html>
<title>
this is a \n title
</TITLE>
<body>
<p>this is a \n title</p>
</body>
</html>
Y una muestra de ejecución:
$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
tr -d '\n' | \
grep -iPo '(?<=<title>)(.*)(?=</title>)'
this is a \n title
Si <title>
se configura así, <title lang="en">
entonces deberá eliminarlo antes de grep
usarlo. La herramienta sed
se puede usar para hacer esto:
$ 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
Lo anterior encuentra la cadena que no distingue entre mayúsculas y minúsculas lang=
seguida de una secuencia de palabras ( \w+
). Luego es despojado.
En algún momento, la expresión regular fallará al resolver este tipo de problema. Si eso ocurre, es probable que desee utilizar un analizador HTML / XML real. Uno de esos analizadores es Nokogiri . Está disponible en Ruby as a Gem y se puede usar así:
$ 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
Lo anterior está analizando los datos que vienen a través de curl
como HTML ( Nokogiri::HTML
). El método xpath
luego busca nodos (etiquetas) en el HTML que son nodos hoja, ( //
) con el nombre title
. Para cada encontrado, queremos devolver su contenido ( e.content
). El puts
luego los imprime.
También puede hacer algo similar con Perl y el módulo 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";
Luego puede ejecutar este script de la siguiente manera:
$ ./title_getter.pl http://www.jake8us.org/~sam/multi-line.html
this is a \n title
<title>Unix\nLinux</title>
está destinado a ser Unix Linux
, no UnixLinux
.
Usar expresiones regulares simples para analizar HTML es ingenuo. Por ejemplo, con líneas nuevas e ignorando la codificación de caracteres especiales especificada en el archivo. Haga lo correcto y analice realmente la página utilizando cualquiera de los otros analizadores reales mencionados en las otras respuestas o utilice el siguiente delineador:
python -c "import bs4, urllib2; print bs4.BeautifulSoup(urllib2.urlopen('http://www.crummy.com/software/BeautifulSoup/bs4/doc/')).title.text"
(Lo anterior incluye un carácter Unicode).
BeautifulSoup también maneja una gran cantidad de HTML incorrecto (por ejemplo, faltan etiquetas de cierre), que arrojaría por completo expresiones regulares simplistas. Puede instalarlo en una python estándar usando:
pip install beautifulsoup4
o si no tienes pip
, con
easy_install beautifulsoup4
Algunos sistemas operativos como Debian / Ubuntu también lo tienen empaquetado ( python-bs4
paquete en Debian / Ubuntu).
bs4
no está en la biblioteca estándar de python. Tienes que instalarlo usando easy_install beautfulsoup4
(no easyinstall bs4
).
Tal vez sea "trampa", pero una opción es pup, un analizador HTML de línea de comandos .
Aquí hay dos formas de hacerlo:
Usando el meta
campo con property="og:title
atributo
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'meta[property=og:title] attr{content}'
Why Are Bad Words Bad?
y otra forma de usar el title
campo directamente (y luego cortar la - YouTube
cadena al final).
$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'title text{}' | sed 's/ - YouTube$//'
Why Are Bad Words Bad?
--plain
opción de cachorro .
Parece posible con el lynx
uso de este truco ( zsh
, bash
sintaxis):
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'
Debido a que es un navegador web de la vida real, no sufre muchas de las limitaciones que menciono en mi otra respuesta .
Aquí, estamos usando el hecho de que lynx
establece la $LYNX_PRINT_TITLE
variable de entorno al título de la página actual al imprimir la página.
Por encima, estamos dando un archivo de configuración (como un tubo) que define una "impresora" lince llamada P
que simplemente da salida al contenido de esa variable de descriptor de archivo 3
(que descriptor de archivo se redirige a lynx
's stdout con 3>&1
mientras que la salida estándar lince es en sí redirigidos a / dev / null).
Luego usamos la función de lynx
secuencias de comandos para simular que el usuario presiona p
, y End
(también conocido como select) y Enter
( ^J
).
-accept_all_cookies
de lo contrario, Lynx solicitaría al usuario la confirmación de cada cookie.
Manera simple:
curl -s example.com | grep -o "<title>[^<]*" | tail -c+8
Pocas alternativas:
curl -s example.com | grep -o "<title>[^<]*" | cut -d'>' -f2-
wget -qO- example.com | grep -o "<title>[^<]*" | sed -e 's/<[^>]*>//g'
Me gustó la idea de Stéphane Chazelas de usar Lynx y LYNX_PRINT_TITLE, pero ese script no me funcionó en Ubuntu 14.04.5.
He creado una versión simplificada usando Lynx y archivos preconfigurados de antemano.
Agregue la siguiente línea a /etc/lynx-cur/lynx.cfg (o donde sea que resida su lynx.cfg):
PRINTER:P:printenv LYNX_PRINT_TITLE>/home/account/title.txt:TRUE:1000
Esta línea le indica que guarde el título, mientras imprime, en "/home/account/title.txt"; puede elegir el nombre de archivo que desee. Solicita páginas MUY grandes, aumente el valor anterior de "1000" a cualquier número de líneas por página que desee, de lo contrario Lynx hará un mensaje adicional "al imprimir documentos que contengan un número muy grande de páginas".
Luego cree el archivo /home/account/lynx-script.txt con el siguiente contenido:
key p
key Select key
key ^J
exit
Luego ejecute Lynx usando las siguientes opciones de línea de comandos:
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 completar este comando, el archivo /home/account/title.txt se creará con el título de su página.
Para resumir, aquí hay una función PHP que devuelve un título de página basado en la URL dada, o falso en caso de error.
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");
Usando nokogiri, uno puede usar una consulta simple basada en CSS para extraer el texto interno de la etiqueta:
$ nokogiri -e 'puts $_.at_css("title").content'
Why Are Bad Words Bad? - YouTube
Del mismo modo, para extraer el valor del atributo "contenido" de la etiqueta:
$ nokogiri -e 'puts $_.at_css("meta[name=title]").attr("content")'
Why Are Bad Words Bad?