选择器在具有定义词的两个元素之间抓取列表

Selectors to scrape lists between two elements with defined words

尝试抓取部分目录 (toc),最好使用 SoupSieve:

<html>
<dl>
#many rows
<dd>4.2.1. Drivers</dd>
<dd>4.2.1.1. itemD1</dd>
<dd>4.2.1.2. itemD2</dd>
<dd>4.2.1.3. itemD3</dd>
<dd>4.2.2. Constraints</dd>
<dd>4.2.2.1. itemC1</dd>
#many more rows
</dl>
</html>

请注意,我需要的项目不是 4.2.1 的 children/descendants。驱动程序,只是因为编号看起来像。

现在,我需要抓取的元素是元素 Drivers 和 Constraints 之间的元素。并不总是其中的 3 个——它可能是 0 个或 3 个或 5 个,这取决于。稍后在我的代码中,我使用 pandas 将这些元素输出到 .csv.

中的单个单元格中

我试过这样的事情:

def get_drivers():
    data.append({
        'url': url,
        'type': 'driver',
        'list': [x.get_text(strip=True) for x in toc.select('dd:-soup-contains-own("Drivers") ~ dd')]
    })

...但这只是给了我从驱动程序到文档末尾的所有元素,通常是我不需要的几十个元素。

问题:如何让选择器在 Drivers 之后开始选择并在 Constraints 停止选择?

您完全可以使用 css 选择器来做到这一点。使用 :-soup-contains:not,以及通用兄弟组合器 (~) 和类型选择器 (dd) 来过滤掉每个后面的内容(即减去 Constraints Drivers 开始

from bs4 import BeautifulSoup as bs

html = '''<html>
<dl>
#many rows
<dd>4.2.1. Drivers</dd>
<dd>4.2.1.1. itemD1</dd>
<dd>4.2.1.2. itemD2</dd>
<dd>4.2.1.3. itemD3</dd>
<dd>4.2.2. Constraints</dd>
<dd>4.2.2.1. itemC1</dd>
#many more rows
</dl>
</html>'''
soup = bs(html, 'lxml')
filtered = [i.text for i in soup.select(
    'dd:-soup-contains(" Drivers") ~ dd:not(dd:-soup-contains(" Constraints"), dd:-soup-contains(" Constraints") ~ dd)')]

我想一个循环也可以工作,但在我看来不太可取:

from bs4 import BeautifulSoup as bs

html = '''<html>
<dl>
#many rows
<dd>4.2.1. Drivers</dd>
<dd>4.2.1.1. itemD1</dd>
<dd>4.2.1.2. itemD2</dd>
<dd>4.2.1.3. itemD3</dd>
<dd>4.2.2. Constraints</dd>
<dd>4.2.2.1. itemC1</dd>
#many more rows
</dl>
<dl>
<dd>Error</dd>
</dl>
</html>'''
soup = bs(html, 'lxml')
start = soup.select_one('dd:-soup-contains(" Drivers") + dd')
next_node = start

while True:
    if not next_node:
        break
    if 'Constraints' in next_node.text:
        break
    print(next_node.text)
    next_node = next_node.find_next('dd')