Проблемы с определением дочерних элементов при использовании 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;
}