web-dev-qa-db-ja.com

コマンドラインを使用してWebサイトのタイトルを取得するにはどうすればよいですか?

Webサイトのタイトルを出力するコマンドラインプログラムが必要です。例:

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

与える必要があります:

Why Are Bad Words Bad? 

URLを指定すると、タイトルが出力されます。

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

&lt;のようなものがそこにある場合は、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を勧めたでしょう。しかし、最近では、ほとんどのGNU=ほとんどのLinuxベースのデスクトップ/ラップトップオペレーティングシステムを含む)システムでデフォルトで検出できるため、wgetはよりポータブルです。他のかなりポータブルなものには、付属のGETコマンドが含まれます頻繁にインストールされるPerlのlibwww、lynx -source、およびより少ない程度curlを使用します。その他common ones include links -sourceelinks -sourcew3m -dump_sourcelftp -c cat...

HTTPプロトコルとリダイレクト処理

wgetは、たとえばfirefoxが表示するページと同じページを取得しない場合があります。その理由は、HTTPサーバーが、クライアントから送信されたリクエストで提供された情報に基づいて、別のページを送信することを選択する可能性があるためです。

Wget/w3m/GET ...によって送信される要求は、firefoxによって送信される要求とは異なります。それが問題である場合は、wgetの動作を変更して、オプションを使用してリクエストを送信する方法を変更できます。

この点でここで最も重要なものは次のとおりです。

  • AcceptおよびAccept-language:クライアントが応答を取得する言語と文字セットをサーバーに通知します。wgetはデフォルトでは何も送信しないため、サーバーは通常、デフォルトの設定で送信します。反対側のfirefoxは、おそらく言語を要求するように構成されています。
  • User-Agent:サーバーに対してクライアントアプリケーションを識別します。一部のサイトは、クライアントに基づいて異なるコンテンツを送信しますが(これは主にJavaScript言語の解釈の違いのためです)、wgetのようなrobot-typeユーザーエージェントを使用している場合、サービスの提供を拒否することがあります。
  • Cookie:以前にこのサイトにアクセスしたことがある場合、ブラウザに永続的なCookieが設定されている可能性があります。 wgetはしません。

wgetは、HTTPプロトコルレベルでリダイレクトが行われるときにリダイレクトに従いますが、ページのコンテンツではなく、JavaScriptや<meta http-equiv="refresh" content="0; url=http://example.com/">などで行われるリダイレクトではありません。

パフォーマンス/効率

ここでは、怠惰であるため、<title>タグの検索を開始する前に、メモリ内のコンテンツ全体をPerl読み取ります。タイトルがファイルの最初の数バイトにある<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はダウンロード時にページを書き込みます。同時に、Perlは出力(-0777 -n)全体をメモリ内で丸呑みし、最初に出現する<title...></titleの間にあるHTMLコードを出力します。

これは、<title>タグが付いているほとんどのHTMLページで機能しますが、機能しない場合もあります。

対照的に、 coffeeMugのソリューション は、HTMLページをXMLとして解析し、titleの対応する値を返します。より正確ですページが有効なXMLであることが保証されている場合。ただし、HTMLは有効なXMLである必要はありません(以前のバージョンの言語はそうではありませんでした)。ほとんどのブラウザーは寛大であり、正しくないHTMLコードを受け入れるため、そこには多くの誤ったHTMLコードさえあります。

私のソリューションと coffeeMug's は、さまざまなコーナーケースで失敗します。

たとえば、私は失敗します:

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

または:

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

彼が失敗する間:

<TITLE>foo</TITLE>

(xmlではなく有効なhtml)または:

または:

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

(ここでも、有効なhtml、有効なXMLにするための<![CDATA[パーツがありません)。

<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

ただし、Webクライアントは、タイトルを表示するときにそのコードをさらに変換することも目的としています(空白の一部を圧縮し、先頭と末尾の空白を削除するなど)。しかし、それが必要になることはまずありません。したがって、他の場合と同様に、努力する価値があるかどうかを判断するのはあなた次第です。

Character set

UTF-8以前は、厳密には&eacute;と記述する必要がありましたが、iso8859-1は非ASCII文字のWebではpreferred文字セットでした。最近のバージョンのHTTPおよびHTML言語では、HTTPヘッダーまたはHTMLヘッダーで文字セットを指定できるようになり、クライアントは受け入れる文字セットを指定できます。現在、UTF-8がデフォルトの文字セットになる傾向があります。

つまり、これはé&eacute;として、&#233;として、UTF-8として記述されていることを意味しますé、(0xc3 0xa9)、iso- 8859-1(0xe9)、最後の2つについては、HTTPヘッダーまたはHTMLヘッダー(異なる形式)の文字セットに関する情報が含まれる場合とそうでない場合があります。

wgetは、生のバイトのみを取得します。文字としての意味を考慮せず、優先する文字セットをWebサーバーに通知しません。

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でエンコードされたページではまったく機能しないことにも注意してください。

総括する

理想的には、ここで必要なのは、情報を提供する実際のWebブラウザーです。つまり、適切なパラメーターを使用してHTTP要求を実行し、HTTP応答を正しく解釈し、ブラウザーが行うようにHTMLコードを完全に解釈し、タイトルを返すために何かが必要です。

私が知っているブラウザーを使用してコマンドラインで実行できるとは思わないので(今すぐ lynx でこのトリックを参照してください)、ヒューリスティックと近似に頼る必要があります。上記のものはどれも同じです。

また、パフォーマンス、セキュリティを考慮したい場合もあります。たとえば、すべてのケース(たとえば、タイトルを設定したり、別のページにリダイレクトしたりするサードパーティのサイトからJavaScriptを取得したWebページ) onloadフック)、単一のHTMLページに対して何百ものクエリを実行する必要があるdomおよびJavaScriptエンジンを備えた実際のブラウザを実装する必要がある場合があります。その一部は脆弱性を悪用しようとします...

正規表現を使用してHTMLを解析することはよくありませんが 、ここでは、タスク(IMO)に十分に対応できる典型的なケースを示します。

47

次のように、hxselectwgetで( HTML-XML-Utils から)試すこともできます。

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

以下を使用して、Debianベースのディストリビューションにhxselectをインストールできます。
_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)}'にパイプします。

28
coffeMug

curlおよびgrepを使用してこれを行うこともできます。 grepPCRE(Perl互換の正規表現) を使用することで、<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">のように設定されている場合は、grepingする前にこれを削除する必要があります。これを行うには、ツール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=に続いてWordシーケンス(\w+)を検出します。その後、取り除かれます。

実際のHTML/XMLパーサー-Rubyの使用

ある時点で、正規表現はこのタイプの問題の解決に失敗します。その場合は、実際のHTML/XMLパーサーを使用することをお勧めします。そのようなパーサーの1つは 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メソッドは、titleという名前のリーフノード(//)であるHTML内のノード(タグ)を検索します。見つかったそれぞれについて、そのコンテンツ(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 
18
slm

単純な正規表現を使用してHTMLを解析するのは簡単です。例えば。改行を含み、ファイルで指定された特殊文字エンコーディングを無視します。正しいことを行い、他の回答で言及されている他の実際のパーサーのいずれかを使用してページを実際に解析するか、次の1つのライナーを使用します。

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のパッケージ)。

7
Zelda

多分それは「不正行為」ですが、1つのオプションは pup、コマンドラインHTMLパーサー です。

これを行うには2つの方法があります。

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?
6
abetusk

このトリックを使用すると、lynxで可能であるようです:

lynx 3>&1 > /dev/null -nopause -noprint -accept_all_cookies \
  -cmd_script /dev/stdin<<'EOF' 'http://www.youtube.com/watch?v=Dd7dQh8u4Hc'
set PRINTER=P:printf '%0s\\n' "$LYNX_PRINT_TITLE">&3:TRUE
key p
key Select key
key ^J
exit
EOF

これは実際のWebブラウザーなので、筆者が other answer で言及した制限の多くに悩まされることはありません。

ここでは、ページを印刷するときに、lynx$LYNX_PRINT_TITLE環境変数を現在のページのタイトルに設定するという事実を使用しています。

上記では、lynxスクリプト機能を使用して(ヒアドキュメント経由で標準入力に渡されるスクリプトを使用)、次のことを行います。

  1. その変数の内容をファイル記述子3に出力するPと呼ばれるlynx "プリンター"を定義します(そのファイル記述子はlynxのstdoutに3>&1でリダイレクトされます。 lynx stdout自体は/ dev/nullにリダイレクトされます)。
  2. ユーザーが押すことをシミュレートする p、 そしてその End (別名 Select)、および Enter (^J)。
4

簡単な方法:

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'
3
kenorb

LynxとLYNX_PRINT_TITLEを使用するStéphaneChazelasのアイデアは気に入りましたが、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」から1ページあたりの任意の行数に増やします。それ以外の場合、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");
1
Maxim Masiutin

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?
1
peak

Python3 + beautifulsoupの例は

python3 -c "import bs4, requests; print(bs4.BeautifulSoup(requests.get('http://www.crummy.com/software/BeautifulSoup/bs4/doc/').content).title.text)"
0
Nik

Xidelを使用する:

$ xidel -s http://www.youtube.com/watch?v=Dd7dQh8u4Hc --css title
Why Are Bad Words Bad? - YouTube

必要であれば、 apt install xidel または類似。

0
JJoao