bash - 複数のリンクを含むhtmlファイルからファイル名を抽出する

bash - 複数のリンクを含むhtmlファイルからファイル名を抽出する

Webページのスクリプトによって自動的に生成されるhtmlファイルをダウンロードしました。ファイルに画像リンクを含む複数のリンクが含まれています。画像のフルネームを抽出しようとしています。

<a href="000000.jpg" title="image name.jpg" target="_blank">Image name.jpg</a>

上から"Image name.jpg"ファイルに保存したいです。そのような名前は何百ものあるため、ファイルを解析し、次のコマンドを使用して表示されるように各名前を保存します。

grep -i -E -o "target=\"_blank\">([[:graph:]]*)\.(jpg|png|gif|webm)" "$thread" | cut -f 2 -d '>' | sed 's/ /_/g' - > "$names"

ここで、 " $thread"はhtmlファイルの名前、 " $names"は出力されるファイル名のリストです。 " "を使用してその部分を削除cutし、'target="_blank">'スペースをアンダースコアに変換します。

ファイルに異なるリンクが複数あるため、クロールする拡張子(imageとwebm)を指定しました。他のすべては無視する必要があります。これらのリンクだけがクロールされましたが、一部のリンクが欠落しているポイントに達しました。

一部のファイルには、スペースと英数字以外の文字が含まれています。これらすべてのケースをカバーする必要があるwhichを使用すると、何も得られないか、html部分[[:print:]]だけが得られ、他のものは何も得られません。<head>使用すると[[:graph:][:space:]]何も得られません。[[:graph:]]上記のように使用したり、[[:alnum:][:punct:]]英数字/その他の文字( "")を含むfilenamewith(parenthesis).jpgファイルをインポートしたりできますが、空白は含まれていないか、その逆の場合は[[:alnum:][:space:]]機能しますが、印刷可能な他の文字を無視します( " file name with spaces.jpg"は機能しますが "一緒に"は使用しません)(括弧、カンマ、またはその他.jpg")。

すべての場合を包括するというのです[[:print:]]が、私が正しく理解したら必要なものを得られません。

grep -E -o(上記に基づいて)一致する必要があります: *.jpg *.png *.gifまたは*.webm

grep私は持っているかどうか、-E/-o/-eさまざまなバリエーションを試しました。

どんなアイデアがありますか?私はArch Linux、grep 2.20、bash 4.3.18を使用しています。

答え1

最良の戦略は、<a>すべてのタグの値を出力できる適切なHTMLパーサーを使用することです。

これはxmlstarlet特にXMLパーサーです。 HTMLは正しい形式のXMLではないかもしれませんが、おそらく次のアイデアを得ることができます。

echo '<html>
<a href="000000.jpg" title="image name.jpg" target="_blank">Image name.jpg</a>
</html>' | xmlstarlet sel -t -v //a
Image name.jpg

答え2

あなたの正規表現は

target="_blank">([[:graph:]]*)\.(jpg|png|gif|webm)

これは、リテラルテキストtarget="_blank">、空白以外の文字の数、最後に4つの文字列のうちの1つ、またはに.jpg一致します。たとえば、grep コマンドは次の行の太字を出力します。.png.gif.webm

<1つ...target="_blank">何か.jpg</a>
<1つ...target="_blank">a.gifted.child.txt</a>
<a … target="_blank">その他.jpg</a>
<1つ...target="_blank">something.jpg</a>+more.jpg

[[:print:]]代わりに使用すると、[[:graph:]]次のようになります。

<1つ...target="_blank">something.jpg</a>ウィブルウォブル<a … target="_blank">something else.jpg</a>

target …行の最初の一致ビットと最後の一致拡張子の間のすべての項目が一致します。

一致からHTMLマークアップ文字を除外する必要があります。

target="_blank">[^<>]*\.(jpg|png|gif|webm)</a>

GNU grepを使用すると、-Pオプションを使用して設定を取得できますパール正規表現、特に幅0のアサーション一致部分にそのテキストを含めずに、一部の定数テキストが前後に来ることを指定できます。

grep -o -P '(?<target="_blank">)[^<>]*\.(jpg|png|gif|webm)(?=</a>)'

<a>予期しない空白(たとえば、タグとクローズ文字の間、または改行文字の間に改行文字など)があると、</a>まだ失敗する可能性があります。することができます適切なHTMLパーサーを使用することをお勧めします

たとえば、Pythonでは美しいスープ(テストされていません):

import re, sys, BeautifulSoup
soup = BeautifulSoup(sys.stdin)
for hit in soup.find_all('a', target='_blank'):
    if re.match(r'.*\.(jpg|png|gif|webm)\Z', hit.string):
        print(hit.string)

同様のコードは次のように書くことができます。HTML::ParserPerlではノコチェルビーなどから

答え3

私は最終的にこれをしました:

w3m -dump -T text/html "$thread" | grep -i -E -o 'File\:+([[:print:]]*)\.(jpg|png|webm|gif)'

w3m このコードをクリーンアップし、grep でファイル名を見つけることができます。 (リンクされたファイルをタイトルと区別するには、リテラルの「ファイル:」部分が必要です)。ほとんどのスペース、Unicode文字、その他の印刷可能なコンテンツをキャプチャするため、[[:print:]]が必要です。

期待どおりに動作します。 (同じ名前のファイルを上書きするのを防ぐ方法を理解する必要がありますが、それは別の日の戦いです。)

関連情報