2012-02-21 38 views
10

Napisałem skrypt w Pythonie używając pywin32 do zapisywania plików pdf do tekstu, który do niedawna działał poprawnie. Używam podobnych metod w Excelu. Kod jest poniżej:"Nie zaimplementowane" Wyjątek podczas używania pywin32 do kontrolowania Adobe Acrobat

def __pdf2Txt(self, pdf, fileformat="com.adobe.acrobat.accesstext"): 
    outputLoc = os.path.dirname(pdf) 
    outputLoc = os.path.join(outputLoc, os.path.splitext(os.path.basename(pdf))[0] + '.txt') 

    try: 
     win32com.client.gencache.EnsureModule('{E64169B3-3592-47d2-816E-602C5C13F328}', 0, 1, 1) 
     adobe = win32com.client.DispatchEx('AcroExch.App') 
     pdDoc = win32com.client.DispatchEx('AcroExch.PDDoc') 
     pdDoc.Open(pdf) 
     jObject = pdDoc.GetJSObject() 
     jObject.SaveAs(outputLoc, "com.adobe.acrobat.accesstext") 
    except: 
     traceback.print_exc() 
     return False 
    finally: 
     del jObject 
     pdDoc.Close() 
     del pdDoc 
     adobe.Exit() 
     del adobe 

Jednak ten kod nagle przestał działać i pojawia się następujący komunikat:

Traceback (most recent call last): 
    File "C:\Documents and Settings\ablishen\workspace\HooverKeyCreator\src\HooverKeyCreator.py", line 38, in __pdf2Txt 
    jObject.SaveAs(outputLoc, "com.adobe.acrobat.accesstext") 
    File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 505, in __getattr__ 
    ret = self._oleobj_.Invoke(retEntry.dispid,0,invoke_type,1) 
com_error: (-2147467263, 'Not implemented', None, None) 
False 

Mam podobny kod napisany w VB, który działa poprawnie więc zgaduję, że to ma coś wspólnego z interfejsami COM niewiążącymi się z odpowiednimi funkcjami? (moja wiedza na temat COM jest niejednolita).

+2

Czy to PDF mają uratować prawa użytkowania? (Dziwne przypuszczenie na podstawie tego z dokumentów: "Ta metoda jest dostępna w Adobe Reader dla dokumentów, które mają prawa do zapisu.) –

+1

Wygląda na to, że nie mam, ale włączam je i nadal otrzymuję ten sam błąd. Plus używam programu Adobe Acrobat Aby uruchomić kod: – Blish

Odpowiedz

3

Blish, this thread posiada klucz do rozwiązania szukasz: https://mail.python.org/pipermail/python-win32/2002-March/000260.html

muszę przyznać, że po wyżej nie jest najłatwiejsze do znalezienia (prawdopodobnie ponieważ Google ocenia go na niskim poziomie w zależności od wieku treści?).

Konkretnie, stosując this piece rada będzie dostać rzeczy działa dla Ciebie: https://mail.python.org/pipermail/python-win32/2002-March/000265.html

Dla porównania, cały kawałek kodu, który nie wymaga ręcznego załatać dynamic.py (fragment powinien działać dość dużo się z box):

# gets all files under ROOT_INPUT_PATH with FILE_EXTENSION and tries to extract text from them into ROOT_OUTPUT_PATH with same filename as the input file but with INPUT_FILE_EXTENSION replaced by OUTPUT_FILE_EXTENSION 
from win32com.client import Dispatch 
from win32com.client.dynamic import ERRORS_BAD_CONTEXT 

import winerror 

# try importing scandir and if found, use it as it's a few magnitudes of an order faster than stock os.walk 
try: 
    from scandir import walk 
except ImportError: 
    from os import walk 

import fnmatch 

import sys 
import os 

ROOT_INPUT_PATH = None 
ROOT_OUTPUT_PATH = None 
INPUT_FILE_EXTENSION = "*.pdf" 
OUTPUT_FILE_EXTENSION = ".txt" 

def acrobat_extract_text(f_path, f_path_out, f_basename, f_ext): 
    avDoc = Dispatch("AcroExch.AVDoc") # Connect to Adobe Acrobat 

    # Open the input file (as a pdf) 
    ret = avDoc.Open(f_path, f_path) 
    assert(ret) # FIXME: Documentation says "-1 if the file was opened successfully, 0 otherwise", but this is a bool in practise? 

    pdDoc = avDoc.GetPDDoc() 

    dst = os.path.join(f_path_out, ''.join((f_basename, f_ext))) 

    # Adobe documentation says "For that reason, you must rely on the documentation to know what functionality is available through the JSObject interface. For details, see the JavaScript for Acrobat API Reference" 
    jsObject = pdDoc.GetJSObject() 

    # Here you can save as many other types by using, for instance: "com.adobe.acrobat.xml" 
    jsObject.SaveAs(dst, "com.adobe.acrobat.accesstext") 

    pdDoc.Close() 
    avDoc.Close(True) # We want this to close Acrobat, as otherwise Acrobat is going to refuse processing any further files after a certain threshold of open files are reached (for example 50 PDFs) 
    del pdDoc 

if __name__ == "__main__": 
    assert(5 == len(sys.argv)), sys.argv # <script name>, <script_file_input_path>, <script_file_input_extension>, <script_file_output_path>, <script_file_output_extension> 

    #$ python get.txt.from.multiple.pdf.py 'C:\input' '*.pdf' 'C:\output' '.txt' 

    ROOT_INPUT_PATH = sys.argv[1] 
    INPUT_FILE_EXTENSION = sys.argv[2] 
    ROOT_OUTPUT_PATH = sys.argv[3] 
    OUTPUT_FILE_EXTENSION = sys.argv[4] 

    # tuples are of schema (path_to_file, filename) 
    matching_files = ((os.path.join(_root, filename), os.path.splitext(filename)[0]) for _root, _dirs, _files in walk(ROOT_INPUT_PATH) for filename in fnmatch.filter(_files, INPUT_FILE_EXTENSION)) 

    # patch ERRORS_BAD_CONTEXT as per https://mail.python.org/pipermail/python-win32/2002-March/000265.html 
    global ERRORS_BAD_CONTEXT 
    ERRORS_BAD_CONTEXT.append(winerror.E_NOTIMPL) 

    for filename_with_path, filename_without_extension in matching_files: 
     print "Processing '{}'".format(filename_without_extension) 
     acrobat_extract_text(filename_with_path, ROOT_OUTPUT_PATH, filename_without_extension, OUTPUT_FILE_EXTENSION) 

ja testowałem to na WinPython x64 2.7.6.3, Acrobat X Pro

+1

Dodawanie pliku winerror.E_NOTIMPL do listy ERRORS_BAD_CONTEXT w pliku dynamic.py zadziałało Bardzo dziękuję – Blish

+1

Witam, używam Pythona i Acrobat Reader Pro dla tej samej funkcji, a obecnie ten kod, a nawet po robienie tego, co zrobił poprzedni komentator, powoduje następujący błąd: "NotAllowedError: Ustawienia zabezpieczeń uniemożliwiają dostęp do tej właściwości lub metody." Czy wiesz, co jest przyczyną? Dziękuję – dasen

+2

Nie mogę Ci powiedzieć wystarczająco dużo dla 'ERRORS_BAD_CONTEXT.append (winerror.E_NOTIMPL). – Fenikso

1

makepy.py to skrypt dostarczany z pakietem python win32com.

Uruchamiam go do instalacji "pytka" do obiektu COM/OLE w systemie Windows. Poniżej znajduje się fragment kodu, z którym rozmawiałem z programem Excel i robiłem w nim pewne rzeczy. Ten przykład zawiera nazwę arkusza 1 w bieżącym skoroszycie. To automatycznie uruchamia makepy jeśli ma wyjątek:

import win32com; 
import win32com.client; 
from win32com.client import selecttlb; 

def attachExcelCOM(): 
    makepyExe = r'python C:\Python25\Lib\site-packages\win32com\client\makepy.py'; 
    typeList = selecttlb.EnumTlbs(); 
    for tl in typeList: 
     if (re.match('^Microsoft.*Excel.*', tl.desc, re.IGNORECASE)): 
      makepyCmd = "%s -d \"%s\"" % (makepyExe, tl.desc); 
      os.system(makepyCmd); 
     # end if 
    # end for 
# end def 

def getSheetName(sheetNum): 
    try: 
     xl = win32com.client.Dispatch("Excel.Application"); 
     wb = xl.Workbooks.Item(sheetNum); 
    except Exception, detail: 
     print 'There was a problem attaching to Excel, refreshing connect config...'; 
     print Exception, str(detail); 
     attachExcelCOM(); 
     try: 
     xl = win32com.client.Dispatch("Excel.Application"); 
     wb = xl.Workbooks.Item(sheetNum); 
     except: 
     print 'Could not attach to Excel...'; 
     sys.exit(-1); 
     # end try/except 
    # end try/except 

    wsName = wb.Name; 
    if (wsName == 'PERSONAL.XLS'): 
     return(None); 
    # end if 
    print 'The target worksheet is:'; 
    print '  ', wsName; 
    print 'Is this correct? [Y/N]',; 
    answer = string.strip(sys.stdin.readline()); 
    answer = answer.upper(); 
    if (answer != 'Y'): 
     print 'Sheet not identified correctly.'; 
     return(None); 
    # end if 
    return((wb, wsName)); 
# end def 

# -- Main -- 
sheetInfo = getSheetName(sheetNum); 
if (sheetInfo == None): 
    print 'Sheet not found'; 
    sys.exit(-1); 
else: 
    (wb, wsName) = sheetInfo; 
# end if 
Powiązane problemy