如何使用 BeautifulSoup 从父子标签中获取文本以放入 DOCX 表中

Posted

技术标签:

【中文标题】如何使用 BeautifulSoup 从父子标签中获取文本以放入 DOCX 表中【英文标题】:How to use BeautifulSoup to get text from parent and children tags to put into a DOCX table 【发布时间】:2019-11-10 11:29:41 【问题描述】:

我正在尝试使用 BeautifulSoup 解析来自 google.com/patents 的声明并将它们放入 DOCX 表中。

我已经设法检索到声明,但不幸的是,父 div 标签包含声明的第一部分,而子 div-s 是声明其余部分的一部分,如下图所示。

当我运行程序时,表格中的第一个单元格包含父单元格和所有子单元格 div 文本,并且 div 子单元格传播以下表格单元格。

我想用父 div 中的文本传播 DOCX 表中的第一个单元格,同时排除子 div,然后用子 div-s 中的文本传播以下单元格。

我已尝试 .decompose 声明以获取父级, 我已经尝试弄清楚如何重命名孩子以放入表格中。

   from bs4 import BeautifulSoup
   import requests
   from docx import Document
   from docx.enum.table import WD_TABLE_DIRECTION

   document = Document()

   url = 'https://patents.google.com/patent/US7054130?oq=US7654309'

   response = requests.get(url)
   data = response.text
   soup = BeautifulSoup(data, 'html.parser')

   claims = soup.select('div .claim-text')

   table = document.add_table(rows=1, cols=2, style='Table Grid')

   for claim in claims:

        if not claim.find('claim-ref'):

            try:
                print(claim.text + '\n')
                cells = table.add_row().cells
                cells[0].text = claim.text

                # Add space between paragraphs
                document.add_paragraph('')

            except:

                continue

    document.save('my_test.docx')

我希望能够使用从父项中找到的声明开头到 DOCX 表的单元格 1 中的文本解析声明,并从单元格中排除子项。孩子们应该各自进入自己的牢房。

这是我尝试运行程序时得到的结果:

这就是我想要实现的目标:

我一直无法弄清楚如何将文本与父级和子级分开。

【问题讨论】:

请edit您的问题显示您希望该网址的前几行看起来像什么。 【参考方案1】:

为避免重复,只需从顶部 div 获取整个文本并适当拆分,例如:

from bs4 import BeautifulSoup
import requests
from docx import Document

document = Document()
url = 'https://patents.google.com/patent/US7054130?oq=US7654309'
response = requests.get(url)
data = response.text
soup = BeautifulSoup(data, 'html.parser')
claims_section = soup.find('section', itemprop='claims').div.div
table = document.add_table(rows=0, cols=2, style='Table Grid')

for div in claims_section.find_all('div', class_='claim', recursive=False):
    div_claim_text = div.find_next('div', class_='claim-text')
    lines = [line.strip() for line in div_claim_text.text.splitlines() if line.strip()]

    for line in lines:
        cells = table.add_row().cells
        cells[0].text = line

document.save('my_test.docx')

这种方法只存储独立声明。

【讨论】:

@BubbaJones,我添加了一种可能有帮助的替代方法。 我认为我有部分解决方案使用您的示例和上面提供的代码。不幸的是,在尝试了其他专利号后,我发现它并不总是有效。 我以为我有解决问题的方法,但在现实生活中绑定后,我发现它并不总是有效。您的代码可以很好地获得所有声明,而不仅仅是独立声明。我使用 if "claim.find('claim-ref'): ... continue" 部分过滤从属声明。我对 Python/BeautifulSoup 很陌生,所以如果我的代码看起来很古怪,那就是原因。您将如何正确修改您的代码以获得独立声明?我已经尝试了一段时间,看起来我失败了...... @BubbaJones,我已将其修改为仅返回独立声明,即11629【参考方案2】:

我以为我找到了解决方案;但是在现实生活中应用代码已经证明代码是错误的。

嵌套的 div 导致表中出现重复条目​​。我尝试使用分解功能来解决问题,但如果声明有多层嵌套的 div 标签,它会失败。

from bs4 import BeautifulSoup
import requests
from docx import Document
from docx.enum.table import WD_TABLE_DIRECTION

document = Document()
url = 'https://patents.google.com/patent/US7054130?oq=US7654309'
response = requests.get(url)
data = response.text
soup = BeautifulSoup(data, 'html.parser')
#claims = soup.select('div .claim-text')
claims =soup.find_all("div", class_="claim-text")




for claim in claims:

    table = document.add_table(rows=0, cols=2, style='Table Grid')
    if claim.find('claim-ref'):
        continue

    else:
        try:
            claim.find('div').decompose()
        except:
            continue
        for row in claim.parent.text.split('\n'):
            if row == '':
                continue
            else:
                cells = table.add_row().cells
                cells[0].text = row
                print(row)
            # Add space between tables
    document.add_paragraph('')

再次感谢!

【讨论】:

【参考方案3】:

您可以从父 div 获取文本,然后从子 div 获取文本,然后将数据附加到为此目的创建的新列表中。

//div/text[1] 允许从 div 中获取第一个文本

[e for e in _list if e] 允许删除空元素

试试这个:

from lxml import html
import requests
from docx import Document
from docx.enum.table import WD_TABLE_DIRECTION

document = Document()

url = 'https://patents.google.com/patent/US7054130?oq=US7654309'

response = requests.get(url)
data = response.text
doc = html.fromstring(data)

parent_claim = [e.strip() for e in doc.xpath("//div[@id='CLM-00001']/div[@class='claim-text']/text()[1]") if e.strip()]
children_claims = [e.strip() for e in doc.xpath("//div[@id='CLM-00001']/div[@class='claim-text']/div[@class='claim-text']/text()") if e.strip()]
table = document.add_table(rows=1, cols=2, style='Table Grid')
claims = []
for e in parent_claim:
    claims.append(e)
for e in children_claims:
    claims.append(e)

for claim in claims:

        print(claim + '\n')
        cells = table.add_row().cells
        cells[0].text = claim

        # Add space between paragraphs
        document.add_paragraph('')

document.save('my_test.docx')

输出:

【讨论】:

很遗憾,原代码检索到了所有独立权利要求,排除了从属权利要求。我不确定如何实现您的代码以达到相同的结果。我很感激你的帮助。 =)

以上是关于如何使用 BeautifulSoup 从父子标签中获取文本以放入 DOCX 表中的主要内容,如果未能解决你的问题,请参考以下文章

Python/BeautifulSoup - 如何从元素中删除所有标签?

如何从 BeautifulSoup4 中的 html 标签中找到特定的数据属性?

如何使用 BeautifulSoup 在标签内获取 html 文本

BeautifulSoup 仅提取***标签[重复]

在 Python 中使用 BeautifulSoup 从脚本标签中提取文本

使用 BeautifulSoup 从 img 标签中提取 src 属性