Perl 使用HTML::TreeBuilder从HTML提取文本

Perl 使用HTML::TreeBuilder从HTML提取文本,perl,html-parsing,Perl,Html Parsing,您好,我正在使用/清理由Microsoft Word等程序生成的一些不良HTML 鉴于示例中的错误HTML片段,我需要提取mosh=“start”和mosh=“stop”之间的文本。注意,这是代码中其他地方设置的任意属性 还要注意,这只是一个示例:唯一的保证是mosh启动和停止的div。这些也可以是表格或 下面的代码实现了这一点,但每行都被提取多次,因为每个子行也有子行 $MoshText应该是 Good Text can be pattern matched Wanted Text More

您好,我正在使用/清理由Microsoft Word等程序生成的一些不良HTML

鉴于示例中的错误HTML片段,我需要提取
mosh=“start”
mosh=“stop”
之间的文本。注意,这是代码中其他地方设置的任意属性

还要注意,这只是一个示例:唯一的保证是mosh启动和停止的
div
。这些也可以是表格或

下面的代码实现了这一点,但每行都被提取多次,因为每个子行也有子行

$MoshText
应该是

Good Text can be pattern matched Wanted Text More Wanted TextYet More Wanted Text
但是饭后

$MoshText

Good Text can be pattern matched Good Text can be pattern matched Good Text can be pattern matched Good Text can be pattern matched
然后,我需要将
m/matched/
上的
$MoshText
拆分为两个字符串,并删除原始文本中的任何对象

我如何修改下面的代码来实现这一点

#!/usr/bin/perl
use HTML::TreeBuilder;
use HTML::Element;

my $body =qq(
<body>
  <div mosh="start">Div where mosh set to start</div
  <div>
<table>
  <tr>
    <td></td><td</td>
    <th>Good Text can be pattern matched</th>
    <td></td><td</td>
  </tr> 
</table
</div>
<p>

   <p>
      <b>Wanted Text</b>
   <br>
      <p><b>More Wanted Text</b></p>
   <div>
      <p><b>Yet More Wanted Text</b></p>
   </div>
  </p>
<div mosh="stop">Div where mosh set to stop bellow here is not needed</div>
);

my ($MoshText, $Flag);

my @kids = $body->content_list();
while (@kids) {
    my $child = shift @kids;
    if (ref $child) {
        my $Mosh = child->attr("mosh");
        if ($Mosh eq "start") {
            $Flag = 1;
        }
        if ($Mosh eq "stop") {
            $Flag = 0;
            last;
        }
        if ($Flag == 1) {
            my $T = $child->as_trimmed_text;
            $MoshText = $MoshText . " " . $T;
        }
        unshift @kids, $child->content_list;
    }
}
print $MoshText . "\n";
但是我现在如何找到delete和insert$new表呢

清洁输出

    <div>
      Div where mosh set to start
    </div> 
    <div class ='MyClass'>
      Good Text can be pattern matched
    </div>
    <div class ='AnotherClass' >
      Wanted Text More Wanted Text Yet More Wanted Text
    </div>
    <div mosh="stop">Div where mosh set to stop bellow here is not needed</div>

mosh设置为开始的Div
好的文本可以进行模式匹配
想要的文本更多想要的文本更多想要的文本
此处不需要mosh设置为停止波纹管的Div

希望这更有意义

我想您已经理解了代码不起作用的原因。您正在打印HTML中所有元素的文本值,并且由于元素的文本值包括其子元素的所有文本节点,因此多个文本片段会多次出现

您需要递归地处理HTML树,检查每个元素的
mosh
属性的值,并相应地保留一个标志(正如您已经做的那样),并且仅在设置了标志的情况下才会在遇到文本节点时打印它们

这个程序演示了。我已经在
matched
上显示了拆分字符串,但是我不清楚您所说的删除原始文本中的任何对象是什么意思

使用严格;
使用警告;
使用HTML::TreeBuilder;
使用HTML::元素;
my$tree=HTML::TreeBuilder->new->parse_文件(*数据);
我的美元被通缉;
我的@mosh_文本;
我的@nodes=($tree);
while(@节点){
my$node=shift@nodes;
if(非ref$node){
按@mosh_text,$node(如果需要);
}
否则{
my$mosh=lc($node->attr('mosh')/“”);
如果($mosh eq‘开始’或$mosh eq‘停止’){
$wanted=$mosh eq‘开始’;
}
取消移动@nodes,$node->content\u列表;
}
}
我的$mosh_text=“@mosh_text”;
打印“$\u\n”表示拆分/\s*匹配的\s*/,$mosh\u文本;
__资料__

Div where mosh set to start使用HTML::TreeBuilder解析HTML页面,然后使用HTML::元素的look\u down()/look\u up()/right()/left()方法查找mosh属性边界

给定边界,可以使用向上/向下查找方法(在边界元素上,而不是树根上)查找包含要更改的文本的元素。更改元素中的文本,然后可以使用as_HTML方法从树根或任何其他元素创建HTML

因此,在psuedocode中:

$tree = HTML::TreeBuilder->parse($something)
$mstart = $tree->look_down(
                            _tag => "div",
                            class  => "mosh_start"
                           )
###
# 1. now use HTML::Element traversal methods to find the element that contains the text to match

# 2. use the content manipulation methods to change the content

# 3. rewrite the file
$tree->as_HTML().
另请参见CPAN版本的一部分

use HTML::TreeBuilder;
my $t = HTML::TreeBuilder->new->parse_file("China.data");

sub list
 {my ($t, $d) = @_;
  $d //= 0;
  if (ref($t))
   {say "  "x$d, $t->tag;
    for($t->content_list)
    {list($_, $d+1);
    }
  }
 else {say "  "x$d, dump($t)}
}

名单(吨)

感谢您的快速回复,请查看我的编辑,了解我的意思“删除原始文本中的任何对象”我将对象视为任何HTML元素div、p、B等@Holly:但文本来自HTML中的各种不同元素。你能用你的示例代码展示一下当适当的元素被删除后HTML是什么样子的吗?很抱歉,我应该这样做。首先请看我的第二次编辑,显示了我正在尝试实现的清理输出。塔克斯!
use HTML::TreeBuilder;
my $t = HTML::TreeBuilder->new->parse_file("China.data");

sub list
 {my ($t, $d) = @_;
  $d //= 0;
  if (ref($t))
   {say "  "x$d, $t->tag;
    for($t->content_list)
    {list($_, $d+1);
    }
  }
 else {say "  "x$d, dump($t)}
}