Comment puis-je obtenir un titre de site Web en ligne de commande?


50

Je veux un programme en ligne de commande qui affiche le titre d'un site Web. Par exemple:

Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc

devrait donner:

Why Are Bad Words Bad? 

Vous lui donnez l'URL et le titre est imprimé.


2
Lorsque je télécharge ce titre, je reçois le message suivant: "Pourquoi les mauvais mots sont-ils mauvais? - Youtube", voulez-vous que le "- Youtube" soit également tronqué?
slm

Réponses:


44
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
  perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'

Vous pouvez le diriger vers GNU recodes’il contient des éléments tels &lt;que:

wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
  perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si' |
  recode html..

Pour enlever la - youtubepièce:

wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
 perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)(?: - youtube)?\s*<\/title/si'

Pour souligner certaines des limitations:

portabilité

Il n'y a pas de commande standard / portable pour effectuer des requêtes HTTP. Il y a quelques décennies, j'aurais recommandé à la lynx -sourceplace ici. Mais de nos jours, il wgetest plus portable car on peut le trouver par défaut sur la plupart des systèmes GNU (y compris la plupart des systèmes d’exploitation pour ordinateurs de bureau / ordinateurs portables basés sur Linux). Parmi les autres assez portables, citons la GETcommande qui vient avec perllibwww qui est souvent installée lynx -source, et dans une moindre mesure curl. D' autres communes les comprennent links -source, elinks -source, w3m -dump_source, lftp -c cat...

Protocole HTTP et traitement de la redirection

wgetpeut ne pas obtenir la même page que celle firefoxaffichée par exemple . La raison en est que les serveurs HTTP peuvent choisir d'envoyer une page différente en fonction des informations fournies dans la demande envoyée par le client.

La requête envoyée par wget / w3m / GET ... va être différente de celle envoyée par firefox. Si cela pose un problème, vous pouvez modifier le wgetcomportement pour modifier la manière dont il envoie la demande avec des options.

Les plus importants ici à cet égard sont:

  • Acceptet Accept-language: cela indique au serveur dans quelle langue et quel jeu de caractères le client souhaite obtenir la réponse. wgetn'envoie pas de valeur par défaut, le serveur envoie donc avec ses paramètres par défaut. firefoxà l'autre extrémité est probablement configuré pour demander votre langue.
  • User-Agent: qui identifie l'application client sur le serveur. Certains sites envoient un contenu différent en fonction du client (bien que ce soit principalement pour des différences entre les interprétations du langage javascript) et peut refuser de vous servir si vous utilisez un agent utilisateur de type robot , comme wget.
  • Cookie: si vous avez déjà visité ce site, votre navigateur peut avoir des cookies permanents pour cela. wgetNe fera pas.

wgetsuivra les redirections quand elles seront terminées au niveau du protocole HTTP, mais comme cela ne regarde pas le contenu de la page, pas celles faites par javascript ou quelque chose comme <meta http-equiv="refresh" content="0; url=http://example.com/">.

Performance / Efficacité

Ici, par paresse, nous avons perllu tout le contenu en mémoire avant de commencer à chercher la <title>balise. Étant donné que le titre se trouve dans la <head>section qui se trouve dans les premiers octets du fichier, ce n'est pas optimal. Une meilleure approche, si GNU awkest disponible sur votre système, pourrait être:

wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
  gawk -v IGNORECASE=1 -v RS='</title' 'RT{gsub(/.*<title[^>]*>/,"");print;exit}'

De cette façon, awk arrête de lire après le premier </titleet, en quittant, wgetarrête le téléchargement.

Analyse du HTML

Ici, wgetécrit la page lorsqu’elle la télécharge. En même temps, perlglisse sa sortie ( -0777 -n) en mémoire, puis imprime le code HTML trouvé entre les premières occurrences de <title...>et </title.

Cela fonctionnera pour la plupart des pages HTML comportant une <title>balise, mais dans certains cas, cela ne fonctionnera pas.

En revanche, la solution de coffeeMug analysera la page HTML au format XML et renverra la valeur correspondante pour title. Il est plus correct de s’assurer que la page est un XML valide . Cependant, il n'est pas nécessaire que HTML soit un XML valide (les anciennes versions du langage ne l'étaient pas) et, comme la plupart des navigateurs sont cléments et acceptent le code HTML incorrect, il existe même de nombreux codes HTML incorrects.

Ma solution et CoffeeMug échoueront dans différents cas, parfois les mêmes, parfois non.

Par exemple, le mien va échouer sur:

<html><head foo="<title>"><title>blah</title></head></html>

ou:

<!-- <title>old</title> --><title>new</title>

Alors que sa volonté échouera sur:

<TITLE>foo</TITLE>

(HTML valide, pas XML) ou:

ou:

<title>...</title>
...
<script>a='<title>'; b='</title>';</script>

(encore une fois, pièces htmlmanquantes <![CDATA[pour rendre XML valide).

<title>foo <<<bar>>> baz</title>

(html incorrect, mais toujours trouvé et supporté par la plupart des navigateurs)

interprétation du code à l'intérieur des balises.

Cette solution génère le texte brut entre <title>et </title>. Normalement, il ne devrait pas y avoir de balises HTML, il pourrait y avoir des commentaires (bien que certains navigateurs comme Firefox ne les gèrent pas, ce qui est très peu probable). Il peut encore y avoir un encodage 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

Ce qui est pris en charge par 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

Mais un client Web est également censé faire plus de transformations sur ce code lors de l'affichage du titre (par exemple, condenser certaines des blancs, supprimer les premiers et les derniers). Cependant, il est peu probable que cela soit nécessaire. Donc, comme dans les autres cas, c'est à vous de décider si cela en vaut la peine.

Jeu de caractères

Avant UTF-8, iso8859-1 était le jeu de caractères préféré sur le Web pour les caractères non-ASCII bien que, à proprement parler, ils devaient être écrits sous la forme &eacute;. Des versions plus récentes de HTTP et du langage HTML ont ajouté la possibilité de spécifier le jeu de caractères dans les en-têtes HTTP ou HTML, et un client peut spécifier les jeux de caractères qu'il accepte. UTF-8 a tendance à être le jeu de caractères par défaut de nos jours.

Donc, cela signifie que là-bas, vous trouverez éécrit comme &eacute;, comme , comme &#233;, comme UTF-8 é, (0xc3 0xa9), comme iso-8859-1 (0xe9), avec pour les 2 derniers, parfois les informations sur le jeu de caractères dans les en-têtes HTTP ou les en-têtes HTML (dans différents formats), parfois non.

wget n'obtient que les octets bruts, peu importe leur signification en tant que caractères, ni le serveur Web sur le jeu de caractères préféré.

recode html..se chargera de convertir le &eacute;ou &#233;en la séquence d'octets appropriée pour le jeu de caractères utilisé sur votre système, mais pour le reste, c'est plus compliqué.

Si votre jeu de caractères système est utf-8, il y a de fortes chances qu'il fonctionne normalement la plupart du temps, car il s'agit généralement du jeu de caractères par défaut utilisé de nos jours.

$ 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

Ce qui éprécède était un UTF-8 é.

Mais si vous voulez couvrir d'autres jeux de caractères, encore une fois, il faudra en prendre soin.

Il convient également de noter que cette solution ne fonctionnera pas du tout pour les pages codées UTF-16 ou UTF-32.

Pour résumer

Idéalement, ce dont vous avez besoin ici, c'est un véritable navigateur Web pour vous donner les informations. Autrement dit, vous avez besoin de quelque chose pour traiter la requête HTTP avec les paramètres appropriés, interpréter correctement la réponse HTTP, interpréter intégralement le code HTML comme le ferait un navigateur et renvoyer le titre.

Comme je ne pense pas que cela puisse être fait en ligne de commande avec les navigateurs que je connais (bien que vous voyiez maintenant cette astucelynx ), vous devez recourir à des heuristiques et à des approximations, et celle ci-dessus en vaut la peine.

Vous pouvez également prendre en compte les performances, la sécurité ... Par exemple, pour couvrir tous les cas (par exemple, une page Web contenant du javascript extrait d'un site tiers qui définit le titre ou redirige vers une autre page dans une page Web). onload), vous devrez peut-être implémenter un navigateur de la vie réelle avec ses moteurs dom et javascript qui devront peut-être faire des centaines de requêtes pour une seule page HTML, dont certaines tentent d'exploiter des vulnérabilités ...

Bien que l’ utilisation des expressions rationnelles pour analyser le langage HTML soit souvent mal vue , voici un cas typique où il convient assez bien à la tâche (IMO).


Est-ce qu'il télécharge aussi les images des pages? De plus, laissera-t-il les fichiers HTML indésirables?
Ufoguy

2
Vous voudrez probablement terminer le titre à la première instance <car il n’est pas garanti que les titres ont des balises de fin et toute autre balise devrait forcer sa résiliation. Vous pouvez également vouloir supprimer de nouvelles lignes.
Brian Nickel

1
Il n'est pas recommandé d'utiliser des expressions régulières pour analyser le code HTML. Déjà. Pas même dans ce cas. C'est une mauvaise habitude. Utilisez plutôt un analyseur syntaxique réel. Il existe une célèbre réponse humoristique de Stackoverflow à ce sujet ...
Robin Green

4
@RobinGreen Cet article traitait de l'utilisation de regex pour analyser un langage non régulier. Il y a des réserves, mais c'est un problème qui est facilement réduit à un langage normal. Je recommande d'utiliser regex pour analyser HTML. Quelquefois. Dans ce cas.
Brian Nickel

2
Et le nombre d'expressions régulières qui fonctionnent pour presque tout est d'environ 0.
Robin Green

27

Vous pouvez également essayer hxselect(à partir de HTML-XML-Utils ) avec wgetles éléments suivants:

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

Vous pouvez installer hxselectdans Debian en utilisant la base distros:
sudo apt-get install html-xml-utils.

La redirection STDERR consiste à éviter le Input is not well-formed. (Maybe try normalize?)message.

Pour vous débarrasser de "- YouTube", dirigez la sortie de la commande ci-dessus vers awk '{print substr($0, 0, length($0)-10)}'.


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

1
Vous voudrez sans doute ajouter -ià hxselecttrop pour les mêmes raisons que manatwork mentionnées dans mon A, sinon il ne correspond pas à <TITLE>.
slm

1
Je n'ai pas trouvé quoi faire avec le msg. sur la normalisation de la sortie. Aucun tel allumer hxselect.
slm

2
Pour les utilisateurs de Mac OS X, Homebrew a une formule contenant hxselect. Installer avec brew install html-xml-utils.
Sukima

1
J'avais des problèmes avec hxselect qui refusait complètement de travailler sur du code HTML mal structuré, je devais donc d'abord le diriger vers hxclean (par exemple wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' | hxclean | hxselect -s '\n' -c 'title' 2>/dev/null).
Hayden Schiff

18

Vous pouvez également utiliser curlet grepfaire ceci. Vous aurez besoin d'obtenir l'utilisation de PCRE (Perl Compatible Regular Expressions) dans greppour obtenir le look derrière et regarder installations à venir afin que nous puissions trouver les <title>...</title>tags.

Exemple

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

Détails

Les curlinterrupteurs:

  • -s = silencieux
  • -o - = envoyer la sortie à STDOUT

Les grepinterrupteurs:

  • -i = insensibilité à la casse
  • -o = Retourne seulement la portion qui correspond
  • -P = Mode PCRE

Le motif pour grep:

  • (?<=<title>) = cherche une chaîne qui commence par celle-ci à sa gauche
  • (?=</title>) = cherche une chaîne qui se termine par ceci à sa droite
  • (.*)= tout entre les deux <title>..</title>.

Situations plus complexes

Si <title>...</titie>s'étend sur plusieurs lignes, alors ce qui précède ne le trouvera pas. Vous pouvez atténuer cette situation en utilisant tr, pour supprimer tous les \ncaractères, c.-à-d tr -d '\n'.

Exemple

Exemple de fichier.

$ cat multi-line.html 
<html>
<title>
this is a \n title
</TITLE>
<body>
<p>this is a \n title</p>
</body>
</html>

Et un exemple de parcours:

$ curl 'http://www.jake8us.org/~sam/multi-line.html' -so - | \
     tr -d '\n' | \
     grep -iPo '(?<=<title>)(.*)(?=</title>)'
this is a \n title

lang = ...

Si le <title>paramètre est défini comme ceci, <title lang="en">vous devrez le supprimer avant de l' grepinitialiser. L'outil sedpeut être utilisé pour cela:

$ 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

Ce qui précède trouve la chaîne insensible à la casse lang=suivie par une séquence de mots ( \w+). Il est ensuite retiré.

Un véritable analyseur HTML / XML - avec Ruby

À un moment donné, regex échouera dans la résolution de ce type de problème. Si cela se produit, vous voudrez probablement utiliser un véritable analyseur HTML / XML. Nokogiri est l'un de ces analyseurs . Il est disponible dans Ruby en tant que gemme et peut être utilisé comme suit:

$ 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

Ce qui précède est l’analyse des données provenant de curlas as HTML ( Nokogiri::HTML). La méthode xpathrecherche ensuite les nœuds (balises) dans le HTML qui sont des nœuds feuilles ( //) avec le nom title. Pour chaque trouvé, nous voulons retourner son contenu ( e.content). Le les putsimprime ensuite.

Un véritable analyseur HTML / XML - en utilisant Perl

Vous pouvez également faire quelque chose de similaire avec Perl et le module 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";

Vous pouvez ensuite exécuter ce script comme suit:

$ ./title_getter.pl http://www.jake8us.org/~sam/multi-line.html
this is a \n title 

1
Solution soignée! :)
coffeMug

3
L'analyse HTML avec des expressions régulières n'est pas si simple. Les balises écrites avec “<TITLE>”, “<title lang = en>”, “<title \ n>” ne seront pas mises en correspondance par votre expression. Problème encore plus grave, ni “<title> \ noops \ n </ title>” ne le seront.
manatwork

4
Tenter d'analyser html en utilisant regex a tendance à être mal vu ici.
user3490

1
@slm, <title>Unix\nLinux</title>est censé être Unix Linux, pas UnixLinux.
Stéphane Chazelas

1
+1 pour rubis + nokogiri. Je l'ai utilisé pour toutes sortes de travaux sur le Web, c'est incroyable!
Rob

7

Utiliser regex simple pour analyser HTML est naïf. Par exemple, avec des nouvelles lignes et en ignorant le codage des caractères spéciaux spécifié dans le fichier. Faites la bonne chose et analysez vraiment la page en utilisant l'un des autres analyseurs réels mentionnés dans les autres réponses ou utilisez le liner suivant:

python -c "import bs4, urllib2; print bs4.BeautifulSoup(urllib2.urlopen('http://www.crummy.com/software/BeautifulSoup/bs4/doc/')).title.text"

(Ce qui précède comprend un caractère Unicode).

BeautifulSoup gère également un grand nombre de codes HTML incorrects (par exemple des balises de fermeture manquantes), ce qui provoquerait une expression rationnelle simpliste. Vous pouvez l'installer dans un python standard en utilisant:

pip install beautifulsoup4

ou si vous n'avez pas pip, avec

easy_install beautifulsoup4

Certains systèmes d'exploitation tels que Debian / Ubuntu l'ont également empaqueté ( python-bs4paquet sur Debian / Ubuntu).


2
bs4n'est pas dans la bibliothèque standard Python. Vous devez l'installer en utilisant easy_install beautfulsoup4(non easyinstall bs4).
Anthon

@Anthon a inclus vos informations
Zelda,

5

Peut-être que c'est "tricher", mais l'une des options est chiot, un analyseur HTML en ligne de commande .

Voici deux façons de le faire:

Utiliser le metachamp avec property="og:titleattribut

$ wget -q 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' -O - | \
> pup 'meta[property=og:title] attr{content}'
Why Are Bad Words Bad?

et une autre manière en utilisant le titlechamp directement (puis en coupant la - YouTubechaîne à la fin).

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

Pour éviter les entités de caractère, les utilisateurs peuvent utiliser l' --plainoption de chiot .
pic

3

Il semble être possible en lynxutilisant cette astuce ( zsh, bashsyntaxe):

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'

Parce que c'est un navigateur Web réel, il ne souffre pas de nombreuses limitations que je mentionne dans mon autre réponse .

Ici, nous utilisons le fait que lynxla $LYNX_PRINT_TITLEvariable d'environnement est définie sur le titre de la page en cours lors de l'impression de la page.

Ci-dessus, nous donnons un fichier de configuration (sous forme de tube) qui définit une "imprimante" lynx appelée Psimplement le contenu de cette variable dans un descripteur de fichier 3(ce descripteur de fichier est redirigé vers la sortie lynxstandard de stdout 3>&1tandis que lynx stdout est lui-même redirigé vers / dev / null).

Ensuite, nous utilisons un lynxscript pour simuler l’utilisateur en appuyant sur p, puis sur End(aka select), et Enter( ^J).

-accept_all_cookies sinon, Lynx demanderait à l'utilisateur une confirmation pour chaque cookie.


3

Manière simple:

curl -s example.com | grep -o "<title>[^<]*" | tail -c+8

Peu d'alternatives:

curl -s example.com | grep -o "<title>[^<]*" | cut -d'>' -f2-
wget -qO- example.com | grep -o "<title>[^<]*" | sed -e 's/<[^>]*>//g'

1
Ce sont les seuls qui ont fonctionné pour moi!
Ahmad Awais

1

J'aimais bien l'idée de Stéphane Chazelas d'utiliser Lynx et LYNX_PRINT_TITLE, mais ce script ne fonctionnait pas pour moi sous Ubuntu 14.04.5.

J'en ai fait une version simplifiée en utilisant Lynx et en utilisant des fichiers pré-configurés à l'avance.

Ajoutez la ligne suivante à /etc/lynx-cur/lynx.cfg (ou à l’endroit où réside votre lynx.cfg):

PRINTER:P:printenv LYNX_PRINT_TITLE>/home/account/title.txt:TRUE:1000

Cette ligne vous invite à enregistrer le titre, lors de l’impression, dans "/home/account/title.txt" - vous pouvez choisir le nom de fichier de votre choix. Vous demandez TRES grandes pages, augmentez la valeur ci-dessus de "1000" à un nombre quelconque de lignes par page, sinon Lynx fera apparaître une invite supplémentaire "lors de l'impression d'un document contenant un très grand nombre de pages".

Créez ensuite le fichier /home/account/lynx-script.txt avec le contenu suivant:

key p
key Select key
key ^J
exit

Ensuite, exécutez Lynx en utilisant les options de ligne de commande suivantes:

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

A l'issue de cette commande, le fichier /home/account/title.txt sera créé avec le titre de votre page.

En résumé, voici une fonction PHP qui renvoie un titre de page basé sur l'URL donnée, ou false en cas d'erreur.

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

En utilisant nokogiri, on peut utiliser une simple requête basée sur CSS pour extraire le texte intérieur de la balise:

 $ nokogiri -e 'puts $_.at_css("title").content'
 Why Are Bad Words Bad? - YouTube

De même, pour extraire la valeur de l'attribut "content" de la balise:

$ nokogiri -e 'puts $_.at_css("meta[name=title]").attr("content")'
Why Are Bad Words Bad?
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.