python -docx - l xml .etree.XMLSyntaxError: слишком длинная длина AttValue - PullRequest
0 голосов
/ 12 января 2020

Я пишу программу для проверки наличия слова в группе файлов .docx (мы говорим примерно о 2500 файлах .docx.

Вот сочная часть кода:

for filename in directorylist:
    if filename.endswith(".docx"):
        i = Document(filename)

        print(filename)


        for destination in destinationlist:
            for paragraph in i.paragraphs:
                if destination in paragraph.text:
                    destinationcount[destination] = 1
                    break
                else:
                    destinationcount[destination] = 0
                    continue

        for destination in destinationcount:
            destinationcountnobool[destination] += destinationcount[destination]

    else:
        continue

Теперь я знаю, о чем вы думаете, это ужасный беспорядок циклов и дерьмового программирования в целом, но это быстрая и грязная работа, так что избавьте меня.

Вот ошибка, которую я получаю:

Traceback (most recent call last):
  File "ICrunchMeSomeFiles.py", line 27, in <module>
    i = Document(filename)
  File "C:\Users\User\Anaconda3\lib\site-packages\docx\api.py", line 25, in Document
    document_part = Package.open(docx).main_document_part
  File "C:\Users\User\Anaconda3\lib\site-packages\docx\opc\package.py", line 130, in open
    Unmarshaller.unmarshal(pkg_reader, package, PartFactory)
  File "C:\Users\User\Anaconda3\lib\site-packages\docx\opc\package.py", line 199, in unmarshal
    pkg_reader, package, part_factory
  File "C:\Users\User\Anaconda3\lib\site-packages\docx\opc\package.py", line 216, in _unmarshal_parts
    partname, content_type, reltype, blob, package
  File "C:\Users\User\Anaconda3\lib\site-packages\docx\opc\part.py", line 191, in __new__
    return PartClass.load(partname, content_type, blob, package)
  File "C:\Users\User\Anaconda3\lib\site-packages\docx\opc\part.py", line 231, in load
    element = parse_xml(blob)
  File "C:\Users\User\Anaconda3\lib\site-packages\docx\oxml\__init__.py", line 28, in parse_xml
    root_element = etree.fromstring(xml, oxml_parser)
  File "src\lxml\etree.pyx", line 3236, in lxml.etree.fromstring
  File "src\lxml\parser.pxi", line 1876, in lxml.etree._parseMemoryDocument
  File "src\lxml\parser.pxi", line 1764, in lxml.etree._parseDoc
  File "src\lxml\parser.pxi", line 1127, in lxml.etree._BaseParser._parseDoc
  File "src\lxml\parser.pxi", line 601, in lxml.etree._ParserContext._handleParseResultDoc
  File "src\lxml\parser.pxi", line 711, in lxml.etree._handleParseResult
  File "src\lxml\parser.pxi", line 640, in lxml.etree._raiseParseError
  File "<string>", line 2
lxml.etree.XMLSyntaxError: AttValue length too long, line 2, column 11011745

Программа отлично работает для небольших выборок, поэтому я предполагаю, что это проблема с памятью. Помощь будет очень признателен

РЕДАКТИРОВАТЬ: Должен был сделать это раньше, но обновил сообщение со всем фрагментом кода, который вызывает ошибку.

import csv
from docx import Document
from collections import Counter
import os

directorylist = os.listdir(os.getcwd()) # Set directory here
destinationcount = Counter()
destinationcountnobool = Counter()
destinationlist = ["test1", "test2", "test3", "test4", "test5"]
print(directorylist)

for filename in directorylist:
    if filename.endswith(".docx"):
        i = Document(filename)    


        for destination in destinationlist:
            for paragraph in i.paragraphs:
                if destination in paragraph.text:
                    destinationcount[destination] = 1
                    break
                else:
                    destinationcount[destination] = 0
                    continue

        for destination in destinationcount:
            destinationcountnobool[destination] += destinationcount[destination]

    else:
        continue


for d in destinationcountnobool:
    print(d + " : " + str(destinationcountnobool[d]))

ОБНОВЛЕНИЕ: Я уже некоторое время изучаю эту проблему ... Кажется, что python может обработать только 118 файлов перед тем, как столкнуться с этой же ошибкой.

ОБНОВЛЕНИЕ: Решено! Вроде ... Думаю. Я отправил свой ответ

Ответы [ 2 ]

0 голосов
/ 13 января 2020

Хорошо, после небольшого отчисления. Я наконец понял, что случилось. Кажется, это была проблема с памятью.

Я кратко высказал предположение, что файл .docx имел какой-то непостижимый символ, который привел к тому, что программа взломала sh. Но при ближайшем рассмотрении я пришел к выводу, что это маловероятно, поскольку файлы очень похожи.

Следующим шагом было дублирование этого проекта и уменьшение размера выборки до тех сумм, которые были обработаны до того, как он потерпел неудачу. , Число было 118.

Я пытался добавить и вычесть файл, и у меня всегда было жесткое ограничение в 118. 119-й файл всегда приводил к взлому sh. Исправление было довольно простым.

for filename in directorylist:
    if filename.endswith(".docx"):
        i = Document(filename)    


        for destination in destinationlist:
            for paragraph in i.paragraphs:
                if destination in paragraph.text:
                    destinationcount[destination] = 1
                    break
                else:
                    destinationcount[destination] = 0
                    continue
        del i

        for destination in destinationcount:
            destinationcountnobool[destination] += destinationcount[destination]

Мне просто нужно было удалить объект, чтобы освободить память. Кроме того, with не работает с python -docx, кажется.

Фу ... Вот и все.

РЕДАКТИРОВАТЬ: Все еще любопытно, почему он обрабатывался нормально до 119-го файла , Был бы рад, если бы кто-то мог просветить меня.

0 голосов
/ 13 января 2020

Я думаю, что может решить вашу проблему:

import os
from collections import defaultdict

directorylist = os.listdir('.')


destinationlist = []
destinationcount = defaultdict(int)


def return_each_paragraph_from_file(directory):
    for filename in directory:
        if filename.endswith(".docx"):
            i = Document(filename)
            for paragraph in i.paragraphs:
                yield paragraph


if __name__ == "main":
    for p in return_each_paragraph_from_file(directorylist):
        for destination in destinationlist:
            destinationcount[destination] += 1 if destination in p.text else destinationcount[destination]

...