Использование xpath в rvest для очистки содержимого между двумя заголовками h5?

Я занимаюсь извлечением содержимого из локальных html-файлов с помощью rvest. Я хотел бы извлечь определенный сегмент контента между двумя заголовками h5, единственной «указывающей» деталью является текстовое название начального заголовка h5. Проблема в том, что документы различаются по своим заголовкам — как идентификаторы, так и текстовое содержание подвержены многим вариациям — единственным исключением является текстовый заголовок «Подробности», который меня интересует. Пожалуйста, посмотрите пример структуры документа:

<div id=”document”>
<h3>Title of the document</h3>
<h4 id=”id11111”>Focus of the document</h4>
<p>This document focuses on…</p>
<p>And also…</p>
<h5 id=”id22222”> 1. Introduction </h5>
<p>Text here.</p>
<h6 id=”33333”> 1.1 Preliminary introduction </h6>
<p> Text here. </p>
<h5 id=”id44444”> 2. Details </h5>
<p>Text here.</p>
<h6 id=”id55555”> 2.1 Details about A </h6>
<p> Text here. </p>
<h6 id=”id66666”> 2.2 Details about B </h6>
<p> Text here. </p>
<h5 id=”id77777”> 3. Timeline </h5>
<p>Text here.</p>
<h6 id=”id88888”> 3.1 Timeline A </h5>
<p>Text here.</p>
</div>

Из предыдущего примера я хотел бы извлечь только и только содержимое тега h5 с id44444, текстовый заголовок «2. Details» до следующего заголовка h5 (h5 id 77777, 3, временная шкала).

Мне удалось точно определить, что мой парсинг начинается с желаемого тега h5 (см. Пример ниже), используя contains и следующий-sibling::*, но он возвращает все одноуровневые элементы до конца документа, тогда как моя цель - остановить возврат к следующему заголовку h5.

Я не понял, как использовать «предшествующий брат», потому что следующий тег h5 не имеет стандартного идентификатора, xpath или текстового содержимого, а порядок заголовков нестандартен. Заголовки h5 могут появляться в разном порядке.

#loading rvest
library('rvest')


files <- list.files(”C:/htmldocuments”)

#performing the scrape
scraping <- sapply(files, function (x)
read_html(x, encoding = "utf-8") %>%
html_nodes(xpath = '//h5[contains(., ”Details”)]/following-sibling::*') %>%
html_text())

Это возвращает результаты, которые начинаются в правильном месте, но как его можно остановить до первого следующего тега h5 после тега h5 «Подробности»? Идентификатор и заголовок следующего тега h5 различаются и поэтому неизвестны.

Я просмотрел несколько похожих вопросов - ответы часто указывают на использование предшествующего брата - однако я не могу понять, как его использовать, поскольку у меня нет возможности узнать, что такое следующий h5.


person voppikode    schedule 29.05.2020    source источник


Ответы (1)


Вы можете использовать следующее выражение XPath:

//p[preceding::*[1][contains(.,"Details")]]

При этом будут выбраны все элементы p, которым предшествует элемент заголовка, содержащий слово «Подробности».

Выход: 3 узла

Узлы

Если вам нужно сохранить заголовки, вы можете использовать:

//*[preceding::*[1][contains(.,"Details")] or contains(text(),"Details")]

Выход: 6 узлов

person E.Wiest    schedule 29.05.2020
comment
Спасибо @E.Wiest за ответ. Я попробовал ваше решение, и оно сработало! Является ли ваше решение «универсальным» в том смысле, что оно также применимо к случаям, когда есть несколько глав текста ниже h6s? <h5 id=”id44444”> 2. Details </h5> <p>Text here.</p> <p>Text here.</p> <h6 id=”id55555”> 2.1 Details about A </h6> <p> Text here. </p> <p>Text here.</p> <p>Text here.</p> <p>Text here.</p> <h6 id=”id66666”> 2.2 Details about B </h6> <p> Text here. </p> <p>Text here.</p> <h5 id=”id77777”> 3. Timeline </h5> В такого рода документах результаты были частичными, к моему большому удивлению... - person voppikode; 01.06.2020
comment
В этом случае вы можете использовать: //p[preceding::h5[1][contains(.,"Details")]]. Вывод: framapic.org/SF45n58G7sVt/1lgVOeH6VEfL.PNG - person E.Wiest; 01.06.2020