从Python脚本中调用exiftool?
问题的原因是作者想要在Python脚本中调用exiftool来处理一批文件,并提取特定的元数据字段。作者发现直接使用subprocess模块逐个调用exiftool处理每个文件的速度非常慢,因此想要寻找一种更快的方法。
为了解决这个问题,作者编写了一个名为meta_for_batch的函数。这个函数接受两个参数:fieldlist和filelist。其中,fieldlist是要提取的元数据字段列表,filelist是要处理的文件列表。
函数的实现思路是构建一个批处理命令,将exiftool作为子进程运行。命令的格式为['exiftool', '-j'] + fieldlist + filelist。然后使用subprocess模块的run函数运行这个命令,并捕获输出结果。
如果命令的返回码不为0,说明命令执行出错,此时函数会抛出一个ValueError异常,并将错误信息作为异常的错误数据。函数使用json.loads函数将命令的输出结果解析为JSON格式的数据,并将其返回。
作者还提到,可能在Windows系统下会因为文件列表过长而出现问题,此时可以使用argfile来解决。而在Linux系统下,作者曾经尝试过处理600个文件,耗时为11.5秒。
最后,作者给出了一个使用示例。通过调用meta_for_batch函数,并传入特定的fieldlist和filelist,可以提取指定文件的特定元数据字段。
如果想要获取字段名称,可以使用exiftool的-args参数。
通过这种方法,作者成功地在Python脚本中调用exiftool处理一批文件,并提取指定的元数据字段,大大提高了处理速度。
以下是整理后的文章:
在Python脚本中调用exiftool处理一批文件,提取特定的元数据字段,是一个常见的需求。然而,直接使用subprocess模块逐个调用exiftool处理每个文件的效率非常低下。那么,有没有一种更快的方法呢?
答案是肯定的。下面我们介绍一种效率更高的方法,可以让你的程序运行得更快。
首先,我们需要编写一个名为meta_for_batch的函数,用于处理一批文件并提取元数据字段。这个函数接受两个参数:fieldlist和filelist。其中,fieldlist是要提取的元数据字段列表,filelist是要处理的文件列表。
函数的实现思路是构建一个批处理命令,将exiftool作为子进程运行。命令的格式为['exiftool', '-j'] + fieldlist + filelist。然后使用subprocess模块的run函数运行这个命令,并捕获输出结果。
如果命令的返回码不为0,说明命令执行出错,此时函数会抛出一个ValueError异常,并将错误信息作为异常的错误数据。函数使用json.loads函数将命令的输出结果解析为JSON格式的数据,并将其返回。
需要注意的是,在Windows系统下可能会因为文件列表过长而出现问题,此时可以使用argfile来解决。而在Linux系统下,我们曾经尝试过处理600个文件,耗时为11.5秒,效果非常好。
下面是一个使用示例,展示了如何调用meta_for_batch函数来提取指定文件的特定元数据字段:
reclist = meta_for_batch( ['-FocalLength', '-ImageHeight', '-ISO', '-Model', '-CameraTemperature', '-SerialNumber', '-ExposureTime', '-LensSerialNumber', '-ImageWidth', '-LensModel', '-SubSecCreateDate'], ['_23A1000.CR3', '_23A1002.CR3', '_23A1003.CR3'] )
如果你想要获取字段名称,可以使用exiftool的-args参数。
通过这种方法,我们成功地在Python脚本中调用exiftool处理一批文件,并提取指定的元数据字段,大大提高了处理速度。
希望这篇文章对你有所帮助!
从上述内容中,我们可以得出这个问题的出现原因是为了避免为每个图像启动一个新的进程,应该使用-exiftool标志来启动exiftool,然后通过stdin发送命令到进程,并在stdout上读取输出。exiftool支持JSON输出,这可能是读取元数据的最佳选择。
解决方法是创建一个名为ExifTool的类,该类启动一个exiftool进程,并具有一个execute()方法来发送命令到该进程。还包括一个get_metadata()方法来以JSON格式读取元数据。
这个类被编写为一个上下文管理器,以确保在完成后退出进程。可以像下面这样使用它:
with ExifTool() as e: metadata = e.get_metadata(*filenames)
对于Python 3,需要进行两个小的更改。第一个是在subprocess.Popen中增加一个额外的参数:
self.process = subprocess.Popen( [self.executable, "-stay_open", "True", "-@", "-"], universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
第二个是必须解码由os.read()返回的字节序列:
output += os.read(fd, 4096).decode('utf-8')
对于Windows系统,需要将sentinel更改为"{ready}\r\n":
sentinel = "{ready}\r\n"
以上就是关于如何从Python脚本中调用exiftool的内容整理。通过使用-exiftool标志启动exiftool进程,并通过stdin发送命令和读取stdout输出,可以避免为每个图像启动新的进程。同时,ExifTool支持JSON输出,可以方便地读取元数据。通过创建一个名为ExifTool的类,可以更方便地调用exiftool,并确保进程在完成后正常退出。
文章标题:从Python脚本调用exiftool的问题及解决方法
在使用Python脚本调用exiftool时,出现了一个AttributeError的错误。具体错误信息如下:
AttributeError: 'ExifTool' object has no attribute 'process'
错误出现在以下代码段中:
self.process.stdin.write(str.join("\n", args))
通过对代码进行修改和适应,问题得到了解决。修改后的代码如下:
#!/usr/local/bin/python3 #! -*- coding: utf-8-mb4 -*- from __future__ import absolute_import import sys import os import subprocess import json class ExifTool(object): sentinel = "{ready}\n" def __init__(self): self.executable = "/usr/bin/exiftool" self.metadata_lookup = {} def __exit__(self, exc_type, exc_value, traceback): self.process.stdin.write("-stay_open\nFalse\n") self.process.stdin.flush() def execute(self, *args): self.process = subprocess.Popen([self.executable, "-stay_open", "True", "-@", "-"], universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) args = (args + ("-execute\n",)) self.process.stdin.write(str.join("\n", args)) self.process.stdin.flush() output = "" fd = self.process.stdout.fileno() while not output.endswith(self.sentinel): output += os.read(fd, 4096).decode('utf-8') return output[:-len(self.sentinel)] def get_metadata(self, *FileLoc): return json.loads(self.execute("-G", "-j", "-n", *FileLoc)) def load_metadata_lookup(self, locDir): self.metadata_lookup = {} for dirname, dirnames, filenames in os.walk(locDir): for filename in filenames: FileLoc = (dirname + '/' + filename) print('\n FILENAME > ', filename, '\n DIRNAMES > ', dirnames, '\n DIRNAME > ', dirname, '\n FILELOC > ', FileLoc, '\n') self.metadata_lookup = self.get_metadata(FileLoc) print(json.dumps(self.metadata_lookup, indent=3)) e = ExifTool() e.load_metadata_lookup('/u02/RECOVERY/')
修改后的代码解决了原先出现的AttributeError错误,成功调用了exiftool并获取了元数据。
这段代码将从指定的目录`/u02/RECOVERY/`中查找每个文档,并执行相应的操作。希望这能对您有所帮助。