Я хочу программу командной строки, которая печатает заголовок веб-сайта. Например:
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
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
: идентифицирует клиентское приложение на сервере. Некоторые сайты отправляют разный контент на основе клиента (хотя это в основном из-за различий между интерпретациями языка javascript) и могут отказаться обслуживать вас, если вы используете пользовательский агент типа робота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
slus свой output ( -0777 -n
) целиком в памяти, а затем печатает HTML-код, найденный между первыми вхождениями <title...>
и </title
.
Это будет работать для большинства HTML-страниц, имеющих <title>
тег, но в некоторых случаях это не сработает.
В отличие от этого решение coffeeMug будет анализировать HTML-страницу как XML и возвращать соответствующее значение для title
. Более правильно, если на странице гарантированно указан правильный XML . Тем не менее, HTML не обязательно должен быть действительным XML (более ранние версии языка не были), и поскольку большинство браузеров проявляют снисходительность и будут принимать неправильный HTML-код, существует даже много неправильного HTML-кода.
И моё решение, и CoffeeMug не удастся для разных угловых случаев, иногда одинаковых, иногда нет.
Например, у меня не получится:
<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 iso8859-1 раньше был предпочтительным набором символов в сети для символов, не относящихся к ASCII, хотя, строго говоря, они должны были быть записаны как é
. Более поздние версии HTTP и язык HTML добавили возможность указывать набор символов в заголовках HTTP или в заголовках HTML, и клиент может указывать кодировки, которые он принимает. UTF-8 сегодня является набором символов по умолчанию.
Таким образом, это означает , что там, вы найдете é
написанные , как é
, так é
как UTF-8 é
, (0xC3 0xa9), в ISO-8859-1 (0xe9), с за 2 последних из них, иногда информацию о кодировке в заголовках 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, извлеченный из стороннего сайта, который устанавливает заголовок или перенаправляет на другую страницу в onload hook), вам, возможно, придется реализовать реальный браузер с его механизмами 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=
за которой следует слово sequence ( \w+
). Это тогда раздето.
В какой-то момент регулярное выражение не сможет решить эту проблему. Если это произойдет, вы, вероятно, захотите использовать настоящий анализатор HTML / XML. Одним из таких парсеров является Nokogiri . Он доступен в Ruby как Gem и может использоваться следующим образом:
$ 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 (например, отсутствующих закрывающих тегов), что полностью исключает упрощенное регулярное выражение. Вы можете установить его в стандартном Python, используя:
pip install beautifulsoup4
или, если у вас нет pip
, с
easy_install beautifulsoup4
Некоторые операционные системы, такие как Debian / Ubuntu, также имеют python-bs4
пакет ( пакет в Debian / Ubuntu).
bs4
отсутствует в стандартной библиотеке Python. Вы должны установить его с помощью 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
опцию щенка .
Кажется, это возможно с 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
переменную среды в заголовок текущей страницы при печати страницы.
Выше мы даем файл конфигурации (как канал), который определяет вызываемый lynx «принтер», P
который просто выводит содержимое этой переменной в файловый дескриптор 3
(этот файловый дескриптор перенаправляется в стандартный lynx
вывод с, в 3>&1
то время как сам lynx stdout перенаправляется сам по себе). в / dev / null).
Затем мы используем средства lynx
сценариев для имитации нажатия клавиш пользователем p
, а также End
(он же select) и Enter
( ^J
).
-accept_all_cookies
в противном случае lynx будет запрашивать у пользователя подтверждение для каждого файла 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-адреса или false в случае ошибки.
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?