web-dev-qa-db-fra.com

extraire du texte à partir de fichiers MS Word dans python

pour travailler avec des fichiers MS Word en python, il existe des extensions python win32, qui peuvent être utilisées dans windows. Comment faire de même sous linux? Y a-t-il une bibliothèque?

27
Badri

Vous pouvez effectuer un appel de sous-processus à antiword . Antiword est un utilitaire de ligne de commande Linux pour vider le texte d'un document Word. Fonctionne assez bien pour les documents simples (évidemment, il perd le formatage). Il est disponible via apt, et probablement sous forme de RPM, ou vous pouvez le compiler vous-même.

20
John Fouhy

Utilisez le natif Python docx . Voici comment extraire tout le texte d'un document:

document = docx.Document(filename)
docText = '\n\n'.join([
    paragraph.text.encode('utf-8') for paragraph in document.paragraphs
])
print docText

Voir site Python DocX

Consultez également Textract qui extrait les tables, etc.

L'analyse de XML avec des expressions rationnelles appelle cthulu. Ne fais pas ça!

31
mikemaccana

benjamin la réponse est plutôt bonne. Je viens de consolider ...

import zipfile, re

docx = zipfile.ZipFile('/path/to/file/mydocument.docx')
content = docx.read('Word/document.xml').decode('utf-8')
cleaned = re.sub('<(.|\n)*?>','',content)
print(cleaned)
14
Chad

OpenOffice.org peut être scripté avec Python: voir ici .

Étant donné que OOo peut charger la plupart des fichiers MS Word sans problème, je dirais que c'est votre meilleur choix.

11
Dan Lenski

Je sais que c'est une vieille question, mais j'ai récemment essayé de trouver un moyen d'extraire du texte à partir de fichiers MS Word, et la meilleure solution que j'ai trouvée était de loin avec wvLib:

http://wvware.sourceforge.net/

Après avoir installé la bibliothèque, son utilisation dans Python est assez simple:

import commands

exe = 'wvText ' + Word_file + ' ' + output_txt_file
out = commands.getoutput(exe)
exe = 'cat ' + output_txt_file
out = commands.getoutput(exe)

Et c'est tout. À peu près, ce que nous faisons est d'utiliser la fonction commands.getouput pour exécuter quelques scripts Shell, à savoir wvText (qui extrait le texte d'un document Word, et cat pour lire la sortie du fichier). Après cela, le texte entier du document Word sera dans la variable out, prêt à l'emploi.

J'espère que cela aidera à l'avenir toute personne ayant des problèmes similaires.

5
David

Jetez un œil à comment fonctionne le format doc et créez un document Word en utilisant PHP sous linux . Le premier est particulièrement utile. Abiword est mon outil recommandé. Il y a cependant limitations :

Cependant, si le document comporte des tableaux, des zones de texte, des feuilles de calcul incorporées et ainsi de suite, il peut ne pas fonctionner comme prévu. Développer de bons filtres MS Word est un processus très difficile, alors soyez patient avec nous alors que nous nous efforçons d'ouvrir correctement les documents Word. Si vous avez un document Word qui ne parvient pas à se charger, veuillez ouvrir un bogue et inclure le document afin que nous puissions améliorer l'importateur.

4
Swati

Si votre intention est d'utiliser uniquement des modules python sans appeler un sous-processus, vous pouvez utiliser le fichier zip python modude).

content = ""
# Load DocX into zipfile
docx = zipfile.ZipFile('/home/whateverdocument.docx')
# Unpack zipfile
unpacked = docx.infolist()
# Find the /Word/document.xml file in the package and assign it to variable
for item in unpacked:
    if item.orig_filename == 'Word/document.xml':
        content = docx.read(item.orig_filename)

    else:
        pass

Votre chaîne de contenu doit cependant être nettoyée, une façon de procéder est:

# Clean the content string from xml tags for better search
fullyclean = []
halfclean = content.split('<')
for item in halfclean:
    if '>' in item:
        bad_good = item.split('>')
        if bad_good[-1] != '':
            fullyclean.append(bad_good[-1])
        else:
            pass
    else:
        pass

# Assemble a new string with all pure content
content = " ".join(fullyclean)

Mais il existe sûrement un moyen plus élégant de nettoyer la chaîne, probablement en utilisant le module re. J'espère que cela t'aides.

4
benjamin

(Remarque: j'ai également posté ceci sur cette question , mais cela semble pertinent ici, alors veuillez excuser la rediffusion.)

Maintenant, c'est assez moche et assez hacky, mais cela semble fonctionner pour moi pour l'extraction de texte de base. Évidemment, pour l'utiliser dans un programme Qt, vous devez générer un processus pour cela, etc., mais la ligne de commande que j'ai piratée ensemble est:

unzip -p file.docx | grep '<w:t' | sed 's/<[^<]*>//g' | grep -v '^[[:space:]]*$'

Donc, c'est:

décompressez -p file.docx : -p == "décompressez vers stdout"

grep '<w: t' : Prenez uniquement les lignes contenant '<w: t' (<w: t> est l'élément XML de Word 2007 pour "texte", pour autant que je sache)

sed 's/<[^ <] > // g' *: supprime tout ce qui se trouve dans les balises

grep -v '^ [[: espace:]] $' *: supprime les lignes vides

Il existe probablement un moyen plus efficace de le faire, mais cela semble fonctionner pour moi sur les quelques documents avec lesquels je l'ai testé.

Pour autant que je sache, décompressez, grep et sed ont tous des ports pour Windows et l'un des Unix, donc cela devrait être raisonnablement multiplateforme. Despit étant un peu un hack laid;)

4
Ben Williams
3
markling

Je ne sais pas si vous allez avoir beaucoup de chance sans utiliser COM. Le format .doc est ridiculement complexe, et est souvent appelé un "vidage de mémoire" de Word au moment de l'enregistrement!

Chez Swati, c'est en HTML, ce qui est bien et dandy, mais la plupart des documents Word ne sont pas si gentils!

3
William Keller

Unoconv pourrait également être une bonne alternative: http://linux.die.net/man/1/unoconv

3
fccoelho

Pour lire les fichiers Word 2007 et versions ultérieures, y compris les fichiers .docx, vous pouvez utiliser le package python-docx :

from docx import Document
document = Document('existing-document-file.docx')
document.save('new-file-name.docx')

Pour lire les fichiers .doc à partir de Word 2003 et versions antérieures, effectuez un appel de sous-processus à antiword . Vous devez d'abord installer antiword:

Sudo apt-get install antiword

Ensuite, appelez-le simplement depuis votre script python:

import os
input_Word_file = "input_file.doc"
output_text_file = "output_file.txt"
os.system('antiword %s > %s' % (input_Word_file, output_text_file))
3
Antoine Dusséaux

Est-ce une vieille question? Je crois qu'une telle chose n'existe pas. Il n'y a que des réponses et des réponses. Celui-ci est assez sans réponse, ou à moitié répondu si vous le souhaitez. Eh bien, les méthodes de lecture des documents * .docx (MS Word 2007 et versions ultérieures) sans utiliser l'interopérabilité COM sont toutes couvertes. Mais les méthodes d'extraction de texte à partir de * .doc (MS Word 97-2000), en utilisant Python uniquement, manquent. Est-ce compliqué? À faire: pas vraiment, à comprendre: eh bien, c'est une autre chose .

Quand je n'ai pas trouvé de code fini, j'ai lu certaines spécifications de format et trouvé quelques algorithmes proposés dans d'autres langues.

Le fichier MS Word (* .doc) est un fichier composé OLE2. Pour ne pas vous déranger avec beaucoup de détails inutiles, pensez-y comme un système de fichiers stocké dans un fichier. Il utilise en fait la structure FAT, donc la définition est vraie. (Hm, vous pouvez peut-être le monter en boucle sous Linux ???) De cette façon, vous pouvez stocker plus de fichiers dans un fichier, comme des images, etc. La même chose se fait dans * .docx en utilisant l'archive Zip à la place. Il existe des packages disponibles sur PyPI qui peuvent lire les fichiers OLE. Comme (olefile, compoundfiles, ...), j'ai utilisé le package compoundfiles pour ouvrir le fichier * .doc. Cependant, dans MS Word 97-2000 , les sous-fichiers internes ne sont pas XML ou HTML, mais des fichiers binaires. Et comme cela ne suffit pas, chacun contient des informations sur l'autre, vous devez donc en lire au moins deux et décompresser les informations stockées en conséquence. Pour bien comprendre, lisez le PDF document à partir duquel j'ai pris l'algorithme.

Le code ci-dessous est très rapidement composé et testé sur un petit nombre de fichiers. Pour autant que je puisse voir, cela fonctionne comme prévu. Parfois, du charabia apparaît au début et presque toujours à la fin du texte. Et il peut également y avoir des caractères étranges entre les deux.

Ceux d'entre vous qui souhaitent simplement rechercher du texte seront ravis. Néanmoins, j'exhorte tous ceux qui peuvent aider à améliorer ce code à le faire.


doc2text module:
"""
This is Python implementation of C# algorithm proposed in:
http://b2xtranslator.sourceforge.net/howtos/How_to_retrieve_text_from_a_binary_doc_file.pdf

Python implementation author is Dalen Bernaca.
Code needs refining and probably bug fixing!
As I am not a C# expert I would like some code rechecks by one.
Parts of which I am uncertain are:
    * Did the author of original algorithm used uint32 and int32 when unpacking correctly?
      I copied each occurence as in original algo.
    * Is the FIB length for MS Word 97 1472 bytes as in MS Word 2000, and would it make any difference if it is not?
    * Did I interpret each C# command correctly?
      I think I did!
"""

from compoundfiles import CompoundFileReader, CompoundFileError
from struct import unpack

__all__ = ["doc2text"]

def doc2text (path):
    text = u""
    cr = CompoundFileReader(path)
    # Load WordDocument stream:
    try:
        f = cr.open("WordDocument")
        doc = f.read()
        f.close()
    except: cr.close(); raise CompoundFileError, "The file is corrupted or it is not a Word document at all."
    # Extract file information block and piece table stream informations from it:
    fib = doc[:1472]
    fcClx  = unpack("L", fib[0x01a2l:0x01a6l])[0]
    lcbClx = unpack("L", fib[0x01a6l:0x01a6+4l])[0]
    tableFlag = unpack("L", fib[0x000al:0x000al+4l])[0] & 0x0200l == 0x0200l
    tableName = ("0Table", "1Table")[tableFlag]
    # Load piece table stream:
    try:
        f = cr.open(tableName)
        table = f.read()
        f.close()
    except: cr.close(); raise CompoundFileError, "The file is corrupt. '%s' piece table stream is missing." % tableName
    cr.close()
    # Find piece table inside a table stream:
    clx = table[fcClx:fcClx+lcbClx]
    pos = 0
    pieceTable = ""
    lcbPieceTable = 0
    while True:
        if clx[pos]=="\x02":
            # This is piece table, we store it:
            lcbPieceTable = unpack("l", clx[pos+1:pos+5])[0]
            pieceTable = clx[pos+5:pos+5+lcbPieceTable]
            break
        Elif clx[pos]=="\x01":
            # This is beggining of some other substructure, we skip it:
            pos = pos+1+1+ord(clx[pos+1])
        else: break
    if not pieceTable: raise CompoundFileError, "The file is corrupt. Cannot locate a piece table."
    # Read info from pieceTable, about each piece and extract it from WordDocument stream:
    pieceCount = (lcbPieceTable-4)/12
    for x in xrange(pieceCount):
        cpStart = unpack("l", pieceTable[x*4:x*4+4])[0]
        cpEnd   = unpack("l", pieceTable[(x+1)*4:(x+1)*4+4])[0]
        ofsetDescriptor = ((pieceCount+1)*4)+(x*8)
        pieceDescriptor = pieceTable[ofsetDescriptor:ofsetDescriptor+8]
        fcValue = unpack("L", pieceDescriptor[2:6])[0]
        isANSII = (fcValue & 0x40000000) == 0x40000000
        fc      = fcValue & 0xbfffffff
        cb = cpEnd-cpStart
        enc = ("utf-16", "cp1252")[isANSII]
        cb = (cb*2, cb)[isANSII]
        text += doc[fc:fc+cb].decode(enc, "ignore")
    return "\n".join(text.splitlines())
2
Dalen

Juste une option pour lire les fichiers 'doc' sans utiliser COM: miette . Devrait fonctionner sur n'importe quelle plateforme.

1
alecxe