プロが教えるわが家の防犯対策術!

ローカルにおいてある HTML ファイルを読み込ませて、<IMG SRC="sample.gif"> から sample.gif を取得します。
このsample.gifのMD5を取得し、たとえば MD5 が "abcd...xyz" であれば、
(ローカルの別フォルダ)/a/b/abcd...xyz.gif にコピーし、
元の参照を <IMG SRC="a/b/abcd...xyz.gif"> に変換するというスクリプトを書きたいと考えています。

HTML ファイルから sample.gif を取り出す方法、ファイルからMD5を取得する方法について教えていただけないでしょうか。

HTMLのパースなど調べたのですが、特定の属性を書き換える方法は
分かりませんでした。
よろしくお願いいたします。

A 回答 (3件)

こんにちは、


書いてから気が付きましたが、画像を先にコピーして、
コピーした情報をハッシュとかに持っといて、その後、その情報を元に HTML を書き換えた方がいいかもですね。

以下のスクリプトは複数参照されている画像は何度もコピーされる事になりますし、エラーも完全無視です、ファイルのロックもしてません。
テストもろくにしてませんし、責任持てませんので、ご自分で書かれる際の参考程度にして下さい。

ファイルを読み込んで正規表現で置換してるだけです。
モジュールは perl5.8 なら多分標準だと思います。

md5 は http://search.cpan.org/~gaas/Digest-MD5-2.36/MD5 … を参考にしてみてください。


#! perl
use 5.008;
use strict;
use warnings;
use Digest::MD5;
use File::Copy;

main();

sub main {

  #画像のコピー先ディレクトリ
  my $path = './copy/';

  local $/ = undef;

  #同ディレクトリ内の拡張子が .html のファイル全て
  for my $file ( glob('*.html') ) {

    open my $fh, '+<', $file or next;

    my $source = <$fh>;

    $source =~ s{(<img [^>]* src=")([^"]+)}
            { $1 . rename_image( $2, $path ) }igesmx;

    truncate $fh, 0;
    seek $fh, 0, 0;
    print {$fh} $source;
    close $fh or next;

  }

}

sub rename_image {

  my( $img, $path ) = @_;

  my( $name, $ext ) = $img =~ /^(.*)(\.\w+)$/;

  my $new_name = $path . Digest::MD5::md5_hex($name) . $ext;

  File::Copy::copy( $img, $new_name ) or return $img;

  return $new_name;

}

参考URL:http://search.cpan.org/~gaas/Digest-MD5-2.36/MD5 …
    • good
    • 0
この回答へのお礼

ありがとうございます。
ソースまで提供していただき、大変助かります。
動作の確認をしましたが、希望している動作とは多少異なるようです。
・引数で読み込むhtmlファイルを指定したい
・フォルダの掘り方が違う
・フォルダがなければ作るようにしたい
・できれば、修正後のhtmlは別ファイルにしたい

いただいたソースで理解できているのはこんな感じです。
・open でファイルを開いて$sourceに入れ、
・正規表現で<img~src="..." の ... を取得し、
・rename_image でそのファイルのMD5を取得し、
・元のファイルのパスも変更する

で、自分で修正しようと思うのですが、やっぱり分かりません。
自分でperlを書いていたときは、open でファイルをオープンして、
while (<FH>) などで行ごとに処理してましたが、
提示していただいたソースではファイルごと$sourceに入れてるんですか??

s{..} の正規表現部分も )( の意味が分かりません。私が書くと
<img[^>]* src="([^"]+)
()でくくったら$1に入る?のかと思うのですが、残念ながら何もマッチしない・・・。
この s{...}{...}igesmx;
としている s って置換の関数?

perl って省略が多いせいか、調べても分からない部分が多くて・・。
いい参考サイトがあったら教えてください。

MD5についてはもう少し理解できてから拝見させていただきます。

お礼日時:2008/09/19 17:30

>perl って省略が多いせいか、調べても分からない部分が多くて・・。


>いい参考サイトがあったら教えてください。

どの言語でもそうですが、サイトでチョコチョコ調べるというよりは最初はドンと本で勉強した方がいいと思いますよ。

http://www.amazon.co.jp/gp/product/4774108170/re …

http://www.amazon.co.jp/%E5%88%9D%E3%82%81%E3%81 …
    • good
    • 0

こんにちは、


> ・引数で読み込むhtmlファイルを指定したい
コマンドプロンプトから perl xxxx.pl ファイル名
とかやって、スクリプト内で、$ARGV[0] を参照すれば良いと思います。

> ・フォルダの掘り方が違う
これも引数とかで指定してやれば良いと思います。


> ・フォルダがなければ作るようにしたい
ファイルテスト演算子を使って判定して、なければ、mkdir すればよいとおもいます。

> ・できれば、修正後のhtmlは別ファイルにしたい
ファイルのオープンを読み込みオープンにして、
任意のファイル名で新規書き出ししてください。

> いただいたソースで理解できているのはこんな感じです。
> ・open でファイルを開いて$sourceに入れ、
> ・正規表現で<img~src="..." の ... を取得し、
> ・rename_image でそのファイルのMD5を取得し、
> ・元のファイルのパスも変更する
その通りです。

> で、自分で修正しようと思うのですが、やっぱり分かりません。
> 自分でperlを書いていたときは、open でファイルをオープンして、
> while (<FH>) などで行ごとに処理してましたが、
> 提示していただいたソースではファイルごと$sourceに入れてるんですか??
です。
local $/ = undef;
で、ファイルを丸呑みするようになります。


> s{..} の正規表現部分も )( の意味が分かりません。私が書くと
> <img[^>]* src="([^"]+)
> ()でくくったら$1に入る?のかと思うのですが、残念ながら何もマッチしない・・・。
> この s{...}{...}igesmx;
> としている s って置換の関数?
$str =~ s/hoge/fuga/;
で、$str 内の 'hoge' を 'fuga' に置換します。
正規表現はあまり得意じゃないので、アレなんですが…
正規表現内で()で括ると後方参照できるようになります。
最初の括弧でキャプチャした文字列を$1次の括弧が$2…てな感じです。

で、イメージタグの src 属性のファイル名の直前までの文字列を$1にキャプチャして、
$2 にファイル名をキャプチャしているつもりです。
で、それをサブルーチンに渡して、コピーできたら、新しいファイル名を返してくるので、
そのファイル名とさっきキャプチャしたファイル名直前までの文字列を結合して、
マッチした全体と置換しているつもりです。

正規表現に e オプションをつけると、perl スクリプトとして評価されます。
正規表現のオプションに関しては、google 先生に尋ねてください。

勝手な事しまして、かえって混乱させてしまったようですね、すみませんです。

通常、ファイルは1行ずつ処理した方が少ないメモリで処理できて良いのでしょうが、
ローカルで行う処理なら、丸呑みも良いと思います。
その為のモジュールもありますので、時間が合ったら調べてみられたら良いかもです。
    • good
    • 0
この回答へのお礼

ありがとうございました!

ちょっと分からないところが多かったのですが、
じっくり調べながらソースを読み返してみると、
ほぼ理解でき、目的のものも作ることができました。

> $str =~ s/hoge/fuga/;
これは知ってたのですが、
$str =~ s{hoge}{fuga};
と書いてもよいんですね。別の関数かなんかなのかと思ってしまいました。

扱ってるhtml ファイルはサイズも大して大きいものがないので、
ファイルを丸ごと処理できる方法を教えていただき、とても助かりました。
複数行にまたがるタグも多いのですが、その置換もできました。

本当にありがとうございました。

お礼日時:2008/09/20 18:05

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!