HTML解析技巧
Perl有一些解析HTML的出色模块,其中之一就是XML::LibXML。它是libxml2 C库的接口;速度极快但也很挑剔。我经常发现XML::LibXML在解析相对简单的、但格式错误的HTML时崩溃。如果你遇到这种情况,不要放弃!本文分享了3种简单技巧,用于在XML::LibXML解析时克服格式错误的HTML。
技巧1:开启恢复模式
如果XML::LibXML在HTML的后期部分崩溃,尝试开启恢复模式,这将返回XML::LibXML遇到错误之前所有正确解析的HTML。
use XML::LibXML;
my $xml = XML::LibXML->new( recover => 1 );
my $dom = $xml->load_html( string => $html );
将恢复模式设置为1时,解析器仍会警告解析错误。要抑制警告,将恢复设置为2。
技巧2:使用HTML::Scrubber首先净化输入
有时仅恢复模式不足以解决问题 - 例如,如果存在两个doctype声明,XML::LibXML将会崩溃。在这些情况下,考虑使用HTML::Scrubber来净化HTML。
HTML::Scrubber提供白名单和黑名单功能,用于包含或排除HTML标签和属性。这是一个强大的组合,允许你创建自定义过滤器来清理你想要解析的HTML。
默认情况下,HTML::Scrubber会移除所有标签,但在重复的doctype声明的情况下,你只需要移除那个标签。为了保险起见,我们也将移除所有的div标签。
use HTML::Scrubber;
my $scrubber = HTML::Scrubber->new( deny => [ 'doctype', 'div' ],
allow=> '*' );
my $scrubbed_html = $scrubber->scrub($html);
my $dom = XML::LibXML->load_html( string => $scrubbed_html );
“deny”规则设置scrubber的黑名单(要排除的内容),“allow”规则指定白名单(要包含的内容)。在这里,我们传递了一个星号(”*”),允许所有内容,但由于我们拒绝div和doctype标签,它们将被移除。
技巧3:使用正则表达式捕获提取数据子集
如果你想要解析的HTML子集具有唯一的标识符(例如id属性),考虑使用正则表达式捕获从HTML文档中提取它。然后你可以使用XML::LibXML清理或立即解析这个子集。
例如,最近我需要从一个格式错误的网页中提取一个HTML表格。幸运的是,表格有一个id属性,这使得使用正则表达式提取它变得轻而易举。
if ( $html =~ /(<table id="t2">.*?<\/table>)/s ) {
my $dom = XML::LibXML->load_html( string => $1 );
...
}
注意正则表达式中使用“s”修饰符以匹配多行。许多HTML页面包含换行符,你不希望你的匹配因为这个问题而失败。
结论
希望这些技巧能让你用XML::LibXML解析HTML更容易。我的GitHub账户有一个网络爬虫脚本,它使用了一些这些技巧。如果你正在寻找解析HTML的另一种完全不同的方法,请查看XML::Rabbit和HTML::TreeBuilder。
喜欢这篇文章?帮助我们,推文一下它!
这篇文章最初发表在PerlTricks.com。
标签
反馈
这篇文章有什么问题吗?请通过GitHub提出问题或发起拉取请求来帮助我们。