2017-02-13 36 views
1

実際、状況は少し複雑です。 XPathで見つかった結果の数が正しくありません

は、私は、この例のHTMLからデータを取得しようとしている。今のところ

<li itemprop="itemListElement"> 
    <h4> 
     <a href="/one" title="page one">one</a> 
    </h4> 
</li> 

<li itemprop="itemListElement"> 
    <h4> 
     <a href="/two" title="page two">two</a> 
    </h4> 
</li> 

<li itemprop="itemListElement"> 
    <h4> 
     <a href="/three" title="page three">three</a> 
    </h4> 
</li> 

<li itemprop="itemListElement"> 
    <h4> 
     <a href="/four" title="page four">four</a> 
    </h4> 
</li> 

、私はurlliblxmlでのPython 3を使用しています。予想通り はいくつかの理由について、次のコードは、

scan = [] 

example_url = "path/to/html" 
page = html.fromstring(urllib.request.urlopen(example_url).read()) 

# Extracting the li elements from the html 
for item in page.xpath("//li[@itemprop='itemListElement']"): 
    scan.append(item) 

# At this point, the list 'scan' length is 4 (Nothing wrong) 

for list_item in scan: 
    # This is supposed to print '1' since there's only one match 
    # Yet, this actually prints '4' (This is wrong) 
    print(len(list_item.xpath("//h4/a"))) 

あなたが見ることができるように、最初の動きは、4つのli要素を抽出し、リストに追加することを(コメントをお読みください)動作しません。各li要素をa要素に対してスキャンしますが、scanの各li要素が実際にはすべて4つの要素であるという問題があります。

...そうだと思いました。

速いデバッグを行うと、scanのリストに4つのli要素が正しく含まれていることがわかりました。結論として、上記のforループに問題があります。

for list_item in scan: 
    # This is supposed to print '1' since there's only one match 
    # Yet, this actually prints '4' (This is wrong) 
    print(len(list_item.xpath("//h4/a"))) 

    # Something is wrong here... 

唯一の本当の問題は、私がバグを突き止めることができないということです。その原因は何ですか?

PS:リストからa要素を取得する簡単な方法がありますが、これはほんの一例であり、実際のものにはもっと多くのものが含まれています。

答えて

0
print(len(list_item.xpath(".//h4/a"))) 

//それは/で始まるので、それは、文書のルートノードから検索します/descendant-or-self::node() を意味します。現在のコンテキストノードを指すように

使用.はない文書全体あなたの例では

1

、XPathは//から始まるとき、それはそれがあった理由である(文書のルートから検索を開始します、list_itemですアンカー要素の4つすべてに一致します)。あなたはli要素に対する検索したい場合は、主要なスラッシュを省略します:

for item in page.xpath("//li[@itemprop='itemListElement']"): 
    scan.append(item) 

for list_item in scan: 
    print(len(list_item.xpath(".//h4/a"))) 
:もちろん

for item in page.xpath("//li[@itemprop='itemListElement']"): 
    scan.append(item) 

for list_item in scan: 
    print(len(list_item.xpath("h4/a"))) 

を検索が同様に相対的であるように、あなたはまた.////を置き換えることができます

2.5 Abbreviated Syntax

:ここ

が仕様から取ら関連の引用です

//は、/descendant-or-self::node()/の略です。たとえば、//para/descendant-or-self::node()/child::paraの略であり、文書内でpara要素を選択します(para要素の文書要素でも//paraによって選択されます)。これは文書要素ノードがルートノードの子であるためです。 div//paradiv/descendant-or-self::node()/child::paraの略語なので、すべてpara子どもの子孫を選択します。

+0

'.//は問題を解決しました。あなたの答えに感謝します。しかしそれはなぜですか?最初に、ページを読み込んでhtmlを取得し、 'li'タグを抽出し、それぞれ**をリストに入れます。なぜ '/'を使うと違いがあるのでしょうか? 2回目の 'for'ループでは、' li'タグのそれぞれを繰り返し処理するので、 'h4'と' a'タグが1つだけ存在します。編集:それは 'li'タグを抽出した後でさえ、私たちはまだ全体のHTMLを持っていることでしょうか?これは真の犯人かもしれません。 – Eekan

+0

@Eekan - 'li'タグを抽出した後でも、XPathクエリはHTML全体にアクセスできます。あなたの例では、 'list_item'は' li'要素への参照です。私は、このようにした理由は、XPathがツリーをたどって親要素を選択できるためだと考えています。これは、 'li'がリファレンスでなければならず、ツリー上の他の要素が依然としてより複雑なクエリに利用できることを意味します。 –

+0

ありがとう、仲間。私はXPathをよく把握していると思います。 – Eekan

関連する問題