为什么Web::Scraper无法提取script标签内的文本内容?
问题原因
- Web::Scraper底层依赖HTML::TreeBuilder解析HTML,HTML::TreeBuilder默认会将
<script>、<style>等标签的内联内容识别为CDATA节点,而非普通文本节点 - Web::Scraper内置的
TEXT抽取过滤器默认只会提取普通文本节点内容,会自动忽略CDATA节点,因此最终返回空值
正确处理方法
有两种常用方案,不需要提前修改标签名:
方案1:自定义回调直接提取CDATA内容
直接在process规则中传入回调,从script元素节点中直接读取CDATA内容,示例修改如下:
our $scraper = scraper { # 替换原来的TEXT过滤器为自定义回调 process 'script', "script" => sub { my $elem = shift; # 提取CDATA内容并去除首尾空白 my $content = $elem->content_array_ref->[0] // ''; $content =~ s/^\s+|\s+$//g; return $content; }; process 'p', "p" => 'TEXT'; process 'other', "other" => 'TEXT'; };
修改后运行即可正常拿到test script的输出。
方案2:修改HTML::TreeBuilder默认解析规则
在解析前修改底层解析器的配置,取消将script标签内容识别为CDATA的默认规则,后续直接用TEXT过滤器即可正常提取:
use Web::Scraper; use Data::Dumper; use HTML::TreeBuilder; # 修改默认解析配置,清空CDATA标签列表 my $builder = HTML::TreeBuilder->new; $builder->cdata_sections([]); my $html = q| <html> <head> <title>test html</title> </head> <body> <script> test script </script> <p> p test </p> <other> other test </other> </body> </html> |; our $scraper = scraper { process 'script', "script" => 'TEXT'; process 'p', "p" => 'TEXT'; process 'other', "other" => 'TEXT'; }; # 传入自定义的解析器实例执行抓取 my $data = $scraper->scrape( $html, undef, { tree_builder => $builder } ); say Dumper $data;
两种方案都可以稳定获取script标签内的内联内容,方案1不需要修改全局解析配置,更推荐在多场景抓取的代码中使用。
内容的提问来源于stack exchange,提问作者w.k
相关产品推荐
相关产品推荐

