Skip to main content

Extract content from docx files

Project description

docx2python

Extract docx headers, footers, text, properties, and images to a Python object.

full documentation

The code is an expansion/contraction of python-docx2txt (Copyright (c) 2015 Ankush Shah). The original code is mostly gone, but some of the bones may still be here.

shared features:

  • extracts text from docx files
  • extracts images from docx files
  • no dependencies (docx2python requires pytest to test)

additions:

  • converts bullets and numbered lists to ascii with indentation
  • retains some structure of the original file (more below)
  • extracts document properties (creator, lastModifiedBy, etc.)
  • inserts image placeholders in text ('----image1.jpg----')
  • (optionally) retains font size, font color, bold, italics, and underscore as html
  • full test coverage and documentation for developers

subtractions:

  • no command-line interface
  • will only work with later versions of Python

Installation

pip install docx2python

Use

from docx2python import docx2python

# extract docx content
docx2python('path/to/file.docx')

# extract docx content, write images to image_directory
docx2python('path/to/file.docx', 'path/to/image_directory')

# extract docx content with basic font styles converted to html
docx2python('path/to/file.docx', html=True)

Note on html feature:

  • font size, font color, bold, italics, and underline supported
  • every tag open in a paragraph will be closed in that paragraph (and, where appropriate, reopened in the next paragraph). If two subsequenct paragraphs are bold, they will be returned as <b>paragraph q</b>, <b>paragraph 2</b>. This is intentional to make each paragraph its own entity.
  • if you specify export_font_style=True, > and < in your docx text will be encoded as &gt; and &lt;

Return Value

Function docx2python returns an object with several attributes.

header - contents of the docx headers in the return format described herein

footer - contents of the docx footers in the return format described herein

body - contents of the docx in the return format described herein

document - header + body + footer (read only)

text - all docx text as one string, similar to what you'd get from python-docx2txt

properties - docx property names mapped to values (e.g., {"lastModifiedBy": "Shay Hill"})

images - image names mapped to images in binary format. Write to filesystem with

for name, image in result.images.items():
    with open(name, 'wb') as image_destination:
        write(image_destination, image)

Return Format

Some structure will be maintained. Text will be returned in a nested list, with paragraphs always at depth 4 (i.e., output.body[i][j][k][l] will be a paragraph).

If your docx has no tables, output.body will appear as one a table with all contents in one cell:

[  # document
    [  # table
        [  # row
            [  # cell
                "Paragraph 1",
                "Paragraph 2",
                "-- bulleted list",
                "-- continuing bulleted list",
                "1)  numbered list",
                "2)  continuing numbered list"
                "    a)  sublist",
                "        i)  sublist of sublist",
                "3)  keeps track of indention levels",
                "    a)  resets sublist counters"
            ]
        ]
     ]
 ]

Table cells will appear as table cells. Text outside tables will appear as table cells.

To preserve the even depth (text always at depth 4), nested tables will appear as new, top-level tables. This is clearer with an example:

#  docx structure

[  # document
    [  # table A
        [  # table A row
            [  # table A cell 1
                "paragraph in table A cell 1"
            ],
            [  # nested table B
                [  # table B row
                    [  # table B cell
                        "paragraph in table B"
                    ]
                ]
            ],
            [  # table A cell 2
                'paragraph in table A cell 2'
            ]
        ]
    ]
]

becomes ...

[  # document 
    [  # table A
        [  # row in table A
            [  # cell in table A
                "table A cell 1"
            ]
        ]
    ],
    [  # table B
        [  # row in table B
            [  # cell in table B
                "table B cell"
            ]
        ]
    ],
    [  # table C
        [  # row in table C
            [  # cell in table C
                "table A cell 2"
            ]
        ]
    ]
]

This ensures text appears

  1. only once
  2. in the order it appears on the docx
  3. always at depth four (i.e., result.body[i][j][k][l] will be a string).

Working with output

This package provides several documented helper functions in the docx2python.iterators module. Here are a few recipes possible with these functions:

from docx2python.iterators import enum_cells

def remove_empty_paragraphs(tables):
    for (i, j, k), cell in enum_cells(tables):
        tables[i][j][k] = [x for x in cell if x]
>>> tables = [[[['a', 'b'], ['a', '', 'd', '']]]]
>>> remove_empty_paragraphs(tables)
    [[[['a', 'b'], ['a', 'd']]]]
from docx2python.iterators import enum_at_depth

def html_map(tables) -> str:
    """Create an HTML map of document contents.

    Render this in a browser to visually search for data.
    """
    tables = self.document

    # prepend index tuple to each paragraph
    for (i, j, k, l), paragraph in enum_at_depth(tables, 4):
        tables[i][j][k][l] = " ".join([str((i, j, k, l)), paragraph])

    # wrap each paragraph in <pre> tags
    for (i, j, k), cell in enum_at_depth(tables, 3):
        tables[i][j][k] = "".join([f"<pre>{x}</pre>" for x in cell])

    # wrap each cell in <td> tags
    for (i, j), row in enum_at_depth(tables, 2):
        tables[i][j] = "".join([f"<td>{x}</td>" for x in row])

    # wrap each row in <tr> tags
    for (i,), table in enum_at_depth(tables, 1):
        tables[i] = "".join(f"<tr>{x}</tr>" for x in table)

    # wrap each table in <table> tags
    tables = "".join([f'<table border="1">{x}</table>' for x in tables])

    return ["<html><body>"] + tables + ["</body></html>"]
>>> tables = [[[['a', 'b'], ['a', 'd']]]]
>>> html_toc(tables)
<html>
    <body>
        <table border="1">
            <tr>
                <td>
                    '(0, 0, 0, 0) a'
                    '(0, 0, 0, 1) b'
                </td>
                <td>
                    '(0, 0, 1, 0) a'
                    '(0, 0, 1, 1) d'
                </td>
            </tr>
        </table>
    </body>
</html>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

docx2python-1.1.tar.gz (23.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

docx2python-1.1.0-py3-none-any.whl (21.0 kB view details)

Uploaded Python 3

docx2python-1.1-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

File details

Details for the file docx2python-1.1.tar.gz.

File metadata

  • Download URL: docx2python-1.1.tar.gz
  • Upload date:
  • Size: 23.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.3

File hashes

Hashes for docx2python-1.1.tar.gz
Algorithm Hash digest
SHA256 39a85d4b57025bf27401b93714bdd12305dbcafe4c4affb36004b8aa3bd61879
MD5 4b38260a6554ca532e069eda1002b1be
BLAKE2b-256 85be6e9dd87e937274a83f9819754d19c2f9a9ff162db7bfe959b957dfd43536

See more details on using hashes here.

File details

Details for the file docx2python-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: docx2python-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 21.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.1

File hashes

Hashes for docx2python-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cf4a279e289cfb35291efdc9b0d77639ab332a4cf346e2a6b8ae478f69d61499
MD5 622e2c7003a059df95e1daa6751e94a7
BLAKE2b-256 087266ac4e92fb2269a44cec957f45d0be90ed69b3433ea64a38acf424825040

See more details on using hashes here.

File details

Details for the file docx2python-1.1-py3-none-any.whl.

File metadata

  • Download URL: docx2python-1.1-py3-none-any.whl
  • Upload date:
  • Size: 18.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.3

File hashes

Hashes for docx2python-1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 82d1c1cee278fe1073f3f1aa04672597453eb70f891021a3b56c6259d89e317c
MD5 4ad06c54d1273859fb95d8bbf199f9b1
BLAKE2b-256 3a86a718d55d478e4d6288f59833137d0aff21800085cc3b17010f1fcc05ccb2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page