Python: как искать во всех типах файлов текстовую строку

Я пытаюсь написать программу, которая сможет искать все файлы (как имена файлов, так и их содержимое) в указанном пользователем каталоге для определенной строки, а затем перемещать эти файлы в новый указанный пользователем каталог.

РЕДАКТИРОВАТЬ: Итак, я внес несколько изменений в свой код. Теперь это работает следующим образом: список файлов получается с помощью os.path.walk(). Затем в каждом файле в списке ищется строка, указанная пользователем. Сначала для строки проверяются только имена файлов, а все положительные совпадения перемещаются в отдельный список. Затем мы начинаем смотреть внутрь файлов, используя расширение файла, чтобы определить, как открыть файл через win32com.client. Наконец, любые файлы, которые все еще находятся в исходном списке, считаются обычными текстовыми файлами и соответственно открываются и просматриваются.

Однако по какой-то причине программа перемещает только текстовые файлы. Если кто-то может понять, почему это так, это будет огромная помощь. :)

################
#Import required modules
import fileinput
from shutil import move
from os.path import abspath, join, splitext, split
from os import mkdir, walk, remove
import win32com.client

################
#Create lists to hold file names
file_list = list()
file_move_list = list()

#Define file extensions which need to be converted
excel_set = [".xls", ".xlsx", ".xlsm", ".xlsb"]
msword_set = [".doc", ".docx"]

################
#Define functions
def getFileList( searchdirectory ):
    #Get a list of all items in the directory to search
    for (dirpath, dirnames, filenames) in walk( searchdirectory ):
        for path in [ abspath( join( dirpath, filename ) ) for filename in filenames ]:
            file_list.append( path )

def searchFiles( readfilelist, movefilelist, searchstring ):
    #Get plain text from each file and search for searchstring
    for filename in readfilelist:
        ext = splitext( filename )[1]
        #Check filenames
        if searchstring in filename:
            movefilelist.append( filename )
            readfilelist.remove( filename )
        #Check if file is a pdf
        elif ext == ".pdf":
            content = getPDFContent( filename )
            if searchstring in content:
                movefilelist.append( filename )
        #Check if file is a word document
        elif ext in msword_set:
            app = win32com.client.Dispatch('Word.Application') 
            doc = app.Documents.Open( filename ) 
            if searchstring in doc.Content.Text:
                movefilelist.append( filename )
            app.Quit()
        #Check if file is an excel workbook/spreadsheet
        elif ext in excel_set:
            app = win32com.client.Dispatch( 'Excel.Application' )
            fileDir, fileName = split( filename )
            nameOnly = splitext( fileName )
            newName = nameOnly[0] + ".csv"
            outCSV = join( fileDir, newName )
            workbook = app.Workbooks.Open( filename )
            workbook.SaveAs(outCSV, FileFormat=24) # 24 is csv format
            workbook.Close(False)
            for line in open( outCSV, mode='r' ):
                if searchstring in line:
                    movefilelist.append( filename )
            app.Quit()
            remove( outCSV )
        #Assume all other files are plain text
        else:
            for line in open( filename, mode='r' ):
                if searchstring in line:
                    movefilelist.append( filename )
        readfilelist.remove( filename )

def moveFiles( movelist, destinationdirectory ):
    mkdir( destinationdirectory )
    for path in movelist:
        #Move the files to the destination folder
        move( path, destinationdirectory )
    print( 'Done' )

def getPDFContent( filename ):
    content = ""
    pdf = pyPdf.PdfFileReader( file( filename, "rb" ) )
    # Extract text from each page and add to content
    for i in range( 0, pdf.getNumPages() ):
        content += pdf.getPage(i).extractText() + " \n"
    return content

################
#Run as main
if __name__=='__main__':
    search_directory = input( 'Enter the path of the directory you wish to search through: ' )
    search_string = input( 'Enter the search term: ' )
    destination_directory = input( 'Enter the name of the new directory which will contain the moved files: ' )
    getFileList( search_directory )
    searchFiles( file_list, file_move_list, search_string )
    moveFiles( file_move_list, destination_directory )

Любая помощь, которую я могу получить, очень ценится. (К вашему сведению, я использую Python 3.2.1)


person Capitrium    schedule 11.07.2011    source источник
comment
Это будет работать только на Windows? Если это так, возможно, можно использовать команду findstr с использованием os.system.   -  person serk    schedule 11.07.2011
comment
В отличие от комментария серка: в Unix вы можете сделать это с помощью grep -R и xargs   -  person phant0m    schedule 11.07.2011
comment
А конкретная проблема?   -  person Andreas Jung    schedule 11.07.2011
comment
@serk и phant0m: На данный момент меня интересует только то, как заставить его работать в Windows, переносимость на данный момент не является большой проблемой. @Blackmoon: проблема в том, что в настоящее время я не могу искать в .pdf, .jpg, .xls и почти во всех других двоичных типах файлов строку простого текста.   -  person Capitrium    schedule 11.07.2011


Ответы (4)


Для окон учтите это:

os.system('findstr /C:"text to search for" *.*')

Это в значительной степени делает все, что вы хотите.

person serk    schedule 11.07.2011
comment
Как ни странно, я не получаю никакого вывода от findstr, когда использую его в командной строке — он просто зависает, пока я не ввожу символ EOF. - person Capitrium; 11.07.2011

Вы можете использовать библиотеку grin (источник). Его можно использовать как в качестве консольного скрипта, так и в качестве библиотеки, которую вы можете использовать. Есть поддержка обнаружения бинарных файлов.

person Vinay Sajip    schedule 11.07.2011

Вам придется сначала конвертировать pdf, xls и т. д., поскольку они в растровом или векторном форматах, поэтому нет текста для поиска. Существуют инструменты, такие как pdtotext, которые преобразуют их для вас, а затем вы можете искать результат.

person Joe    schedule 11.07.2011
comment
Я надеялся избежать этого, так как это кажется менее эффективным с точки зрения накладных расходов, но я думаю, что от этого никуда не деться: P Я внес некоторые изменения в свой код, чтобы отразить необходимость конвертировать определенные файлы и напрямую открывать другие с помощью win32com, чтобы увидеть их содержимое. - person Capitrium; 12.07.2011

Если кому-то нужен этот код, у меня он работает правильно. Убедитесь, что вы установили PyPDF2 и win32com.client

################
#Import required modules
import fileinput
from shutil import move
from os.path import abspath, join, splitext, split
from os import mkdir, walk, remove
import win32com.client
import PyPDF2 as pyPdf

################
#Create lists to hold file names
file_list = list()
file_move_list = list()

#Define file extensions which need to be converted
excel_set = [".xls", ".xlsx", ".xlsm", ".xlsb"]
msword_set = [".doc", ".docx"]

################
#Define functions
def getFileList( searchdirectory ):
    #Get a list of all items in the directory to search
    for (dirpath, dirnames, filenames) in walk( searchdirectory ):
        for path in [ abspath( join( dirpath, filename ) ) for filename in filenames ]:
            file_list.append( path )

def searchFiles( readfilelist, movefilelist, searchstring ):
    #Get plain text from each file and search for searchstring
    for filename in readfilelist:
        ext = splitext( filename )[1]
        #Check filenames
        if searchstring in filename:
            movefilelist.append( filename )
            readfilelist.remove( filename )
        #Check if file is a pdf
        elif ext == ".pdf":
            content = getPDFContent( filename )
            if searchstring in content:
                movefilelist.append( filename )
        #Check if file is a word document
        elif ext in msword_set:
            app = win32com.client.Dispatch('Word.Application') 
            doc = app.Documents.Open( filename ) 
            if searchstring in doc.Content.Text:
                movefilelist.append( filename )
            app.Quit()
        #Check if file is an excel workbook/spreadsheet
        elif ext in excel_set:
            app = win32com.client.Dispatch( 'Excel.Application' )
            fileDir, fileName = split( filename )
            nameOnly = splitext( fileName )
            newName = nameOnly[0] + ".csv"
            outCSV = join( fileDir, newName )
            workbook = app.Workbooks.Open( filename )
            workbook.SaveAs(outCSV, FileFormat=24) # 24 is csv format
            workbook.Close(False)
            for line in open( outCSV, mode='r' ):
                if searchstring in line:
                    movefilelist.append( filename )
            app.Quit()
            remove( outCSV )
        #Assume all other files are plain text
        elif ext == ".txt":
            txtFile = open(filename, mode='r')
            for line in txtFile:
                if searchstring in line:
                    movefilelist.append( filename )
            txtFile.close()
        else:
            print(filename + " is not reconized")
        #readfilelist.remove( filename )

def moveFiles( movelist, destinationdirectory ):
    mkdir( destinationdirectory )
    for path in movelist:
        #Move the files to the destination folder
        move( path, destinationdirectory )
    print( 'Done' )

def getPDFContent( filename ):
    content = ""
    fd = file(filename, 'rb')
    pdf = pyPdf.PdfFileReader( fd )
    # Extract text from each page and add to content
    for i in range( 0, pdf.getNumPages() ):
        content += pdf.getPage(i).extractText() + " \n"
    fd.close()
    return content

################
#Run as main
if __name__=='__main__':
    search_directory = input( 'Enter the path of the directory you wish to search through, in this format "C:\Users\admin\folder" : ' )
    search_string = input( 'Enter the search term in quotes: ' )
    destination_directory = input( 'Enter the name of the new directory which will contain the moved files, in this format"C:\Users\admin\folder" : ' )

    getFileList( search_directory )
    searchFiles( file_list, file_move_list, search_string )
    moveFiles( file_move_list, destination_directory )
person RandomDeduction    schedule 16.07.2014
comment
FYI Это использует Python2.7 - person RandomDeduction; 16.07.2014