XPath: Как получить текст между 2 HTML-тегами с одинаковым уровнем? - PullRequest
0 голосов
/ 30 апреля 2019

Я новичок в , и я работаю с , чтобы получать текст с разных генерируемых HTML-страниц.
Я получаю {id} тега заголовка от пользователя (<h1|2|.. id="title-{id}">text</h1|2|3..>). Мне нужно получить текст из всех тегов HTML между этим заголовком и следующим заголовком того же уровня. Поэтому, если заголовок h1, мне нужно получить весь текст всех тегов до следующего заголовка h1.
Все идентификаторы заголовков имеют одинаковый шаблон "title- {id}", где генерируется {id}.
Чтобы было понятнее, вот пример:

<html>
    <body>
        ...
        <h2 id="tittle-id1">id1</h2>
        bunch of tags containing text I want to get
        <h2 id="tittle-id2">id2</h2>
        ...
    </body>
</html>

ПРИМЕЧАНИЕ. Я не знаю, какой это может быть заголовок. Это может быть любой из тегов заголовка html от <h1> до <h6>


ОБНОВЛЕНИЕ:
Пробуя несколько вещей, я заметил, что не уверен, что следующий заголовок того же уровня или вообще существует. Так как заголовки используются как заголовки и подзаголовки. Данный идентификатор может быть последним подзаголовком, поэтому у меня будет заголовок более высокого уровня после или даже последний из страниц. Так что в основном у меня есть только идентификатор заголовка, и мне нужно получить весь текст «абзаца».


Работа вокруг:
Я нашел своего рода обходное решение:
Я делаю это в 3 шага:
Сначала я использую //*[@id='title-{id}], что позволяет мне получить полную строку с тегом, так что теперь я знаю, какой это заголовок тега.
Во-вторых, я использую //*[id='title-{id}]/following-sibling::*, это позволяет искать следующий заголовок того же или более высокого уровня {myHeader}.
Наконец, я использую //*[id='title-{id}]/following-sibling::* и //{myHeader}//preceding-sibling::*, чтобы узнать, что находится между или идти до конца страницы, если заголовок не найден.

Ответы [ 3 ]

2 голосов
/ 30 апреля 2019

Вот xpath для получения всех элементов между тегами h2.

//h2/following-sibling::*[count(following-sibling::h2)=1]

Вот пример HTML, который я использовал для имитации сценария.(обновите идентификатор, чтобы проверить различные опции, показанные ниже).

// [@ id = 'tittle-id1'] / follow :: [count (follow-родной брат :: [name () = имя (предыдущий родной брат :: [@ id = 'tittle-id1'])]) = 1]

<html><head></head><body>
 
        ...
        <h2 id="tittle-id1">id1</h2>
		  <h3 id="tittle-id3"> h3 tag</h3>
		  <h4 id="tittle-id4"> h4 tag</h4>
		  <h3 id="tittle-id5"> 2nd h3  tag</h3>
        bunch of tags containing text I want to get
		   <h5 id="tittle-id6"> h5 tag </h5>
        <h2 id="tittle-id2">id2</h2>
		<h4 id="tittle-id7"> 2nd h4 tag</h4>
        ...
    
	
</body></html>

вывод, если ввод пользователя: {id1} enter image description here

вывод, если ввод пользователя: {id4} enter image description here

выводится, если пользовательский ввод: {id3} enter image description here

Примечание. Этот xpath разработан для соответствия исходному сценарию публикации.

1 голос
/ 30 апреля 2019

Поскольку предикаты в XPath фильтруют список узлов контекста , вы не сможете выполнить выбор соединения, если не сможете повторно ввести целевые значения из относительного контекста исходных значений. Пример выбора всех элементов с таким же именем, как у элемента с определенным атрибутом id:

//*[name()=name(//*[@id=$generated-id-string])]

Теперь для "проблемы меток" используйте, как обычно, метод Кайса для пересечения:

//*[name()=name(//*[@id=$generated-id-string])]/preceding-sibling::node()[
   count(.|//*[@id=$generated-id-string]/following-sibling::node())
      =
   count(//*[@id=$generated-id-string]/following-sibling::node())
]

Тест в http://www.xpathtester.com/xpath/0dcfdf59dccb8faf3705c22167ae45f1

0 голосов
/ 06 мая 2019

Вот что у меня сработало:
Для этого имейте ввиду, что я использую с :

name_query = u"//*[name()=name(//*[@id='"+id+"'])]"
all = response.xpath(name_query)
for selector in all.getall():
     if self.id in selector:
          position = all.getall().index(selector)
balise = "h" + all.getall()[position].split("<h")[1][0]
title = all.getall()[position].split(">")[1].split("<")[0]
query = u"//*[preceding-sibling::"+balise+"[1] ='"+title+"' and following-sibling::"+balise+"]"
self.log('query = '+query)
results = response.xpath(query)
results.pop(len(results)-1)
with open(filename,'wb') as f:
    for text in results.css("::text").getall():
        f.write(text.encode('utf-8')+"\n")

В целом это должно работать. Я проверил его на нескольких заголовках с разными уровнями, он отлично работает для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...