Извлечение текста из HTML — Perl с помощью HTML::TreeBuilder

Я пытаюсь получить доступ к файлам .html и извлечь текст в тегах <p>. По логике, мой код ниже должен работать. С помощью HTML::TreeBuilder. Я анализирую html, затем извлекаю текст в <p>, используя find_by_attribute("p"). Но мой скрипт вышел с пустыми каталогами. Я ничего не упустил?

#!/usr/bin/perl

use strict;
use HTML::TreeBuilder 3;
use FileHandle;

my @task = ('ar','cn','en','id','vn');

foreach my $lang (@task) {
mkdir "./extract_$lang", 0777 unless -d "./extract_$lang";
opendir (my $dir, "./$lang/") or die "$!";
my @files = grep (/\.html/,readdir ($dir));
closedir ($dir);

foreach my $file (@files) {
    open (my $fh, '<', "./$lang/$file") or die "$!";
    my $root = HTML::TreeBuilder->new;
    $root->parse_file("./$lang/$file");
    my @all_p = $root->find_by_attribute("p");
    foreach my $p (@all_p) {
        my $ptag = HTML::TreeBuilder->new_from_content ($p->as_HTML);
        my $filewrite = substr($file, 0, -5); 
        open (my $outwrite, '>>', "extract_$lang/$filewrite.txt") or die $!;
        print $outwrite $ptag->as_text . "\n";  
        my $pcontents = $ptag->as_text;
        print $pcontents . "\n";
        close (outwrite);
    }
close (FH);
}
}

Мои файлы .html представляют собой простые текстовые html с веб-сайтов .asp, например. http://www.singaporemedicine.com/vn/hcp/med_evac_mtas.asp

Мои файлы .html сохраняются в:

./ar/*
./cn/*
./en/*
./id/*
./vn/*

person alvas    schedule 19.12.2011    source источник


Ответы (4)


Вы путаете элемент с атрибутом. Программу можно написать намного короче:

#!/usr/bin/env perl
use strictures;
use File::Glob qw(bsd_glob);
use Path::Class qw(file);
use URI::file qw();
use Web::Query qw(wq);
use autodie qw(:all);

foreach my $lang (qw(ar cn en id vn)) {
    mkdir "./extract_$lang", 0777 unless -d "./extract_$lang";
    foreach my $file (bsd_glob "./$lang/*.html") {
        my $basename = file($file)->basename;
        $basename =~ s/[.]html$/.txt/;
        open my $out, '>>:encoding(UTF-8)', "./extract_$lang/$basename";
        $out->say($_) for wq(URI::file->new_abs($file))->find('p')->text;
        close $out;
    }
}
person daxim    schedule 19.12.2011
comment
Я получаю предупреждающее сообщение Wide character in print at extract.pl line 24. Есть ли ограничения для TreeBuilder? Он по-прежнему печатается, даже если perl выдает предупреждение, верно? - person alvas; 19.12.2011
comment
Вы должны указать кодировку вывода текста. Сравните, как я открываю выходной файл с тем, как это делаете вы. Узнайте о теме кодирования в Perl на p3rl.org/UNI. - person daxim; 19.12.2011
comment
Я попытался с вашим кодом, но получил ошибку компиляции в use strictures, я также получаю ошибки в других атрибутах use. Нужно ли устанавливать новый Perl, чтобы они работали? - person alvas; 19.12.2011
comment
Ошибка: Can't locate strictures.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.12.4 /usr/local/share/perl/5.12.4 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.12 /usr/share/perl/5.12 /usr/local/lib/site_perl .) at extract-daxim.pl line 3. - person alvas; 19.12.2011
comment
Замените use strictures; на use strict; use warnings; Или установите дистрибутив strictures с CPAN. - person friedo; 19.12.2011
comment
а теперь я понял! установить CPAN на мою машину. - person alvas; 19.12.2011
comment
@daxim, я все еще получаю сообщение об ошибке, где написано Bareword found where operator expected at extract-daxim.pl line 14, near "s/[.]html$/.txt/r" это тильда ~? - person alvas; 20.12.2011
comment
я не понимаю эту часть кода `. file($file)-›basename =~ s/[.]html$/.txt/r;` файл и базовое имя не имеют my или $, они из Path::Class и File::Glob ?? - person alvas; 20.12.2011
comment
2er0, модификатор r доступен только в Perl 5.13.2 или выше. Либо установите дополнительную стабильную версию Perl 5.14.x (perlbrew упрощает эту задачу), либо используйте исправленную версию кода выше. работает вокруг отсутствия r. — file — экспортируемая функция, basename — метод. Оба задокументированы в Path::Class::File. Пожалуйста, прочтите учебное пособие по Perl для среднего уровня, чтобы понять основные концепции. - person daxim; 20.12.2011

Используйте find_by_tag_name для поиска имен тегов, а не find_by_attribute.

person choroba    schedule 19.12.2011

Вы хотите find_by_tag_name, а не find_by_attribute:

my @all_p = $root->find_by_tag_name("p");

Из документов:

$h->find_by_tag_name('тег', ...)

В контексте списка возвращает список элементов в $h или ниже, которые имеют любое из указанных имен тегов. В скалярном контексте возвращает первый (при предварительном обходе дерева) такой найденный элемент или undef, если его нет.

person Eugene Yarmash    schedule 19.12.2011
comment
означает ли это, что если тег ‹p› встроен, мне может потребоваться снова запустить цикл? например <p>...<p>...<\p>...<\p> - person alvas; 19.12.2011
comment
@ 2er0 этот метод вернет все элементы p сразу. Вы можете использовать его в результирующих элементах, чтобы найти вложенные p. - person Eugene Yarmash; 19.12.2011

Вы можете взглянуть на Mojo::DOM, который позволяет вам использовать селекторы CSS.

person Alexander Hartmaier    schedule 19.12.2011