2013-08-17 68 views
3

我想弄清楚在Perl中使用HTML :: TreeBuilder從XML文件中的某些HTML中提取幾段文本的最佳方法。在perl中用HTML定位div :: TreeBuilder

我讓它使用$tree->address(或者我認爲)工作,直到我意識到並非所有條目都是以相同的順序。

沒有經過列表中的每一項,看起來每個條目都有幾個<div>元素,但其中只有一個<div>的元素有<p>個元素。並且<div>都沒有課程,這將使這很容易。

我已經嘗試了幾種不同的方式,所以沒有任何東西似乎能工作,我可以在其中提取我想要的文本。我看了幾個不同的例子,但他們中沒有一個真的非常接近我所尋找的。

這將是很好,如果是這樣的工作:

$bodyText = $tree->look_down('_tag' => 'div' => 'p'); 

但是,這給我的錯誤:

param list to look_down ends in a key! 

不管怎麼說,也許有人可以幫我指出正確的方向,我有一直在尋找整夜,現在我的大腦受傷了。

謝謝!

約翰

+0

你可以添加一個HTML代碼片段嗎? – simbabque

回答

2

你的錯誤信息是有道理的。 look_down方法需要一個散列(當然是一個列表)。你給它三個元素,所以最後一個是關鍵。請記住=>也被稱爲胖逗號並且只是一個更可讀的方式來編寫,。不過,這有點奇怪的錯誤信息。

你需要做的是首先解析<div>,然後解析那些<p> s。你不能一次使用HTML :: TreeBuilder。您將從第一個foreach獲得每個<div>的HTML :: Element對象。讓他們look_down<p> s。

use strict; 
use warnings; 
use feature qw(say); 
use HTML::TreeBuilder 5 -weak; 

my $tree = HTML::TreeBuilder->new_from_content(<DATA>); 
foreach my $e ($tree->look_down(_tag => 'div')) { 
    foreach my $f ($e->look_down(_tag => 'p')) { 
    say $f->as_text; 
    } 
} 

__DATA__ 
<html> 
<body> 
<div>foo</div> 
<div><p>hello world</p></div> 
<div>foo2</div> 
<div>foo3</div> 
<div><p>hello again</p></div> 
</body> 
</html> 
0
use Web::Query 'wq'; 
print wq("<html><div><p>I'm trapped under a hat</p></div><div /><div /><div /><div /><div />") 
     ->find('div p')->text; 
+0

非常整齊。不過,解釋會很好。 ;-) – simbabque

2

我建議使用的XPath此:

use strict; 
use warnings; 
use feature qw(say); 
use HTML::TreeBuilder::XPath; 

my $tree = HTML::TreeBuilder->new_from_content(<DATA>); 
foreach my $e ($tree->findnodes('//div/p')) { 

    say $e->as_text; 
} 

__DATA__ 
<html> 
<body> 
<div>foo</div> 
<div><p>hello world</p></div> 
<div>foo2</div> 
<div>foo3</div> 
<div><p>hello again</p></div> 
</body> 
</html> 
3

隨着HTML::TreeBuilder香草形式,這是使用一個代碼作爲參考的look_down準則做得最好。將調用樹中每個節點的子例程,該節點通過所有先前的標準,並且如果子例程返回真值,則會保留節點。

這個程序顯示了它的用法。匿名子例程使用grep來檢查傳遞給它的節點的子節點,並計算具有p標記的所有元素。數組@divs然後包含具有p子元素的所有div元素。您可能需要確保@divs只包含一個元素。

use strict; 
use warnings; 

use feature 'say'; 

use HTML::TreeBuilder; 

my $doc = HTML::TreeBuilder->new_from_content(<<__HTML__); 
<div>content</div> 
<div>content</div> 
<div><p>paragraph</p></div> 
<div>content</div> 
<div>content</div> 
__HTML__ 

my @divs = $doc->look_down(
    _tag => 'div', 
    sub { grep { ref eq 'HTML::Element' and $_->tag eq 'p' } $_[0]->content_list } 
); 

say scalar @divs, " found:\n"; 
say $divs[0]->as_HTML('<>&', ' '); 

輸出

1 found: 

<div> 
    <p>paragraph</div> 

然而,這是非常更整潔採用增強HTML::TreeBuilder::XPath,它允許到數據使用XPath表達式來解決。這允許look_down成與findnodes呼叫被替換:

my @divs = $doc->findnodes('//div[p]'); 

,結果是相同的,上面的代碼。

+0

嘗試您的第一個示例,我收到以下錯誤:'不能調用方法「isa」沒有包或對象引用在...'但不知道爲什麼? –

+0

@JohnB:我很抱歉。我忘了你不能在空字符串上調用'isa'。我修復了它。 – Borodin