我需要解析HTML表中的监控数据以进行日志记录。
HTML文档中有多个表没有任何标识符,因此识别正确的TR需要即兴创作。
感兴趣的特定行是:
<TR>
<TD>Signal to Noise Ratio</TD>
<TD>35 dB</TD>
<TD>35 dB</TD>
<!-- MORE TDs continue here... -->
</TR>
因此,可以使用的标识符/常数是&#34;信噪比&#34; TR中的字符串,用于识别文档中正确的TD。
第一行中包含此行中标识字符串的TD
个元素的数量是可变的。我需要将这些元素中的所有整数存储为变量,类似于:
my %data;
my @keys = qw(SNR1 SNR2 SNR3 SNR4);
my $content = LWP::Simple::get("http://192.168.100.1/cmSignalData.htm")
or die "Couldn't get it!";
if ( $content =~ /<TD>(.+?) dB<\/TD>/ ) {
$data{SNR1} = $1;
}
for (@keys) {
print "$_:" . $data{$_} . " ";
}
print "\n";
然后以完全相同的模式解析其他表中的其他TR
元素。
答案 0 :(得分:2)
不要使用Regex解析HTML。使用HTML解析器。
CPAN上有几个HTML解析器模块可用。我最喜欢的是Mojo :: DOM。你可以像下面这样使用它:
#!/usr/bin/perl
use strict;
use warnings;
use Mojo::DOM;
my $HTML = <<"EOF";
<table>
<TR>
<TD>Signal to Noise Ratio</TD>
<TD>35 dB</TD>
<TD>35 dB</TD>
</TR>
</table>
EOF
my $dom = Mojo::DOM->new( $HTML );
if ($dom->at('tr td')->text() eq 'Signal to Noise Ratio'){
for my $e ($dom->find('td')->each) {
if($e->text() =~ /(\d+)\sdB/){
print $1."\n";
}
}
}
关于Mojo::DOM
和Mojo::UserAgent
的8分钟视频教程,请查看Mojocast Episode 5
答案 1 :(得分:2)
您可以使用XPath查询轻松获取所需的值,因为您在特定td
节点之后查找同一级别的所有以下td
个节点。
以下是使用HTML::TreeBuilder::XPath
模块的示例:
use HTML::TreeBuilder::XPath;
my $tree = HTML::TreeBuilder::XPath->new;
$tree->parse_file("yourfile.html");
my @snr = $tree->findvalues('//td[.="Signal to Noise Ratio"]/following-sibling::td');
$tree->delete;
@snr = map /^(\d+)/, @snr;
print join(', ', @snr);
XPath是一种用于查询HTML / XML文档的树表示的语言DOM (Document Object Model) tree。
查询详情:
// # anywhere in the tree (*)
td # a `td` element with the following "predicate" (embedded in square brackets):
[.="Signal to Noise Ratio"] # predicate: the text content of the current node (figured
# by a dot) is exactly "Signal to Noise Ratio"
/following-sibling::td # 'following-sibling::' is a kind of selector called "axis"
# that selects all nodes with the same parent node after the
# current element.
# 'td' selects only `td` elements in this node-set.
(*)如果你想要你可以更明确。您可以从根元素//td
/html/body/center/table/tbody/tr/td
。
这种方法需要构建文档树以便能够查询它。它不是一种快速方法,但主要优点是您使用HTML结构而不是通配文本方法。
请注意,您可以避免数组map
提取每个项目开头的数字。 XPath有几个字符串函数,包括substring-before
:
//td[.="Signal to Noise Ratio"]/following-sibling::td/substring-before(text(), " dB")
如果性能很重要,您可以使用像HTML::TokeParser::Simple
之类的拉解析器尝试另一种方法。这不太方便编写,但它更快,因为没有构建DOM树,并且您将节省内存,因为您可以将HTML文件作为流读取并在需要时停止阅读将整个文件加载到内存中。
答案 2 :(得分:2)
这是使用 Mojolicious 的版本。它直接从您的pastebin存储库中提取HTML
for
循环遍历所有表中的所有行。在其中,@columns
数组设置为行中所有列(<td>
元素)的文本内容
检查第一个元素,首先它是否存在,其次是Signal to Noise Ratio
。如果是,那么全局数组@snr
将设置为@columns
剩余部分中的十进制数,last
将停止搜索所需行
use strict;
use warnings;
use 5.010;
use Mojo;
my $ua = Mojo::UserAgent->new;
my $dom = $ua->get('http://pastebin.com/raw.php?i=73H5peKW')->res->dom;
my @snr;
for my $row ( $dom->find('table tr')->each ) {
my @columns = $row->find('td')->map('text')->each;
next unless @columns;
if ( shift @columns eq 'Signal to Noise Ratio' ) {
@snr = map /(\d+)/, @columns;
last;
}
}
say "@snr";
35 35 34 34 34 34 34 34