Проверяем все страницы сайта в валидаторе html
Интро
Цель — создать велосипед скрипт, который пробежится по сайту и проверит каждую страницу сайта на валидность html.
Я слышал, что если нападает перфекционизм, то надо полежать, отдохнуть и это пройдет.
Подумаешь, в валидаторе ошибка…
Но если все же не проходит, то
Ставим докер и контейнер с валидатором
Раньше поставить локальный валидатор было делом муторным.
Не то, что бы сложным, а требующим времени.
С приходом докера он устанавливается за секунды.
Ставим докер:
yum install docker
После установки докера берем себе готовый образ с собранным валидатором:
docker pull magnetikonline/html5validator
Когда образ закачается, то запускаем его:
docker run -p 8080:80 -p 8888:8888 --name validator --restart=always -d magnetikonline/html5validator
И стартуем:
docker start validator
После запуска можно зайти на http://localhost:8888 и увидеть:
Локальный валидатор работает! Его можно натравить на какой-нибудь сайт.
И проверяем с командной строки:
curl 'localhost:8888?doc=http://www.w3schools.com'
И вот такой результат:
Как видно, валидатор нашел 3 ошибки.
Паучок
Теперь надо написать скрипт, который бы обошел все страницы сайта.
За основу я взял вот такой web crawler/scraper на основе Mojo.
И немного изменил:
#!/usr/bin/env perl
use 5.010;
use open qw(:locale);
use strict;
use utf8;
use warnings qw(all);
use Mojo::UserAgent;
use List::MoreUtils 'true';
use Term::ANSIColor;
# Адрес сайта для проверки
my $site_to_check = 'http://habrahabr.ru';
# Адрес локального валидатора
my $local_validator = 'http://192.168.1.217:8888';
# FIFO queue
my @urls = ( Mojo::URL->new($site_to_check) );
# User agent following up to 5 redirects
my $ua = Mojo::UserAgent->new( max_redirects => 5 );
# Track accessed URLs
my $active = 0;
my %uniq;
sub parse {
my ($tx) = @_;
# Request URL
my $url = $tx->req->url;
# Extract and enqueue URLs
for my $e ( $tx->res->dom('a[href]')->each ) {
# Validate href attribute
my $link = Mojo::URL->new( $e->{href} );
next if 'Mojo::URL' ne ref $link;
# "normalize" link
$link = $link->to_abs( $tx->req->url )->fragment(undef);
next unless $link->protocol =~ /^https?$/x;
# Don't go deeper than /a/b/c
next if @{ $link->path->parts } > 3;
# Access every link only once
next if ++$uniq{ $link->to_string } > 1;
# Don't visit other hosts
next if $link->host ne $url->host;
push @urls, $link;
my $get = $ua->get( $local_validator . "?doc=$link" )->res->body;
my @answ = split / /, $get;
my $count = true { /class="error"/ } @answ;
print color("green"), $link, color("reset");
print " Кол-во ошибок в валидаторе: ",
color("red"), "$count \n", color("reset");
}
return;
}
sub get_callback {
my ( undef, $tx ) = @_;
# Parse only OK HTML responses
$tx->res->code == 200
and $tx->res->headers->content_type =~ m{^text/html\b}ix
and parse($tx);
# Deactivate
--$active;
return;
}
Mojo::IOLoop->recurring(
0 => sub {
# Keep up to 4 parallel crawlers sharing the same user agent
for ( $active .. 4 - 1 ) {
# Dequeue or halt if there are no active crawlers anymore
return ( $active or Mojo::IOLoop->stop )
unless my $url = shift @urls;
# Fetch non-blocking just by adding
# a callback and marking as active
++$active;
$ua->get( $url => \&get_callback );
}
}
);
# Start event loop if necessary
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
Ссылка на гитхаб
Результат работы: