Я хочу, щоб програма командного рядка друкувала заголовок веб-сайту. Наприклад:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
повинен дати:
Why Are Bad Words Bad?
Ви надаєте йому URL-адресу, і вона виводить заголовок.
Я хочу, щоб програма командного рядка друкувала заголовок веб-сайту. Наприклад:
Alan:~ titlefetcher http://www.youtube.com/watch?v=Dd7dQh8u4Hc
повинен дати:
Why Are Bad Words Bad?
Ви надаєте йому URL-адресу, і вона виводить заголовок.
Відповіді:
wget -qO- 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc' |
perl -l -0777 -ne 'print $1 if /<title.*?>\s*(.*?)\s*<\/title/si'
Ви можете передавати його GNU, recode
якщо в ньому є такі речі <
:
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
...
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
до припинення завантаження.
Тут wget
пише сторінка під час її завантаження. У той же час, perl
Sururs його вихід ( -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 & 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, хоча строго кажучи, їх потрібно було писати як é
. Більш новітні версії HTTP та мови HTML додали можливість задавати набір символів у заголовках HTTP або в заголовках HTML, і клієнт може вказати схеми, які він приймає. На сьогодні UTF-8, як правило, є набором даних за замовчуванням.
Отже, це означає, що там ви знайдете é
написані як é
, як é
UTF-8 é
, (0xc3 0xa9), як iso-8859-1 (0xe9), з двома останніми, іноді інформацією на графіці у заголовках HTTP або заголовках HTML (у різних форматах), іноді немає.
wget
отримує лише неочищені байти, він не дбає про їх значення як символи, і не повідомляє веб-серверу про бажану схему.
recode html..
подбає про перетворення é
або é
в належну послідовність байтів для набору символів, використовуваних у вашій системі, але для решти, це складніше.
Якщо ваш системний набір - 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'appartement - YouTube
Це é
було UTF-8 é
.
Але якщо ви хочете прикрити інші шаблони, про це слід подбати ще раз.
Слід також зазначити, що це рішення взагалі не працюватиме на кодованих сторінках UTF-16 або UTF-32.
В ідеалі, що вам тут потрібно, це справжній веб-браузер, який дає вам інформацію. Тобто вам потрібно щось зробити для HTTP-запиту з належними параметрами, правильно інтерпретувати відповідь HTTP, повністю інтерпретувати HTML-код як браузер і повернути заголовок.
Оскільки я не думаю, що це можна зробити в командному рядку з відомими мені браузерами (хоча дивіться зараз цей трюкlynx
), ви повинні вдатися до евристики та наближень, і те, що вище, так само добре, як і будь-яке.
Ви також можете взяти до уваги продуктивність, безпеку ... Наприклад, щоб охопити всі випадки (наприклад, веб-сторінку, яка має деякий javascript, витягнутий із стороннього сайту, який встановлює заголовок або перенаправляє на іншу сторінку в при завантаженні гачка), можливо, вам доведеться реалізувати браузер у реальному житті зі своїми системами dom та javascript, які, можливо, повинні робити сотні запитів для однієї сторінки HTML, деякі з яких намагаються використовувати вразливості ...
У той час як використання регулярних выражень для розбору HTML часто піддається нахабству , ось типовий випадок, коли він достатньо хороший для виконання завдання (IMO).
<
оскільки в заголовках не гарантується наявність кінцевих тегів, а будь-який інший тег повинен змусити його припинити. Можливо, ви також хочете зняти нові лінії.
Ви також можете спробувати hxselect
(з HTML-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)}'
.
sudo apt-get install html-xml-utils
hxselect
.
Ви також можете використовувати 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
Якщо значення <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-аналізатор. Одним з таких аналізаторів є 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
Вище описано аналіз даних, що надходять через curl
HTML ( Nokogiri::HTML
). Потім метод xpath
шукає у HTML вузлах (тегах), які є вузлами листя, ( //
) з назвою title
. Для кожного знайденого ми хочемо повернути його вміст ( e.content
). puts
Потім друкує їх.
Ви також можете зробити щось подібне за допомогою 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
<title>Unix\nLinux</title>
покликаний бути Unix Linux
, ні UnixLinux
.
Використання простого регулярного вираження для розбору 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).
bs4
відсутня в стандартній бібліотеці пітона. Ви повинні встановити його за допомогою easy_install beautfulsoup4
(не easyinstall bs4
).
Можливо, це "обман", але одним із варіантів є " 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 .
Здається, це можливо за 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
( дескриптор цього файлу перенаправляється на lynx
stdout з 's, 3>&1
поки lydx stdout сам перенаправляється до / dev / null).
Тоді ми використовуємо інструмент lynx
сценаріїв для імітації натискання користувача p
, а також End
(виберіть) і Enter
( ^J
).
-accept_all_cookies
оскільки в іншому випадку рись попросить у користувача підтвердження для кожного файлу cookie.
Простий спосіб:
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'
Мені сподобалася ідея Стефана Шазеласа використовувати 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");
Використовуючи 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?