1

テーブルを含むいくつかの html ページを処理したい。

ページ:

  • 複数のクラスレス テーブルが含まれており、正しいテーブルを識別する唯一の方法
  • 必要なテーブルには、最初のセル値「Content」があります

質問: Web::Scrape または Scrappy またはその他のツールを使用して、セルの値に基づいて正しいテーブルを見つける方法は?

コード例:

#!/usr/bin/env perl
use 5.014;
use warnings;
use Web::Scraper;
use YAML;

my $html = do { local $/; <DATA> };

my $table = scraper {

    #the easy way - table with class, or id or any attribute
    #process 'table.xxx > tr', 'rows[]' => scraper {
    #unfortunately, the table hasn't class='xxx', so :(

    process 'NEED_HELP_HERE > tr', 'rows[]' => scraper {
        process 'th', 'header' => 'TEXT';
        process 'td', 'cols[]' => 'TEXT';
    };
};
my $result = $table->scrape( $html );
say Dump($result);

__DATA__
<head><title>title</title></head>
<body>
<table><tr><th class="inverted">header</th><td>value</td></tr></table>
<!-- here are several another tables (different count) -->

<table> <!-- would be easy with some class="xxx" -->
   <tr>
     <th class="inverted">Content</th> <!-- Need this table - 1st cell == "Content" -->
     <td class="inverted">col-1</td>
     <td class="inverted">col-n</td>
   </tr>
   <tr>
     <th>Date</th>
     <td>2012</td>
     <td>2001</td>
   </tr>
   <tr>
     <th>Banana</th>
     <td>val-1</td>
     <td>val-n</td>
   </tr>
</table>
</body>
</html>
4

3 に答える 3

4

ノードのテキスト コンテンツを確認するには、XPath 式を使用する必要があります。

これでうまくいくはずです

my $table = scraper {
  process '//table[tr[1]/th[1][normalize-space(text())="Content"]]/tr', 'rows[]' => scraper {
    process 'th', 'header' => 'TEXT';
    process 'td', 'cols[]' => 'TEXT';
  };
};

複雑に見えるかもしれませんが、分解すればOKです。

最初の要素の最初の要素に、正規化されたときと等しいテキスト要素が含まれるルートの下にある要素の<tr>子であるすべての要素が選択されます(先頭と末尾のスペースが削除されます)。<table><th><tr>"Content"

出力

---
rows:
  - cols:
      - col-1
      - col-n
    header: Content
  - cols:
      - 2012
      - 2001
    header: Date
  - cols:
      - val-1
      - val-n
    header: Banana
于 2012-05-22T14:51:23.580 に答える
3

HTML::TableExtractはこの問題に適しているようです。

これを試してみてください。

#!/usr/bin/Perl 

use strict;
use warnings;
use lib qw( ..); 
use HTML::TableExtract; 
use LWP::Simple; 

my $te = HTML::TableExtract->new( headers => [qw(Content)] );
my $content = get("http://www.example.com");
 $te->parse($content);

foreach my $ts ($te->tables) {
   print "Table (", join(',', $ts->coords), "):\n";
   foreach my $row ($ts->rows) {
      print join(',', @$row), "\n";
   }
 }

この行を変更した場合

 my $te = HTML::TableExtract->new( headers => [qw(Content)] );

 my $te = HTML::TableExtract->new();

すべてのテーブルが返されます。したがって、上記のコードブロックで探しているものが正確に得られない場合は、その行をいじることができます。

于 2012-05-22T14:30:56.423 に答える
1

いつものように、Web::Queryはコンパクトさで勝っています。Scraper とは異なり、結果に名前を付ける必要はありませんが、必要に応じて 1 行追加するだけです。

use Web::Query qw();
Web::Query->new_from_html($html)
->find('th:contains("Content")')
->parent->parent->find('tr')->map(sub {
    my (undef, $tr) = @_;
    +{ $tr->find('th')->text => [$tr->find('td')->text] }
})

式が戻る

[
    {Content => ['col-1', 'col-n']},
    {Date    => [2012,    2001]},
    {Banana  => ['val-1', 'val-n']}
]
于 2012-05-22T15:18:35.390 に答える