Как написать выражение xpath? - PullRequest
1 голос
/ 03 марта 2020
text = '''\
<html>
    <body>
        <p><strong>test</strong>TEXT A B </p>
        <p><strong>test</strong>TEXT A </p>
        <p><strong>test</strong>TEXT B </p>
        <p><strong>ok</strong>TEXT A B </p>
        <p>TEXT A B </p>
    <body>
</html>'''
import lxml.html
root = lxml.html.fromstring(text)

В html -тексте есть три p узла, я хочу извлечь <p><strong>test</strong>TEXT A B </p> по желанию.

Возможности:

1.текстовое значение Элемент p содержит A и B.
2.текстовое значение подэлемента p strong равно test.

node = root.xpath('.//p[contains(text(),"A") and contains(text(),"B")]')

Приведенное выше выражение извлечет три узла, i Попробуйте xpath:

node = root.xpath('.//p[/strong(contains(text(),"test")) and contains(text(),"A") and contains(text(),"B")]')

Это неверное выражение в xpath, как написать правильный формат?

Ответы [ 2 ]

1 голос
/ 04 марта 2020

Попробуйте решение, отличное от XPath, и оно вам может понравиться.

from simplified_scrapy import SimplifiedDoc
html = '''<html>
    <body>
        <p><strong>test</strong>TEXT A B </p>
        <p><strong>test</strong>TEXT A </p>
        <p><strong>test</strong>TEXT B </p>
        <p><strong>ok</strong>TEXT A B </p>
        <p>TEXT A B </p>
    <body>
</html>'''
doc = SimplifiedDoc(html)
ps = doc.selects('p').contains(['<strong>test</strong>','A','B'])
print (ps)

Результат:

[{'tag': 'p', 'html': '<strong>test</strong>TEXT A B '}]

Вы также можете попробовать следующий код, чтобы увидеть, что выводится .

print (doc.selects('p').containsOr(['<strong>test</strong>','<strong>ok</strong>']))
print (doc.selects('p').notContains(['<strong>test</strong>','<strong>ok</strong>']))
0 голосов
/ 03 марта 2020

Правильное выражение XPath с учетом ваших требований:

//p[contains(., 'A') and contains(., 'B') and strong/text() = 'test']"

Python output

>>> root.xpath("//p[contains(., 'A') and contains(., 'B') and strong/text() = 'test']")
[<Element p at 0x1075031b0>]

Проблема с вашими предлагаемыми подходами

Ваше первое решение не включает в себя все условия (текстовое содержание strong отсутствует), а второе включает strong() (вы, вероятно, имели в виду strong[]).

Ваше второе предлагаемый подход может быть изменен с минимальными изменениями, с тем же выводом:

>>>> root.xpath('//p[strong[contains(text(),"test")] and contains(text(),"A") and contains(text(),"B")]')
[<Element p at 0x1075031b0>]

Разница с моим решением выше состоит в том, что я проверяю строковое значение ., в то время как ваше решение имеет text().

...