【问题标题】:How to Parse a webpage如何解析网页
【发布时间】:2021-07-01 21:59:17
【问题描述】:

我正在尝试从 EnviroCanada 天气页面中提取以下内容。

我正在尝试按照以下方式获取每个小时。

时间 |大腿 |特洛 |湿度

7:00 | 23 | 22.9 | 30

提取的 HTML 页面:

<tr>
         <td headers="header1" class="text-center vertical-center"> 7:00 </td>
        <td headers="header2" class="media vertical-center"><span class="pull-left"><img class="media-object" height="35" width="35" src="/weathericons/small/02.png" /></span><div class="visible-xs visible-sm">
            <br />
            <br />
          </div>
          <div class="media-body">
            <p>Partly Cloudy</p>
          </div>
        </td>
        <td headers="header3m" class=" metricData text-center vertical-center">23
                                            �(22.9)
                                        </td>
        <td headers="header3i" class=" imperialData hidden text-center vertical-center">73
                                            �(73.2)
                                        </td>
        <td headers="header4m" class="metricData text-center vertical-center">
          <abbr title="West-Northwest">WNW</abbr> 8</td>
        <td headers="header4i" class="imperialData hidden text-center vertical-center">
          <abbr title="West-Northwest">WNW</abbr> 5</td>
        <td headers="header6" class="metricData text-center vertical-center">30</td>
        <td headers="header6" class="imperialData hidden text-center vertical-center">87</td>
        <td headers="header7" class="text-center vertical-center">83</td>
        <td headers="header8" class="metricData text-center vertical-center">20</td>
        <td headers="header8" class="imperialData hidden text-center vertical-center">68</td>
        <td headers="header9m" class="metricData text-center vertical-center">100.7</td>
        <td headers="header9i" class="imperialData hidden text-center vertical-center">29.7</td>
        <td headers="header10" class="metricData text-center vertical-center">24</td>
        <td headers="header10" class="imperialData hidden text-center vertical-center">15</td>
      </tr>

到目前为止的代码:

use strict;
use warnings;
use LWP::Simple;
use HTML::TokeParser;


 my $url = "http://weather.gc.ca/past_conditions/index_e.html?station=yyz";
 my $page = get($url) ||
die "Could not load URL\n";


 my $parser = HTML::TokeParser->new(\$page) ||
die "Parse error\n";

 $parser->get_tag("td") foreach ();
 $parser->get_tag("");
 my $time = $parser->get_text();

  ??
 my $thigh = $parser->get_text();


 ???
 my $tlow = $parser->get_text();

 ???
 my $humid = $parser->get_text();

我完全迷路了

【问题讨论】:

标签: html perl


【解决方案1】:

使用LWP::Simple 获取页面后,您可以根据需要使用它来选择特定工具,而不是使用通用解析器。

在这种情况下,您手上有一张桌子,我建议您使用HTML::TableExtract。有了它,您可以通过多种方式干净地检索表格元素,然后处理它们。它可以处理多个表、使用标题、设置解析首选项等等。通常,您甚至不必查看实际的 HTML。该模块是HTML::Parser 的子类。根据我的经验,它是一个非常好的工具。


这里是一些基本代码,用于这个特定的页面和任务。

use warnings;
use strict;
use LWP::Simple;
use HTML::TableExtract;

my $url = "http://weather.gc.ca/past_conditions/index_e.html?station=yyz";
my $page = get($url) or die "Can't load $url: $!";

my $headers = [ 'Time', 'Temperature', 'Humidex' ];

my $tec = HTML::TableExtract->new(headers => $headers);
$tec->parse($page);

my $fmt = "%6s | %6s | %6s | %8s\n";    
printf($fmt, 'Time', 'T-high', 'T-low', 'Humidex');    

my ($time, $temp_hi, $temp_low, $hum);

foreach my $rrow ($tec->rows) {
    # Skip rows without expected data. Clean up leading/trailing spaces.
    next if $rrow->[0] !~ /^\s*\d?\d:\d\d/;
    my @row = map { s|^\s*||; s|\s*$||; $_ } @$rrow;
    # Process as needed
    ($time, $hum) = @row[0,2];
    ($temp_hi, $temp_low) = $row[1] =~ /(\d+) .* \( (\d+\.\d+) \)/xs;
    printf($fmt, $time, $temp_hi, $temp_low, $hum);
}

前几行输出

时间 | T-高 | T-低 |湿润剂 16:00 | 29 | 29.2 | 37 15:00 | 27 | 27.2 | 37 14:00 | 26 | 25.6 | 33 ...

评论。

newheaders 属性使其仅提取这些标题下的列。循环变量是一个 reference,指向具有行元素的数组。元素是单元格中的原始文本。

第一行跳过不具有预期格式的行 - 一个可能的数字 \d? 后跟另一个数字,然后是 : 然后是两个数字。这是时间,3:0003:00

为清楚起见,将数组引用$rrow 提取到数组@row 中。 在特定列中寻找的元素,@row[0,2] 在它们出现时使用。 $row[1] 中的一个由正则表达式解析,它捕获一个数字 (\d+),然后是两个由 . 分隔的数字,可能还有中间文本 (.*)。这些捕获由正则表达式返回,并分配给其他两个变量。

请参阅模块的文档,如果需要,请参阅有关参考 perlreftut 和正则表达式 perlretut 的教程。另一个有用的页面是 Data Structures Cookbook perldsc。其他介绍见Tutorials。它们通常具有指向更具体文档的链接。

【讨论】:

  • 问题是我如何提取 3:00、5:00 等时间并放在适当的列中?它们都属于相同的标题标签。
  • 我尝试了 HTML::TableExtract(简单测试),但它不喜欢“我的 foreach”:使用 LWP::Simple;使用 HTML::TableExtract;使用文本::表格;我的 $doc = 'weather.gc.ca/past_conditions/index_e.html?station=yyz';我的 $headers = ['时间','温度'];我的 $table_extract = HTML::TableExtract->new(headers => $headers);我的 $table_output = Text::Table->new(@$headers); $table_extract->parse_file($doc);我的 ($table) = $table_extract->tables; foreach 我的 $row ($table->rows) { clean_up_spaces($row); # 为简洁起见没有显示 $table_output->load($row); } 打印 $table_output;
  • @BrianB 我已经发布了一些基本但有效的代码。当我有时间时会清理它(即使看起来你不需要它!)。告诉我进展如何。
  • 感谢您的帮助
  • @BrianB 这变成了一个很长的评论——我的意思是:它是固定的。在next if ... 行中,我将/\d\d:\d\d/ 更改为/\d?\d:\d\d/。因此,添加了一个字符,?。这意味着它之前的模式是可选的,可能有一个或零个。如果添加一些解释会有所帮助,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-23
  • 2015-09-17
  • 1970-01-01
  • 1970-01-01
  • 2013-01-12
  • 1970-01-01
相关资源
最近更新 更多