【问题标题】:Perl web scraper, retrieve data from text inside a script tagPerl web scraper,从脚本标签内的文本中检索数据
【发布时间】:2019-07-17 08:45:56
【问题描述】:

到目前为止,我一直在使用 perl 从使用 HTML::TreeBuilder 的网页中获取数据。当数据包含在metadiv 标签中时,这是可以的;但现在我偶然发现了一个我不会爬的新结构,虽然它看起来很简单。

<html lang="en">
    <body>
        <script type="text/javascript">
            panel.web.bootstrapData = {
                "data": {
                    "units": "kW",
                    "horsePower": 100.00
                }
            };
        </script>
    </body>
</html>

该示例显示了我从网络获取的内容的相关部分。我想获取unitshorsePower 的值。

目前我使用的代码片段:

use strict;
use LWP::UserAgent;
use HTTP::Request::Common;
use HTML::TreeBuilder;

[...]

$reply = $ua->get($url, @ns_headers);

# printing the reply would get us the first code snippet.
print $reply->content;

unless ($reply->is_success) {
    [...]
}

my $tree = HTML::TreeBuilder->new_from_content($reply->content);
my @unit_array = $tree -> look_down(_tag=>'meta','itemprop'=>'unit');
my $unit = $unit_array[0]->attr('content');

[...]

任何人都知道如何获取相关数据以及我是否应该使用HTML::TreeBuilder以外的东西?我通过stackoverflow和网络搜索没有发现任何类似的案例。

【问题讨论】:

  • 这是一个非常不同的问题。您打算做的是解析/抓取 JavaScript 代码,而不是 HTML。 script 标签的内容是一个 JS 程序,恐怕你必须用完全不同的方法来解析。
  • @JesusAlonsoAbad 我同意一般情况下确实如此。但 OP 示例清楚地表明,他的源数据在 &lt;script&gt; 标签中嵌入了 JSON 字符串。
  • 感谢您的 cmets。在我的情况下,Stefan 的解决方案非常有效。

标签: html perl web-scraping web-crawler


【解决方案1】:

您基本上是在正确的道路上。但是HTML::TreeBuilder 对 JavaScript 一无所知。

方法:

  • 找到&lt;script&gt; 节点
  • 从这些节点中提取 JSON 内容
    • 注意:对于给出的示例来说这很容易,但对于更复杂的&lt;script&gt; 内容需要更多技巧
    • 在正则表达式中的转义 \; 并不是真正需要的,但如果没有它,SO 语法高亮显示会变得混乱
  • 使用JSON 将字符串解码为 Perl 数据结构
  • 在您的脚本中访问这些数据结构

没有错误检查的第一个粗略解决方案。我在代码中留下了一些调试行,注释掉了,这样你就可以跟踪每个步骤在做什么:

#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;
use HTML::TreeBuilder;
use JSON;

my $decoder = new JSON;

my $tree       = HTML::TreeBuilder->new_from_file(\*DATA);
#$tree->dump;
my @scripts    = $tree->look_down(_tag => 'script');
#$scripts[0]->dump;
# NOTE 1: ->as_text() *DOES NOT* return <script> content!
# NOTE 2: ->as_HTML() probably doesn't work for all cases, i.e. escaping
my $javascript = ($scripts[0]->content_list())[0];
#print "${javascript}\n";
my($json)      = $javascript =~ /(\{.+\})\;/s;
#print "${json}\n";
my $object     = $decoder->decode($json);

print Dumper($object);
print "FOUND: units: ", $object->{data}->{units},
      " horsepower: ",  $object->{data}->{horsePower}, "\n";

# IMPORTANT: $tree needs to be destroyed by hand when you're done with it!
$tree->delete;

exit 0;

__DATA__
<html lang="en">
    <body>
        <script type="text/javascript">
            panel.web.bootstrapData = {
                "data": {
                    "units": "kW",
                    "horsePower": 100.00
                }
            };
        </script>
    </body>
</html>

试运行:

$ perl dummy.pl
$VAR1 = {
          'data' => {
                      'horsePower' => '100',
                      'units' => 'kW'
                    }
        };
FOUND: units: kW horsepower: 100

【讨论】:

  • 刚刚尝试过您的解决方案,效果很好。只需要调整正则表达式,因为实际的网络在&lt;script&gt; 标签下还有更多的 JSON。谢谢。
  • 我认为-&gt;as_HTML() 可能不是最佳选择,尽管它适用于您的示例。我已经更新了我的答案,改为使用-&gt;content_list()
猜你喜欢
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
相关资源
最近更新 更多