如何使用 python-pptx 从 PowerPoint 中的组形状中的文本形状中提取文本。

How to extract text from a text shape within a Group Shape in powerpoint, using python-pptx.

我的 PowerPoint 幻灯片有许多组形状,其​​中有子文本形状。

之前我使用过这段代码,但它不处理组形状。

for eachfile in files:
prs = Presentation(eachfile)

textrun=[]
for slide in prs.slides:
    for shape in slide.shapes:
        if hasattr(shape, "text"):
            print(shape.text)
            textrun.append(shape.text)
new_list=" ".join(textrun)
text_list.append(new_list)

我正在尝试从这些子文本框中提取文本。我已经设法使用 GroupShape.shape 到达这些子元素 但是我得到一个错误,这些是 'property' 类型的,所以我无法访问文本或迭代它们(类型错误:'property' 对象不可迭代)。

from pptx.shapes.group import GroupShape
from pptx import Presentation
for eachfile in files:
prs = Presentation(eachfile)

textrun=[]
for slide in prs.slides:
    for shape in slide.shapes:
        for text in GroupShape.shapes:
            print(text)

然后我想捕获文本并附加到字符串以供进一步处理。

所以我的问题是,如何访问子文本元素并从中提取文本。

我花了很多时间浏览文档和源代码,但一直没弄明白。任何帮助将不胜感激。

我想你需要这样的东西:

from pptx.enum.shapes import MSO_SHAPE_TYPE

for slide in prs.slides:
    # ---only operate on group shapes---
    group_shapes = [
        shp for shp in slide.shapes
        if shp.shape_type == MSO_SHAPE_TYPE.GROUP
    ]
    for group_shape in group_shapes:
        for shape in group_shape.shapes:
            if shape.has_text_frame:
                print(shape.text)

组形状包含其他形状,可在其 .shapes 属性 上访问。它 而不是 本身有一个 .text 属性。因此,您需要迭代组中的形状并从每个形状中获取文本。

请注意,此解决方案仅深入一层。递归方法可用于深度优先遍历树,并从包含组的组中获取文本(如果有的话)。

另请注意,并非所有形状都有文本,因此您必须检查 .has_text_frame 属性 以避免在图片形状上引发异常。

较早的回答遗漏了一些更深入的 "group in group" 个案例。组形状可能包含许多级别的形状,包括组形状。因此,在许多现实生活中,需要在组形状中进行递归搜索。

之前的答案只解析了其中的一些(一直到第二层组形状)。但即使是那个层组形状也可能反过来包含更多的组。所以我们需要一个迭代搜索策略。这最好通过重用上面的代码来显示,保留第一部分:

from pptx.shapes.group import GroupShape
from pptx import Presentation
for eachfile in files:
prs = Presentation(eachfile)

textrun=[]
for slide in prs.slides:
    for shape in slide.shapes:

然后我们需要用递归部分的调用替换 "for text in GroupShape.shapes:" 测试:

    textrun=checkrecursivelyfortext(slide.shapes,textrun)

并且还插入函数的新递归函数定义(就像在 import 语句之后)。为了便于比较,插入的函数使用与上面相同的代码,只是添加了递归部分:

def checkrecursivelyfortext(shpthissetofshapes,textrun):
    for shape in shpthissetofshapes:
        if shape.shape_type == MSO_SHAPE_TYPE.GROUP:
            textrun=checkrecursivelyfortext(shape.shapes,textrun)
        else:
            if hasattr(shape, "text"):
                print(shape.text)
                textrun.append(shape.text)
    return textrun

Mats Bengtsson 的回答是正确的,除了逻辑错误中的一个小错误会导致它重新循环对象、一些非 pythonic 命名和缺少导入。

错误在这里:

for slide in prs.slides:
    for shape in slide.shapes:
        textrun = checkrecursivelyfortext(slide.shapes,textrun)

由于他创建的函数循环遍历 slide.shapes 中的所有形状,最终结果是对于幻灯片上的每个形状,它将递归循环遍历幻灯片上的所有形状!

这个修复很简单,只需删除“for shape in slide.shapes”的第二个循环并直接进入递归函数。

为了便于阅读,我将 post 整个固定片段。

from pptx.shapes.group import GroupShape
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx import Presentation

def check_recursively_for_text(this_set_of_shapes, text_run):
    for shape in this_set_of_shapes:
        if shape.shape_type == MSO_SHAPE_TYPE.GROUP:
            check_recursively_for_text(shape.shapes, text_run)
        else:
            if hasattr(shape, "text"):
                print(shape.text)
                text_run.append(shape.text)
    return text_run


for eachfile in files:
    prs = Presentation(eachfile)
    text_run=[]
    for slide in prs.slides:
        text_run = check_recursively_for_text(slide.shapes, text_run)