【问题标题】:Python: How to search all file types for a text stringPython:如何在所有文件类型中搜索文本字符串
【发布时间】:2011-07-11 16:17:47
【问题描述】:

我正在尝试编写一个程序,该程序能够在用户指定的目录中搜索所有文件(文件名及其内容)以查找特定字符串,然后将这些文件移动到新的用户指定的目录。

编辑:好的,所以我对我的代码进行了一些更改。它现在的工作方式是:使用 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)

【问题讨论】:

  • 这只能在 Windows 上运行吗?如果是这样,也许可以使用 os.system 使用 findstr 命令。
  • 与serk 的评论相反:在Unix 上,您可以使用grep -Rxargs 这样做
  • 具体的问题是?
  • @serk 和 phant0m:目前我只关心让它在 Windows 上运行,目前可移植性不是一个大问题。 @Blackmoon:问题是我目前无法在 .pdf、.jpg、.xls 和几乎所有其他“二进制”文件类型中搜索纯文本字符串。

标签: python search python-3.x win32com


【解决方案1】:

如果有人需要此代码,我可以让它正常工作。确保安装PyPDF2win32com.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 )

【讨论】:

  • 仅供参考,这是使用 Python2.7
【解决方案2】:

对于 Windows,请考虑:

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

这几乎可以满足您的所有需求。

【讨论】:

  • 奇怪的是,当我在命令提示符下使用 findstr 时,我没有得到任何类型的输出 - 它只是挂起,直到我输入 EOF 字符。
【解决方案3】:

您可以考虑使用 grin 库 (source)。它既可用作控制台脚本,也可用作您可以构建的库。支持检测二进制文件。

【讨论】:

    【解决方案4】:

    您必须先转换 pdf、xls 等,因为它们是光栅或矢量格式,因此没有可搜索的文本。有一些工具,例如 pdtotext,可以为您转换它们,然后您可以搜索输出。

    【讨论】:

    • 我希望避免这样做,因为它在开销方面似乎效率较低,但我想没有办法绕过它:P 我在我的代码中做了一些更改以反映需要转换某些文件,并使用 win32com 直接打开其他文件以查看其内容。
    猜你喜欢
    • 2011-12-12
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多