Как выбрать тег по содержанию тега перед ним? - PullRequest
0 голосов
/ 16 апреля 2019

У меня есть HTML-страница, которая выглядит так:

<div>
<h1>First Item</h1>
<p> the text I want </p>
</div>

<div>
<h1>Second Item</h1>
<p> the text I don't want </p>
</div>

Заголовок «Первый элемент» может находиться на разных уровнях тегов на каждой странице, поэтому индекс не является фиксированным.

Я хочу, чтобы какая-то выборка выглядела как (это псевдокод).

from lxml import html

locate_position = locate(html.xpath(//div/h1[contains("First Item")])))

scrape = html.xpath(//div[locate_position]/p)

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

Это легко с bs4 4.7.1, если вы готовы рассмотреть возможность его использования.Вы можете использовать :contains pseudo class, чтобы указать, что h1 должен содержать строку поиска, и смежный братский комбинатор , чтобы указать, что совпадение должно иметь тег p сразу после.

Смежный соседний комбинатор (+) разделяет два селектора и соответствует второму элементу, только если он непосредственно следует за первым элементом, и оба являются потомками одного и того же родительского элемента.

from bs4 import BeautifulSoup as bs

html = '''
<div>
<h1>First Item</h1>
<p> the text I want </p>
</div>

<div>
<h1>Second Item</h1>
<p> the text I don't want </p>
</div>
'''

soup = bs(html, 'lxml')

#multiple matches possible
matches = [match.text for match in soup.select('h1:contains("First Item") + p')]
print(matches)

# first match (useful if only one match expected or first required)
soup.select_one('h1:contains("First Item") + p').text
0 голосов
/ 16 апреля 2019

Если вы просто хотите соответствовать предыдущему брату:

/p/preceding-sibling::contains(h1,"First Item")

Вариант, более близкий к вашему примеру:

/div[contains(h1, "First Item")]/p

Которые получают p, которые являются дочерними элементами div, у которых есть h1 child.

...