Проблемы с определением дочерних элементов при использовании Mojo::DOM

Я пытаюсь извлечь текст из старого форума vBulletin, используя WWW::Mechanize а также Mojo::DOM,

vBulletin не использует HTML и CSS для семантической разметки, и у меня возникают проблемы с использованием Mojo::DOM->children чтобы получить на определенных элементах.

Эти посты vBulletin структурированы по-разному в зависимости от их содержания.

Одно сообщение:

<div id="postid_12345">The quick brown fox jumps over the lazy dog.<div>

Одно сообщение, цитирующее другого пользователя:

<div id="postid_12345">
    <div>
    <table>
        <tr>
            <td>
            <div>Quote originally posted by Bob</div>
            <div>Everyone knows the sky is blue.</div>
            </td>
        </tr>
    </table>
    </div>

 I disagree with you, Bob. It's obviously green.
</div>

Одно сообщение со спойлерами:

<div id="postid_12345">
    <div class="spoiler">Yoda is Luke's father!</div>
</div>

Одиночное сообщение, цитирующее другого пользователя, со спойлерами:

<div id="postid_12345">
    <div>
    <table>
        <tr>
            <td>
            <div>Quote originally posted by Fred</div>
            <div class="spoiler">Yoda is Luke's father!</div>
            </td>
        </tr>
    </table>
    </div>
    <div class="spoiler">No waaaaay!</div>
</div>

Предполагая вышеупомянутый HTML и массив, упакованный с необходимыми почтовыми идентификаторами:

for (@post_ids) {
    $mech->get($full_url_of_specific_forum_post);
    my $dom = Mojo::DOM->new($mech->content);
    my $div_id = 'postid_' . $_;

    say $dom->at($div_id)->children('div')->first;
    say $dom->at($div_id)->text;
}

С помощью $dom->at($div_id)->all_text дает мне все в непрерывной строке, что затрудняет определение того, что цитируется и что оригинально в посте.

С помощью $dom->at($div_id)->text пропускает все дочерние элементы, поэтому цитируемый текст и спойлеры не подобраны.

Я пробовал варианты $dom->at($div_id)->children('div')->first, но это дает мне все, включая HTML.

В идеале я хотел бы иметь возможность собирать весь текст в каждом посте, с каждым дочерним элементом в отдельной строке, например

 POSTID12345:
 + Quote originally posted by Bob
 + Everyone knows the sky is blue. 
 I disagree with you, Bob. It's obviously green. 

Я новичок в Mojo и ржавый с Perl. Я хотел решить это самостоятельно, но после просмотра документации и возни с ней несколько часов, мой мозг переполнен, и я в растерянности. Я просто не понимаю, как Mojo::DOM а также Mojo::Collections Работа.

Любая помощь будет оценена.

2 ответа

Глядя на источник Mojo::DOM, в основном all_text Метод рекурсивно обходит DOM и извлекает весь текст. Используйте этот источник, чтобы написать свою собственную функцию DOM. Его рекурсивная функция зависит от возврата одной строки, в вашей может быть, что она возвращает массив с любым контекстом, который вам нужен.

РЕДАКТИРОВАТЬ:

После некоторого обсуждения IRC пример веб-поиска обновился, и он может помочь вам в этом. http://mojolicio.us/perldoc/Mojolicious/Guides/Cookbook

Есть модуль для создания плоского HTML-дерева, HTML:: Linear. Объяснение назначения плоского HTML-дерева немного длинное и скучное, поэтому вот иллюстрация, показывающая результаты работы инструмента xpathify, связанного с этим модулем:

Скриншот

Как видите, узлы дерева HTML становятся единым списком ключ / значение, где ключ - это XPath для этого узла, а значение - текстовый атрибут узла. Вот несколько нажатий клавиш: вот как вы используете HTML:: Linear:

#!/usr/bin/env perl
use strict;
use utf8;
use warnings;

use Data::Printer;
use HTML::Linear;

my $hl = HTML::Linear->new;
$hl->parse_file(q(vboard.html));

for my $el ($hl->as_list) {
    my $hash = $el->as_hash;
    next unless keys %{$hash};
    p $hash;
}
Другие вопросы по тегам