Я хочу программу командной строки, которая печатает заголовок веб-сайта. Например:
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команду, которая поставляется с perllibwww, которая часто устанавливается 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пишет страницу, как она загружает его. В то же время, perlslus свой 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?