2012-05-16 34 views
13

Mục tiêu: Trích xuất văn bản từ một phần tử cụ thể (ví dụ: li), trong khi bỏ qua các thẻ hỗn hợp khác nhau, tức là làm phẳng con đầu tiên và chỉ cần trả lại văn bản được ghép nối của từng con riêng biệt.HTML XPath: Trích xuất văn bản được trộn lẫn với nhiều thẻ?

Ví dụ:

<div id="mw-content-text"><h2><span class="mw-headline" >CIA</span></h2> 
    <ol> 
    <li>Central <a href="/Intelligence_Agency.html">Intelligence Agency</a>.</li> 
    <li>Culinary <a href="/Institute.html">Institute</a> of <a href="/America.html">America</a>.</li> 
    </ol> 

    </Div> 

văn bản mong muốn:

  • Cơ quan Tình báo Trung ương
  • Culinary Institute of America

Trừ rằng các thẻ neo xung quanh ngăn cản một hồi đơn giản.

Để trở về mỗi thẻ li riêng biệt, chúng tôi sử dụng đơn giản:

//div[contains(@id,"mw-content-text")]/ol/li 

nhưng điều đó cũng bao gồm xung quanh thẻ neo, vv Và

//div[contains(@id,"mw-content-text")]/ol/li/text() 

lợi nhuận chỉ có yếu tố văn bản đó là trẻ em trực tiếp của li, tức là 'Trung tâm', '.'...

Có vẻ hợp lý khi đó tìm kiếm các phần tử văn bản của tự và con cháu

//div[contains(@id,"mw-content-text")]/ol/li[descendant-or-self::text] 

nhưng điều đó không trả về gì cả!

Mọi đề xuất? Tôi đang sử dụng Python, vì vậy tôi mở để sử dụng các mô-đun khác để xử lý hậu kỳ.

(Tôi đang sử dụng Scrapy HtmlXPathSelector mà dường như XPath 1.0 compliant)

+0

Có thể hữu ích: http://stackoverflow.com/questions/4378502/xpath-return-all-non-blank-text-nodes-not-descendant-of-a-style-or-script/6303276 – warvariuc

Trả lời

24

Bạn sắp hoàn tất.Có một vấn đề nhỏ trong:

//div[contains(@id,"mw-content-text")]/ol/li[descendant-or-self::text] 

Biểu thức điều chỉnh là:

//div[contains(@id,"mw-content-text")]/ol/li[descendant-or-self::text()] 

Tuy nhiên, có một biểu thức đơn giản mà tạo ra chính xác nối truy nã của tất cả các văn bản nút theo quy định li:

string(//div[contains(@id,"mw-content-text")]/ol/li) 
+0

Có một lý do cụ thể tại sao 'contains' được sử dụng thay vì' @ id = 'hay là nó chỉ vì OP đã đặt câu hỏi với' contains'? – Kiril

+0

@Lirik, Với câu trả lời này, tôi giúp OP lấy mã của anh ấy làm những gì anh ta muốn - tôi không thể đoán anh ấy muốn chọn 'div' với thuộc tính' id', hay với thuộc tính 'id' có chứa một chuỗi đã cho. Có thể anh ta là người trước đây, nhưng người trả lời nên tránh đoán trước, bất cứ khi nào có thể. –

2

Chuỗi nối là khéo léo. Dưới đây là một giải pháp nhanh chóng sử dụng lxml:

>>> from lxml import etree 
>>> doc = etree.HTML("""<div id="mw-content-text"><h2><span class="mw-headline" >CIA</span></h2> 
...  <ol> 
...  <li>Central <a href="/Intelligence_Agency.html">Intelligence Agency</a>.</li> 
...  <li>Culinary <a href="/Institute.html">Institute</a> of <a href="/America.html">America</a>.</li> 
...  </ol> 
... 
...  </Div>""") 
>>> for element in doc.xpath('//div[@id="mw-content-text"]/ol/li'): 
... print "".join(element.xpath('descendant-or-self::text()')) 
... 
Central Intelligence Agency. 
Culinary Institute of America. 

Xin lưu ý rằng // có hiệu suất/thực hiện ngoài ý muốn có khả năng kém và nên tránh nếu có thể, nhưng khó có thể làm như vậy với ví dụ HTML mảnh.

5

Tôi nghĩ rằng những điều sau đây sẽ trả lại kết quả chính xác:

//div[contains(@id,"mw-content-text")]/ol/li//text() 

Lưu ý dấu gạch chéo kép trước khi văn bản(). Điều này có nghĩa là các nút văn bản trên bất kỳ mức nào dưới đây li phải được trả lại.

+0

Đây là một ý tưởng hay, nhưng nó trả về tất cả các phần tử văn bản, mà không có bất kỳ ngữ cảnh nào mà chúng xuất phát từ đó. Kiểm tra với 'Trình kiểm tra XPath' của Firefox tôi nhận được: 1: Trung tâm 2: Cơ quan tình báo 3:. 4: Ẩm thực 5: Viện 6: của 7: Mỹ 8:. Không có cách nào để biết văn bản nào xuất phát từ đó ... – ChaimKut

+0

Nếu mỗi dòng kết thúc bằng dấu chấm (và không có dòng nào có dấu chấm ở giữa (như Tiến sĩ, Mr., v.v.)), bạn có thể nối tất cả các văn bản lên đến thời kỳ và chỉ giả định rằng mỗi giai đoạn == kết thúc của một li. – rishimaharaj

Các vấn đề liên quan