4

我正在尝试使用WWW::Mechanize和从旧的 vBulletin 论坛中提取文本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 和一个包含必要帖子 ID 的数组:

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;
}

Using$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

任何帮助将不胜感激。

4

2 回答 2

3

查看 Mojo::DOM 的源代码,基本上该all_text方法递归遍历 DOM 并提取所有文本。使用该源代码编写您自己的遍历 DOM 函数。它的递归函数取决于返回单个字符串,在您的字符串中,您可能会让它返回一个包含您需要的任何上下文的数组。

编辑:

在对 IRC 进行了一些讨论之后,网络抓取示例已经更新,它可能会帮助您指导您。http://mojolicio.us/perldoc/Mojolicious/Guides/Cookbook#Web_scraping

于 2012-12-28T22:14:51.450 回答
2

有一个扁平化 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;
}
于 2012-12-29T17:26:08.477 回答