2008-09-24 14 views

Répondre

18

Vous pouvez effectuer un appel de sous-processus à antiword. Antiword est un utilitaire de ligne de commande linux pour le déchargement de texte d'un document Word. Fonctionne plutôt bien pour les documents simples (évidemment, il perd la mise en forme). Il est disponible via apt, et probablement en tant que RPM, ou vous pouvez le compiler vous-même.

+0

antiword peut convertir des documents Word en DocBook XML, ce qui préservera (au moins certains) formatage. –

+0

'catdoc' fonctionne également si antiword n'est pas disponible. – Xiflado

4

Jetez un oeil à how the doc format works et create word document using PHP in linux. Le premier est particulièrement utile. Abiword est mon outil recommandé. Il y a limitations cependant:

However, if the document has complicated tables, text boxes, embedded spreadsheets, and so forth, then it might not work as expected. Developing good MS Word filters is a very difficult process, so please bear with us as we work on getting Word documents to open correctly. If you have a Word document which fails to load, please open a Bug and include the document so we can improve the importer.

+0

Non seulement cela bien! Même le texte le plus élémentaire enregistré dans le format Word 97 est presque impossible à obtenir facilement sans compter sur le mot pour le faire pour vous (COM). La plupart des documents Word ne sont pas en HTML! –

+0

Abiword ne suppose pas qu'il s'agit d'un document HTML, et compte tenu de l'étendue de l'outil ... Je ne pense pas qu'il était "facile" de l'implémenter. Abiword est un outil qui vous aide à lire des fichiers MS Word ... et puisque l'auteur est concerné par la récupération de texte, cela suffit. – Swati

+0

Ah, j'ai toujours pensé que abiword était juste un autre traitement de texte! Mec, ça m'aurait sauvé quelques maux de tête en arrière. –

3

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 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! OpenOffice.org peut être scripté avec Python: see here

10

Depuis OOo peut charger la plupart des fichiers MS Word parfaitement, je dirais que c'est votre meilleur pari.

+10

Pas parfaitement. Proche, mais loin d'être parfait dans mon expérience (OO 2.0 - 3.0). – SpliFF

+4

Aussi impeccable que MS Word N + 1 ouvre MS Word N fichiers, et bien mieux que MS Word N + 1 ouvre MS Word N-1 fichiers, IMHO – voyager

5

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

http://wvware.sourceforge.net/

Après l'installation de la bibliothèque, l'utiliser en Python est assez facile:

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 un couple de scripts shell, à savoir wvText (qui extrait le texte d'un document Word, et chat pour lire la sortie du fichier). Après cela, le texte entier du document Word sera dans la variable out, prêt à l'emploi.

Espérons que cela aidera toute personne ayant des problèmes similaires à l'avenir.

4

(Note: Je posté sur this question aussi, mais il semble pertinent en l'espèce, donc s'il vous plaît excuser le reposter.)

Maintenant, cela est assez laid et assez hacky, mais il semble fonctionner pour moi extraction de texte de base. Il est évident que pour l'utiliser dans un programme Qt vous auriez à lancer un processus pour elle, etc., mais la ligne de commande que j'ai piraté ensemble est:

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

Voilà:

décompressez fichier -p .docx: -p == "décompressez stdout"

grep '< w: t': Grab seulement les lignes contenant '< w: t' (< w: t > est l'élément XML pour Word 2007 "texte", pour autant que je peux dire)

sed 's/< [^ <]> // g' *: Retirer tout les balises contenues dans

grep -v^[[: space:]] $ '*: Supprimer les lignes vides

Il y a probablement un moyen plus efficace de le faire, mais cela semble fonctionner pour moi sur les quelques docs avec lesquels je l'ai testé. Pour autant que je sache, unzip, grep et sed ont tous des ports pour Windows et tous les Unix, donc il devrait être raisonnablement multiplateforme. Despit étant un peu un hack laid;)

4

Si vous avez l'intention d'utiliser des modules purement python sans appeler un sous-processus, vous pouvez utiliser le module python zipfile.

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é, une façon de le faire 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 y a sûrement une façon plus élégante pour nettoyer la chaîne, en utilisant probablement le module re . J'espère que cela aide.

+1

Pour supprimer des entités XML comme   de 'texte': >>> de xml.sax.saxutils importer unescape >>> text = unescape (contenu) – aitchnyu

+0

en utilisant le module de re, le nettoyage peut être beaucoup plus facile: 'stripped_content = re.compile (b '<.*?>').sub (b '', content ) # strip tags' Une chose que je ne pouvais pas comprendre dans votre code est, dans l'extrait précédent, pourquoi ne pas vous "casser" dans le bloc "if"? –

11

La réponse de benjamin 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') 
cleaned = re.sub('<(.|\n)*?>','',content) 
print cleaned 
+0

Je dois réitérer cela ne fonctionne que pour docx (Word 2007 ou version ultérieure). Pour les fichiers .doc wvware est votre meilleur pari. En fonction de votre environnement, cela peut être difficile à configurer, mais cela fait du très bon travail. – Chad

+3

Pour supprimer des entités XML telles que   de 'text': >>> depuis xml.sax.saxutils import unescape >>> text = unescape (nettoyé) – aitchnyu

+0

content = docx.read ('word/document.xml'). decode ('utf-8') sinon vous obtiendrez une erreur lors du nettoyage: TypeError: impossible d'utiliser un modèle de chaîne sur un objet semblable à un octet –

29

Utilisez le module docx Python natif . Voilà 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 Python DocX site

Consultez également Textract qui sort des tables etc.

XML avec regexs Parsing cthulu invoque. Ne fais pas ça!

+0

faites-vous 'de docx import *' ici? Si non, comment obtenez-vous 'getdocumenttext', etc.? – dbliss

+1

'opendocx' n'est pas dans le module (c'était peut-être en 2009). Les documents sont ouverts via la classe Document, par ex. 'Importer docx; document = docx.Document ('Bonjour world.docx') '. – egpbos

+0

@egpbos J'ai mis à jour l'exemple de code pour utiliser la nouvelle génération python-docx. – mikemaccana

1

Juste une option pour la lecture de fichiers 'doc' sans utiliser COM: miette. Devrait travailler sur n'importe quelle plate-forme.

1

Si vous avez installé LibreOffice, you can simply call it from the command line to convert the file to text, chargez le texte dans Python.

+1

Ah Philip! Je cherchais simplement un moyen de rejeter les modifications triviales de style que vous avez faites à un autre poste de la mienne. J'ai essayé de vous contacter directement. Pourriez-vous dire plus clairement ce que vous suggérez ici? Cette réponse que j'ai donnée ici est en réponse à la question. Est-ce pas assez bon? – markling

+1

Re. vos retouches de style et de grammaire: je préférais mon propre style et ma grammaire, merci. Un bon éditeur n'impose pas son propre style. Et vraiment, aucun d'entre nous n'a assez de temps pour faire des vérifications de sortilège et de grammaire triviales, n'est-ce pas? Je pense que vous trouverez peut-être que c'est un peu excessif. – markling

1

Est-ce une vieille question? Je crois qu'une telle chose n'existe pas. Il y a seulement des réponses et des réponses sans réponse. 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 COM interop sont toutes couvertes. Mais les méthodes d'extraction de texte à partir de * .doc (MS Word 97-2000), en utilisant uniquement Python, manquent. Est-ce compliqué? A faire: pas vraiment, à comprendre: eh bien, c'est autre chose.Lorsque je n'ai pas trouvé de code fini, j'ai lu quelques spécifications de format et j'ai trouvé quelques algorithmes proposés dans d'autres langages.

Le fichier MS Word (* .doc) est un fichier composé OLE2. Pour ne pas vous déranger avec beaucoup de détails inutiles, considérez-le comme un système de fichiers stocké dans un fichier. Il utilise réellement la structure FAT, donc la définition est valide. (Hm, peut-être vous pouvez 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 est faite dans * .docx en utilisant l'archive ZIP à la place. Il existe des paquets disponibles sur PyPI qui peuvent lire les fichiers OLE. Like (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 des fichiers 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 extraire les informations stockées en conséquence. Pour bien comprendre, lisez le document PDF à partir duquel j'ai pris l'algorithme.

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

Ceux d'entre vous qui souhaitent simplement rechercher du texte seront heureux. Néanmoins, j'invite quiconque à aider à améliorer ce code pour 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

Pour lire Word 2007 et les fichiers plus tard, 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 de Word 2003 et plus tôt, faire un appel subprocess à antiword. Vous devez installer antiword premier:

sudo apt-get install antiword 

Ensuite, il suffit d'appeler à partir de 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)) 
Questions connexes