2015-04-21 5 views
0

Проблема: Я хочу найти xpath узлов, которые формируют текстовую строку в документе HTML. Язык используется питон (LXML для разбора документа)Получить xpath для узлов, которые образуют строку в документе HTML

Чтобы проиллюстрировать идею рассмотреть документ:

<HTML> 
 

 
<HEAD> 
 
    <TITLE>sample document</TITLE> 
 
</HEAD> 
 

 
<BODY BGCOLOR="FFFFFF"> 
 
    <HR> 
 
    <a href="http://google.com">Goog</a> 
 
    <H1>This is one header</H1> 
 
    <H2>This is a another Header</H2> 
 
    <P>Travel from 
 
    <P> 
 
     <B>SFO to JFK</B> 
 
     <BR> 
 
     <B><I>on May 2, 2015 at 2:00 pm. For details go to confirm.com </I></B> 
 
     <HR> 
 
     <div style="color:#0000FF"> 
 
     <h3>Traveler <b> name </b> is 
 
     <p> John Doe </p> 
 
     </div> 
 
.....

Теперь, учитывая строки «SFO в JFK на 2 мая 2015 »и« Имя путешественника - Джон Доу », как я могу получить Xpath для первого узла в наборе узлов, которые образуют строку. (Если это трудно даже множество узлов будет делать)

Примеры выходов:

"SFO to JFK on May 2, 2015" -> /html/body/p/p/b 
"Traveler name is John Doe" -> /html/body/p/p/div/h3 

В последующем наблюдении, вместо строки выше, если у нас есть регулярное выражение, что будет подход к решению проблема?

Примечание: С точки зрения реализации питона, я подходил к проблеме, как в фрагменте кода ниже

import lxml.html as lh 
from StringIO import StringIO 
from lxml import etree 

elem_tree = lh.parse(StringIO(html_document)) 
xpath = etree.XPath(_the_xpath_here) 
list_of_nodes = xpath(elem_tree) 
+0

Не будет ли xpath быть просто «// B», потому что это единственный элемент html, который вы ищете, который должен предоставить вам массив всех элементов B на странице. Также вы можете запускать xpaths в консоли Chrome с помощью $ x ("xpath"); – Asheliahut

+0

Ну, извините, я должен был уточнить. Документ не исправлен. Как и в вопросе, должен быть, если у меня есть HTML и набор строк, как бы получить xpath? – Ark

ответ

0

Вы можете попробовать этот подход:

import lxml.html as lh 
from lxml import etree 

elem_tree = lh.parse("Q12.html") 
input_string = ["SFO to JFK on May 2, 2015", "Traveler name is John Doe"] 

for i in input_string: 
    xpath = "//*[contains(normalize-space(.), '{0}') and not(.//*[contains(normalize-space(.), '{0}')])]/*" 
    node = elem_tree.xpath(xpath.format(i))[0] 

    print '{0} -> {1}'.format(i, elem_tree.getpath(node)) 

    #Output: 
    #SFO to JFK on May 2, 2015 -> /html/body/p[2]/b[1] 
    #Traveler name is John Doe -> /html/body/div/h3 

Краткое объяснение:

  • contains(normalize-space(.), '{0}') : Фильтр, содержащий узлы текст (один из input_string)

  • not(.//*[contains(normalize-space(.), '{0}')]): выберите узел, если какой-либо из его потомков не содержит текст. Другими словами, выберите внутренний узел, содержащий текст.

  • getpath(): "возвращает структурную, абсолютное выражение XPath, чтобы найти элемент."

ОБНОВЛЕНИЕ:

Заменить задней /* в xpath переменной строки к следующему:

/descendant-or-self::*[contains('{0}', text()) or contains(text(), '{0}')] 

Работает над структурой HTML, размещенной в вопросе, а также с той, которую вы связали ниже. Однако рассмотрение общих случаев, имеющих разную характеристику того, что было продемонстрировано в обоих примерах HTML, выходит за рамки запроса xpath в этом ответе.

+0

Хороший ответ и объяснение, за исключением того, что он не работает для всех строк для меня. (Например, html на странице https://gist.github.com/anonymous/3d4b059464773ebd2d2f, а строка, которую я пыталась найти, была «Телефон: 1-213-484-7000», но «xpath» выше не смог найти узел для того же самого). – Ark

+0

@Ark Проверьте ** раздел UPDATE **, который будет работать для HTML в том виде, в котором вы связаны. Однако я не пытаюсь решить все требования, которые вы ставите под сомнение. Кажется, слишком много: p – har07

+0

Спасибо за обновление! Да, общее решение было бы трудным, так как могут быть тонкие случаи. Однако я думаю, что ваш ответ дает хорошую начальную точку. :) – Ark

Смежные вопросы