03 May 2011

(Perl) sitemap.xml の全URLをW3C HTML Validatorでチェックするスクリプト

sitemap.xml内の全URLをW3C HTML Validatorで連続して検査し、結果をHTMLファイルに書き込むスクリプト。

攻撃と思われては困るので、1個のURLを検査した後に、10秒スリープする仕様とした。
(約100個のURL検査したら、”Could not contact validator” を返されたので、60秒くらいスリープしたほうがよかったのか…。 どうも攻撃と思われたようです。スイマセン)

→ 『 (Perl) ローカルにインストールしたW3C Markup Validatorを用いてWebService::Validator::HTML::W3Cでのチェックを行う 』 の記事も併せてお読みください。


#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use File::Basename;
use Getopt::Long;
use XML::Parser;
use XML::SimpleObject;
use WebService::Validator::HTML::W3C;


my $xml_filepath;
my $output_html;
my @arr_urls;
my $wait_sec = 60; # wait 60 second, for W3C server load control

# プログラム引数を取り込む
GetOptions('xml=s' => \$xml_filepath,
'output=s' => \$output_html);

if(!defined($xml_filepath) || !defined($output_html)){
die("W3C html validator\n usage :\n ".basename($0)." -xml=[sitemap.xml] -output=[out.html]\n");
}

# 無効文字のチェックと削除
$xml_filepath =~ s/[\x00-\x2c|\x3a-\x40|\x5b-\x5e|\x60|\x7b-\xff]//g;
$output_html =~ s/[\x00-\x2c|\x3a-\x40|\x5b-\x5e|\x60|\x7b-\xff]//g;

unless( -f $xml_filepath ){
die("Error : sitemap file ".$xml_filepath." not found\n");
}

print("Target File : ".$xml_filepath."\nOutput File : ".$output_html."\n");

# XMLからURLを抜き出して配列に格納する
my $p = new XML::Parser(Style=>'Tree');
my $s = new XML::SimpleObject($p->parsefile($xml_filepath));
my @arr = $s->child('urlset')->child('url');
foreach(@arr){
push(@arr_urls, $_->child('loc')->value);
}

if($#arr_urls < 0){
die("Error : no url found from sitemap file\n");
}

print(($#arr_urls+1)." URLs found.\nW3C query start ...\n");

my $v = WebService::Validator::HTML::W3C->new(detailed => 1);

open(FH, '>'.$output_html) or die("Error : ".$output_html." open error\n");

# バッファリング無効化
my $old_fh = select FH;
$|=1;
select $old_fh;

print(FH "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n".
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n".
"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"ja-JP\" xml:lang=\"ja-JP\">\n".
"<head>\n".
"<title>W3C html validator result</title>\n".
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n".
"<style type=\"text/css\">\n".
"table { border:1px solid rgb(153, 51, 51); border-collapse:collapse;".
" font-size: 10pt; margin: 10px; }\n".
"th { font-weight: normal; background:#f8ede2; border:1px solid rgb(153, 51, 51);".
" padding: 0.2em 0.4em; text-align: left; }\n".
"td { border:1px solid rgb(153, 51, 51); padding: 0.2em 0.4em; }\n".
"</style>\n".
"</head>\n".
"<body>\n".
"<p>".($#arr_urls+1)." URLs</p>\n".
"<table>\n");

foreach(@arr_urls){
my $target_url = $_;
print(" ".$target_url."\n");

if($v->validate($target_url)){
if ( $v->is_valid ) {
printf (FH "<tr><th colspan=\"3\"><a target=\"_blank\" href=\"%s\">%s</a> : valid</th></tr>\n", $v->uri, $v->uri);
}
else {
printf (FH "<tr><th colspan=\"3\"><a target=\"_blank\" href=\"%s\">%s</a> : not valid</th></tr>\n", $v->uri, $v->uri);
foreach my $error ( @{$v->errors} ) {
printf(FH "<tr><td></td><td>%d</td><td>%s</td></tr>\n", $error->line, $error->msg);
}
}
}
else {
printf (FH "<tr><th colspan=\"3\"><a target=\"_blank\" href=\"%s\">%s</a> : Fatal Error : %s</th></tr>\n", $target_url, $target_url, $v->validator_error);
}

sleep($wait_sec); # W3Cサーバ負荷防止のため、ウエイトを入れる
}

print(FH "</table>\n</body>\n</html>\n");

close(FH);

print("program end\n");

■ (入力ファイル) sitemap.xml のサンプル


<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>/r271-635/</loc>
<priority>1.0</priority>
</url>
<url>
<loc>/r271-635/2011/05/linux_conky_and_screenlets.html</loc>
<lastmod>2011-05-01T05:45:50Z</lastmod>
</url>
<url>
<loc>/r271-635/2011/04/ubuntu_freebsd_locale.html</loc>
<lastmod>2011-04-30T07:16:29Z</lastmod>
</url>
</urlset>

■ 出力されるHTMLファイルの例

FirefoxのHTML Validatorを全て通過しているにもかかわらず、これだけのエラーが出る…

20110503-validator.jpg