Як отримати заголовок веб-сайтів за допомогою командного рядка?


50

Я хочу, щоб програма командного рядка друкувала заголовок веб-сайту. Наприклад:

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

повинен дати:

Why Are Bad Words Bad? 

Ви надаєте йому URL-адресу, і вона виводить заголовок.


2
Коли я завантажую цю назву, я отримую: "Чому погані слова погані? Youtube?"
slm

Відповіді:


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

Ви можете передавати його GNU, recodeякщо в ньому є такі речі &lt;:

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

Щоб видалити - youtubeдеталь:

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

Щоб вказати на деякі обмеження:

портативність

Немає стандартної / портативної команди для виконання HTTP-запитів. Кілька десятиліть тому я рекомендував би lynx -sourceзамість цього тут. Але сьогодні wgetє більш портативним, оскільки його можна знайти за замовчуванням у більшості систем GNU (включаючи більшість операційних систем настільних ПК / ноутбуків на базі Linux). Інші досить портативні пристрої включають GETкоманду, яка постачається з perl's libwww, яка часто встановлюється lynx -source, і в меншій мірі curl. Інші поширені з них включають в себе links -source, elinks -source, w3m -dump_source, lftp -c cat...

Протокол HTTP та обробка перенаправлення

wgetможе не отримати ту саму сторінку, що та, firefoxяка відображатиметься, наприклад. Причина полягає в тому, що сервери HTTP можуть вирішити надіслати іншу сторінку на основі інформації, наданої у запиті, надісланому клієнтом.

Запит, надісланий wget / w3m / GET ..., відрізнятиметься від запиту, надісланого Firefox. Якщо це проблема, ви можете змінити wgetповедінку, щоб змінити спосіб надсилання запиту, хоча і за допомогою параметрів.

Найважливішими з цього приводу є:

  • Acceptі Accept-language: це вказує серверу, якою мовою та діаграмою клієнт хотів би отримати відповідь. wgetЗа замовчуванням не надсилає жодних, тому сервер зазвичай надсилає свої налаштування за замовчуванням. firefoxз іншого боку, ймовірно, налаштовано на запит вашої мови.
  • User-Agent: що ідентифікує клієнтську програму на сервері. Деякі сайти відправити інший зміст , засноване на клієнті (хоча це в основному відмінність між яваскрипт мовних інтерпретаціями) і може відмовитися служити вам , якщо ви використовуєте робот -типу агент користувача як wget.
  • Cookie: якщо ви раніше відвідували цей сайт, у вашому веб-переглядачі можуть бути постійні файли cookie. wgetне буде.

wgetбуде виконувати переадресації, коли вони будуть виконані на рівні протоколу HTTP, але оскільки він не розглядає зміст сторінки, а не ті, які виконуються через JavaScript або подібні речі <meta http-equiv="refresh" content="0; url=http://example.com/">.

Продуктивність / ефективність

Тут із ліні ми perlпрочитали весь вміст у пам’яті, перш ніж почати шукати <title>тег. Зважаючи на те, що заголовок знайдено в <head>розділі, який знаходиться в перших кількох байтах файлу, це не є оптимальним. Кращим підходом, якщо GNU awkдоступний у вашій системі, може бути:

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

Таким чином, awk перестає читати після першого </title, і, виходячи з цього, призводить wgetдо припинення завантаження.

Розбір HTML

Тут wgetпише сторінка під час її завантаження. У той же час, perlSururs його вихід ( -0777 -n) ціле в пам'яті, а потім друкує HTML-код, який знаходиться між першими входженнями <title...>та </title.

Це буде працювати для більшості HTML-сторінок, на яких є <title>тег, але є випадки, коли він не працює.

На противагу цьому рішення CoffeeMug розбере HTML сторінку як XML та поверне відповідне значення для title. Це правильніше, якщо сторінка гарантує дійсність XML . Однак HTML не обов'язковий, щоб він був дійсним XML (старіші версії мови не були), а оскільки більшість браузерів там поблажливіші і приймають неправильний HTML-код, там навіть багато неправильного HTML-коду.

Як моє рішення, так і кава-Маг не вдасться в різних кутових випадках, іноді одних і тих же, іноді ні.

Наприклад, у мене не вдасться:

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

або:

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

Поки його не вдасться:

<TITLE>foo</TITLE>

(дійсний html, не xml) або:

або:

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

(знову ж таки дійсні html, відсутні <![CDATA[частини, щоб зробити його дійсним XML).

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

(неправильний HTML, але все ще знайдений там і підтримується більшістю браузерів)

інтерпретація коду всередині тегів.

Це рішення видає неочищений текст між <title>та </title>. Зазвичай там не повинно бути жодних HTML-тегів, можливо, це можуть бути коментарі (хоча деякі браузери, як firefox, так дуже малоймовірні). Можливо, все ще існує кодування 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

Про що опікується 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

Але веб-клієнт також має на увазі зробити більше перетворень цього коду під час відображення заголовка (наприклад, ущільнити деякі пробіли, видалити провідні та зворотні). Однак навряд чи буде в цьому потреба. Отже, як і в інших випадках, вирішувати, чи варто докладати зусиль, вирішувати.

Набір символів

До UTF-8 переважним шаблоном в Інтернеті для символів, що не належать до ASCII, був iso8859-1, хоча строго кажучи, їх потрібно було писати як &eacute;. Більш новітні версії HTTP та мови HTML додали можливість задавати набір символів у заголовках HTTP або в заголовках HTML, і клієнт може вказати схеми, які він приймає. На сьогодні UTF-8, як правило, є набором даних за замовчуванням.

Отже, це означає, що там ви знайдете éнаписані як &eacute;, як &#233;UTF-8 é, (0xc3 0xa9), як iso-8859-1 (0xe9), з двома останніми, іноді інформацією на графіці у заголовках HTTP або заголовках HTML (у різних форматах), іноді немає.

wget отримує лише неочищені байти, він не дбає про їх значення як символи, і не повідомляє веб-серверу про бажану схему.

recode html..подбає про перетворення &eacute;або &#233;в належну послідовність байтів для набору символів, використовуваних у вашій системі, але для решти, це складніше.

Якщо ваш системний набір - utf-8, велика ймовірність, що це буде нормально більшу частину часу, оскільки це, як правило, діапазон за замовчуванням, який використовується зараз.

$ 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

Це éбуло UTF-8 é.

Але якщо ви хочете прикрити інші шаблони, про це слід подбати ще раз.

Слід також зазначити, що це рішення взагалі не працюватиме на кодованих сторінках UTF-16 або UTF-32.

Підсумовуючи

В ідеалі, що вам тут потрібно, це справжній веб-браузер, який дає вам інформацію. Тобто вам потрібно щось зробити для HTTP-запиту з належними параметрами, правильно інтерпретувати відповідь HTTP, повністю інтерпретувати HTML-код як браузер і повернути заголовок.

Оскільки я не думаю, що це можна зробити в командному рядку з відомими мені браузерами (хоча дивіться зараз цей трюкlynx ), ви повинні вдатися до евристики та наближень, і те, що вище, так само добре, як і будь-яке.

Ви також можете взяти до уваги продуктивність, безпеку ... Наприклад, щоб охопити всі випадки (наприклад, веб-сторінку, яка має деякий javascript, витягнутий із стороннього сайту, який встановлює заголовок або перенаправляє на іншу сторінку в при завантаженні гачка), можливо, вам доведеться реалізувати браузер у реальному житті зі своїми системами dom та javascript, які, можливо, повинні робити сотні запитів для однієї сторінки HTML, деякі з яких намагаються використовувати вразливості ...

У той час як використання регулярних выражень для розбору HTML часто піддається нахабству , ось типовий випадок, коли він достатньо хороший для виконання завдання (IMO).


Чи завантажує зображення також зі сторінок? Також це залишить непотрібні HTML-файли позаду?
Ufoguy

2
Ви, мабуть, хочете скасувати заголовок у першій інстанції, <оскільки в заголовках не гарантується наявність кінцевих тегів, а будь-який інший тег повинен змусити його припинити. Можливо, ви також хочете зняти нові лінії.
Брайан Нікель

1
Не рекомендується використовувати регулярні вирази для розбору HTML. Колись. Навіть у цьому випадку. Це шкідлива звичка. Використовуйте замість цього справжній парсер. Про це є відома жартівлива відповідь Стакковерлупа ...
Робін Грін

4
@RobinGreen У цій публікації йшлося про використання регулярного вираження для розбору нерегулярної мови. Існують застереження, але це проблема, яка легко зводиться до звичайної мови. Я рекомендую використовувати регулярний вираз для розбору HTML. Іноді. В цьому випадку.
Брайан Нікель

2
А кількість регулярних виразів, які працюють майже на все, становить приблизно 0.
Робін Грін

27

Ви також можете спробувати hxselectHTML-XML-Utils ) з wgetнаступним чином:

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

Ви можете встановити hxselectв дистрибутивах на основі Debian з допомогою:
sudo apt-get install html-xml-utils.

Перенаправлення STDERR - це уникати Input is not well-formed. (Maybe try normalize?)повідомлення.

Для того, щоб позбутися "YouTube", передайте вихідну команду вище awk '{print substr($0, 0, length($0)-10)}'.


Здається, "hxselect" встановлений на Ubuntu за замовчуванням. Я навіть не можу знайти його в своїх існуючих сховищах. Як це встановити?
Ufoguy

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

Я отримую цю помилку на Ubuntu 12.10 "Введення недостатньо сформоване. (Може, спробуйте нормалізувати?)"
slm

1
Я не знайшов, що робити з повідомленнями. про нормалізацію випуску. Такого вмикання немає hxselect.
slm

1
Для Mac OS X люди Homebrew мають формулу з hxselect в ній. Встановити за допомогою brew install html-xml-utils.
Сукіма

18

Ви також можете використовувати curlі grepробити це. Вам необхідно заручитися використання PCRE (Perl Compatible Regular Expressions) в , grepщоб отримати вид ззаду і дивитися вперед об'єкти , так що ми можемо знайти <title>...</title>мітки.

Приклад

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

Деталі

У curlвимикачах:

  • -s = мовчати
  • -o - = надіслати вихід STDOUT

У grepвимикачах:

  • -i = нечутливість випадку
  • -o = Поверніть лише ту частину, яка відповідає
  • -P = Режим PCRE

Шаблон grep:

  • (?<=<title>) = шукайте рядок, який починається з цього зліва від нього
  • (?=</title>) = шукайте рядок, який закінчується цим праворуч від нього
  • (.*)= все між ними <title>..</title>.

Більш складні ситуації

Якщо <title>...</titie>простягається декілька рядків, то вищезгадане не знайде. Ви можете пом'якшити цю ситуацію, використовуючи trдля видалення будь-яких \nсимволів, тобто tr -d '\n'.

Приклад

Зразок файлу.

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

І вибір проби:

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

lang = ...

Якщо значення <title>встановлено таким чином, <title lang="en">його потрібно буде видалити перед тим, як grepрозпочати його. Інструмент sedможна використовувати для цього:

$ 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

Вищенаведене знаходить нечутливу до регістру строку з lang=наступною послідовністю слів ( \w+). Потім його знімають.

Справжній HTML / XML-аналізатор - за допомогою Ruby

У якийсь момент регулярний вираз не зможе вирішити подібний тип проблеми. Якщо це трапиться, ви, ймовірно, захочете використовувати справжній HTML / XML-аналізатор. Одним з таких аналізаторів є Nokogiri . Він доступний в Ruby як дорогоцінний камінь і може використовуватися так:

$ 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

Вище описано аналіз даних, що надходять через curlHTML ( Nokogiri::HTML). Потім метод xpathшукає у HTML вузлах (тегах), які є вузлами листя, ( //) з назвою title. Для кожного знайденого ми хочемо повернути його вміст ( e.content). putsПотім друкує їх.

Справжній HTML / XML-аналізатор - за допомогою Perl

Ви також можете зробити щось подібне за допомогою Perl та 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";

Потім ви можете запустити цей сценарій так:

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

1
Охайне рішення! :)
coffeMug

3
Розбирати HTML з регулярними виразами не так просто. Теги, написані як "<TITLE>", "<title lang = en>", "<title \ n>", не будуть відповідати вашому вираженню. Ще більша проблема, ні "<title> \ noops \ n </title>" не буде.
манастирство

4
Спроба розбору html за допомогою регулярного вираження тут, як правило, нахмуриться .
користувач3490

1
@slm, <title>Unix\nLinux</title>покликаний бути Unix Linux, ні UnixLinux.
Стефан Шазелас

1
+1 Для рубіну + нокогірі. Я використовував його для всіх видів веб-вискоблювання, це дивовижно!
Роб

7

Використання простого регулярного вираження для розбору HTML наївно. Наприклад, з новими рядками та ігноруванням спеціального кодування символів, зазначеного у файлі. Зробіть правильно і дійсно проаналізуйте сторінку, використовуючи будь-який з інших реальних аналізаторів, згаданих в інших відповідях, або скористайтеся наступним вкладишем:

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

(Сказане вище включає символ Unicode).

BeautifulSoup також обробляє безліч невірних HTML (наприклад, відсутні теги закриття), які б повністю кинули спрощене повторне вирівнювання. Ви можете встановити його в стандартний пітон, використовуючи:

pip install beautifulsoup4

або якщо у вас немає pip, с

easy_install beautifulsoup4

Деякі операційні системи, такі як Debian / Ubuntu, також мають її в упаковці ( python-bs4пакет на Debian / Ubuntu).


2
bs4відсутня в стандартній бібліотеці пітона. Ви повинні встановити його за допомогою easy_install beautfulsoup4(не easyinstall bs4).
Антон

@Anthon включив вашу інформацію
Zelda

5

Можливо, це "обман", але одним із варіантів є " pup", аналізатор командного рядка HTML .

Ось два способи зробити це:

Використання metaполя з property="og:titleатрибутом

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

та інший спосіб використання titleполя безпосередньо (а потім відключення - YouTubeрядка в кінці).

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

Щоб уникнути сутності символів, користувачі можуть скористатися --plainпараметром pup .
пік

3

Здається, це можливо за lynxдопомогою цього фокусу ( zsh, bashсинтаксису):

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'

Оскільки це веб-браузер у реальному житті, він не зазнає багатьох обмежень, про які я згадую в своїй іншій відповіді .

Тут ми використовуємо той факт, що lynxвстановлює $LYNX_PRINT_TITLEзмінну середовища на заголовок поточної сторінки при друку сторінки.

Вище ми надаємо файл конфігурації (як трубу), який визначає рись "принтер", який називається, Pщо просто виводить вміст цієї змінної в дескриптор файлу 3( дескриптор цього файлу перенаправляється на lynxstdout з 's, 3>&1поки lydx stdout сам перенаправляється до / dev / null).

Тоді ми використовуємо інструмент lynxсценаріїв для імітації натискання користувача p, а також End(виберіть) і Enter( ^J).

-accept_all_cookies оскільки в іншому випадку рись попросить у користувача підтвердження для кожного файлу cookie.


3

Простий спосіб:

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

Мало альтернатив:

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

1
Це єдині, хто працював на мене!
Ахмад Авайс

1

Мені сподобалася ідея Стефана Шазеласа використовувати Lynx та LYNX_PRINT_TITLE, але цей сценарій не працював для мене під Ubuntu 14.04.5.

Я створив спрощену версію, використовуючи запуск Lynx та використання файлів, попередньо налаштованих заздалегідь.

Додайте наступний рядок до /etc/lynx-cur/lynx.cfg (або там, де знаходиться ваш lynx.cfg):

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

Цей рядок вказує зберегти заголовок під час друку в "/home/account/title.txt" - ви можете вибрати будь-яке ім'я файлу, яке ви бажаєте. Ви вимагаєте ДУЖЕ великих сторінок, збільшуйте вищевказане значення з "1000" на будь-яку кількість рядків на потрібній сторінці, інакше Lynx зробить додаткове підказку "при друкуванні документа, що містить дуже велику кількість сторінок".

Потім створіть /home/account/lynx-script.txt файл із таким вмістом:

key p
key Select key
key ^J
exit

Потім запустіть Lynx, використовуючи такі параметри командного рядка:

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

Після завершення цієї команди буде створено файл /home/account/title.txt із заголовком вашої сторінки.

Коротше кажучи, ось функція PHP, яка повертає заголовок сторінки на основі вказаної URL-адреси або помилковий у випадку помилки.

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

Використовуючи nokogiri, ви можете отримати простий запит на основі CSS для вилучення внутрішнього тексту тегу:

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

Аналогічно, щоб отримати значення атрибута "content" тегу:

$ nokogiri -e 'puts $_.at_css("meta[name=title]").attr("content")'
Why Are Bad Words Bad?
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.