我正在寻找使用 exiftool 从我的照片和视频中扫描 EXIF 标签。它是一个 perl 可执行文件。对此进行推断的最佳方法是什么?是否有任何 Python 库可以做到这一点?还是我应该直接调用可执行文件并解析输出?(后者似乎很脏。)谢谢。
我问的原因是因为我目前使用的是 pyexiv2,它不支持视频。Perl 的 exiftool 对图像和视频的支持非常广泛,我想使用它。
为避免为每个图像启动新进程,您应该开始exiftool
使用该-stay_open
标志。然后,您可以通过标准输入向进程发送命令,并在标准输出上读取输出。ExifTool 支持 JSON 输出,这可能是读取元数据的最佳选择。
这是一个简单的类,它启动一个exiftool
进程并提供一种execute()
向该进程发送命令的方法。我还包括get_metadata()
以 JSON 格式读取元数据:
import subprocess
import os
import json
class ExifTool(object):
sentinel = "{ready}\n"
def __init__(self, executable="/usr/bin/exiftool"):
self.executable = executable
def __enter__(self):
self.process = subprocess.Popen(
[self.executable, "-stay_open", "True", "-@", "-"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return self
def __exit__(self, exc_type, exc_value, traceback):
self.process.stdin.write("-stay_open\nFalse\n")
self.process.stdin.flush()
def execute(self, *args):
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)
return output[:-len(self.sentinel)]
def get_metadata(self, *filenames):
return json.loads(self.execute("-G", "-j", "-n", *filenames))
此类被编写为上下文管理器,以确保完成后退出进程。您可以将其用作
with ExifTool() as e:
metadata = e.get_metadata(*filenames)
为 python 3 编辑:要让它在 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 编辑:要使其在 Windows 上运行,sentinel
需要更改为"{ready}\r\n"
,即
sentinel = "{ready}\r\n"
否则程序将挂起,因为 execute() 中的 while 循环不会停止
以此为参考...
import subprocess
import os
import json
class ExifTool(object):
sentinel = "{ready}\n"
def __init__(self, executable="/usr/bin/exiftool"):
self.executable = executable
def __enter__(self):
self.process = subprocess.Popen(
[self.executable, "-stay_open", "True", "-@", "-"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return self
def __exit__(self, exc_type, exc_value, traceback):
self.process.stdin.write("-stay_open\nFalse\n")
self.process.stdin.flush()
def execute(self, *args):
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)
return output[:-len(self.sentinel)]
def get_metadata(self, *filenames):
return json.loads(self.execute("-G", "-j", "-n", *filenames))
... 使用 Python 3.8.10 和 IPYTHON 返回跟随错误;
" 56 57 e = ExifTool() ---> 58 e.load_metadata_lookup('/u02/RECOVERY/') 中的 AttributeError Traceback (最近一次调用最后一次)
在 load_metadata_lookup(self, locDir) 51 '\n FILELOC > ', FileLoc, '\n') 52 ---> 53 self.get_metadata(FileLoc) 54 55
在 get_metadata(self, FileLoc) 38 39 def get_metadata(self, FileLoc): ---> 40 return json.loads(self.execute("-G", "-j", "-n", FileLoc)) 41 42
在执行(自我,*args)28 def执行(自我,*args):29 args = args +(“-execute\n”,)---> 30 self.process.stdin.write(str.join(“ \n", args)) 31 self.process.stdin.flush() 32 输出 = ""
AttributeError:“ExifTool”对象没有属性“进程”
...
然后进行一些修改......成功!... 使用 [https://stackoverflow.com/users/279627/sven-marnach] 进行修改和改编
#!/usr/local/bin/python3
#! -*- coding: utf-8-mb4 -*-
from __future__ import absolute_import
import sys
import os
import subprocess
import json
headers_infos = """
.:.
.:. box33 | systems | platform |
.:. [ Renan Moura ]
.:. [ ver.: 9.1.2-b ]
.:.
"""
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/')
...注意此代码ll来自“/u02/RECOVERY/” ...目录查找并在找到的每个文档上执行...希望这可以帮助您...