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

时间:2018-08-06 06:22:50

标签: python text powerpoint 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'类型的,所以我无法访问它们上的文本或对其进行迭代(TypeError:'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)

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

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

我花了很多时间浏览文档和源代码,但无法弄清楚。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:2)

更早的答案错过了一些更深层次的“成组”案例。组形状可以包含许多级别的形状,包括组形状。因此,在许多现实生活中,需要在组形状之间进行递归搜索。

上一个答案仅解析其中一些(向下到组形状的第二层)。但是即使是该图层组形状也可能包含其他组。因此,我们需要一种迭代搜索策略。最好通过重用上面的代码,并保留第一部分来说明这一点:

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 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

答案 1 :(得分:1)

我认为您需要这样的东西:

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属性,以避免在图片形状上引发异常。

答案 2 :(得分:0)

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

错误在这里:

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

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

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

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

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)