2016-12-30 9 views
3

XPathセレクタを使用してページ上の各アイテム(約24)を選択し、各アイテムのXPathセレクタを使用して各アイテムから値を返します。すべてのノードではなく、単一のノードを検索する方法

サブノードでXPathセレクタを実行していても、各サブノードに対して個別に実行したいすべてのサブノードを検索しているようです。

docの各アイテムを検索してから、それぞれhtml_listingを繰り返します。その後get_field_data_fromに渡し:セレクタが存在する場合

def get_listing(doc,field_data = {}) 
    doc.xpath(get_listing_tag[:path]).each do |html_listing| 
    fd = get_field_data_from(html_listing,field_data) 
    if !field_data && fd.detect {|_,data| !data } 
     set_uri doc.xpath(get_sub_page_tag[:path]) 
     get 
     fd = get_listing(Nokogiri::HTML(body),fd) 
    end 
    yield fd 
    end 
end 

をだから、反復する私がいる探しているすべてのFieldsの上には

selector = send("get_%s_tag" % field) 

を使用して文字列を含むXPathのセレクターを取得するために使用され、データはすでにそれは、HTML item上のXPathセレクタを使用して使用してテキストを保存することが見出されていない

res[field] = item.xpath(selector[:path]).inner_text 

次に生成されたハッシュを次の反復で使用するために戻します。

def get_field_data_from(item,data) 
    Fields.inject(data) do |res,field| 
    selector = send("get_%s_tag" % field) 
    unless !selector || res[field] 
     begin 
     res[field] = item.xpath(selector[:path]).inner_text 
     rescue Exception => e 
     puts "Error for field: %s" % field 
     raise e 
     end 
    end 
    res 
    end 
end 

どういうわけか、それは

res[field] = item.xpath(selector[:path]).inner_text 

をやっているようだ、それだけでは与えられたアイテムリストではなく、すべてのアイテムを検索するようです。やって

  1. puts item.xpath(selector[:path]).inner_text 
    

    戻り、複数の結果

  2. を私は実際にすべてのhtml_listingsをループではないよ、私は原因であることやっている知っています。フィールドデータyield fdget_listingにある場合は、breakを実行するので、1回だけ行います。

私は何が起こっているのか分からないようです。他の誰かがそれを見ますか?

答えて

1

あなたは要素のXPathクエリを固定する必要があります。

  • node.xpath("//example")は、グローバル検索
  • node.xpath(".//example")は、現在のノード

お知らせ先頭のドット.から始まるローカル検索を行いん現在のノードでクエリをアンカーします。それ以外の場合は、現在のノードから呼び出した場合でも、ルートノードに対してクエリーが実行されます。

タグ名で検索する場合は、代わりにCSSセレクタを使用することを検討してください。 XPathよりも落とし穴が少ないCSSは常に現在のノードから検索します。

+0

サブノードで行った場合でもですか? – Thermatix

+0

はい、xpathはそのように混乱しています。 – akuhn

+0

wtf?すべてのサブノードの兄弟に対してそれを実行しようとしている場合、サブノード上のxpathを実行するポイントは何ですか?それは意味がありません。何らかの形で、ありがとうございました。 – Thermatix

1

同じように深刻な問題があります。

item.xpath(selector[:path]).inner_text 

xpathはノードセットを返します。 inner_textは、NodeSet内のすべてのノードの結果を連結します。その結果、通常は望むものではない文字列が生成されます。

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<html> 
    <body> 
    <p>foo</p> 
    <p>bar</p> 
    </body> 
</html> 
EOT 

doc.search('p').class # => Nokogiri::XML::NodeSet 
doc.search('p').inner_text # => "foobar" 

代わりに、テキストを取得、その後、ノードのリストを歩いてmapを使用する必要があります。

doc.search('p').map(&:inner_text) # => ["foo", "bar"] 

または、簡略化のために:

doc.search('p').map(&:text) # => ["foo", "bar"] 

を参照してください "How to avoid joining all text from Nodes when scraping" も。

関連する問題