如何通过批处理文件执行 Python 代码并传递参数 - 使用 argparse

Posted

技术标签:

【中文标题】如何通过批处理文件执行 Python 代码并传递参数 - 使用 argparse【英文标题】:How execute Python code and pass argument via Batch file -using argparse 【发布时间】:2021-07-06 04:08:24 【问题描述】:

我正在尝试通过批处理文件执行 Python 代码,而无需将参数硬编码到 Python 行中。相反,我想在批处理本身上指定任何其他参数。 但是当我运行 .bat 文件时,什么都没有发生。

我的过程:

使用 -argparse 在 Python 代码中创建了一个用于查找参数和凭据的函数。

创建了一个“应该”提供参数和凭据的批处理文件。

Python代码中的函数:image2json.py

import os
import imghdr
import json


version = "1.0.0.1"

downscale = 2048

bytelimit = 9000000
countlimit = 16

inputdir = None
outputdir = None
authjson = None


def get_args() -> dict:
    import argparse
    # Parse external arguments, and return as dictionary
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument(
        "-i", "--inputpath",
        required=True,
        help="The path to the input folder.")
    arg_parser.add_argument(
        "-o",
        "--outputpath",
        required=True,
        help="The path to the output folder.")
    arg_parser.add_argument(
        "-c",
        "--credentials",
        required=True,
        help="The path to the credentials JSON-file.")

    return vars(arg_parser.parse_args())
args = get_args()

inputdir = args['inputpath']
outputdir = args['outputpath']
authjson = args['credentials']


def load_image(file_path: str, flags=None):
    import imageio
    import cv2

    ext = file_path[-3:].lower()
    if ext != "gif":
        return cv2.imread(file_path, flags)
    else:
        gif = imageio.mimread(file_path)
        img = cv2.cvtColor(gif[0], cv2.COLOR_RGB2BGR)
        return img


def build_error_json(message: str):
    import json
    error_dict = dict()
    error_dict['error'] = message
    serialized = json.dumps(error_dict)
    return serialized

def batch_request(image_batch):
    from google.cloud import vision_v1
    from google.cloud.vision_v1 import enums
    from google.cloud.vision_v1 import types
    from google.protobuf.json_format import MessageToJson
    

    annotator_client = vision_v1.ImageAnnotatorClient.from_service_account_json(authjson)

    features = [
        types.Feature(type=enums.Feature.Type.TEXT_DETECTION)  #TEXT_DETECTION DOCUMENT_TEXT_DETECTION
    ]

    requests = []

    for name, image in image_batch.items():
        request = types.AnnotateImageRequest(image = image, features = features)
        requests.append(request)

    response = annotator_client.batch_annotate_images(requests)

    for name, annotation_response in zip(image_batch.keys(), response.responses):

        out_json = os.path.join(outputdir, name + ".json")

        if annotation_response.error.message:
            print("Annotation Error: " + name)
            serialized = build_error_json(response.error.message)
            with open(out_json, "w") as o:
                o.write(serialized)
            continue
            
        try:
            if (len(annotation_response.full_text_annotation.text) > 0):
                serialized = MessageToJson(annotation_response.full_text_annotation)
            else:
                serialized = build_error_json("Text not found.")
        except Exception as e:
            serialized = build_error_json(str(e))

        print("Annotation Done: " + name)

        with open(out_json, "w") as o:
            o.write(serialized)      


def get_credentials():
    try:
        auth = os.environ['GOOGLE_APPLICATION_CREDENTIALS']
    except:
        auth = None

    if (authjson is not None):
        print('The credentials taken from system environment')
        return auth

    dirname = os.path.dirname(os.path.realpath(__file__))

    jsons = list()

    (_, _, filenames) = next(os.walk(dirname))
    for file in filenames:
        if file.endswith(".json"):
             jsons.append(os.path.join(dirname, file))

    if (len(jsons) == 1):
        print('The credentials taken from local json: ' + os.path.basename(jsons[0]))
        return jsons[0]
    else:
        print('Credentials is not found. Please specify the credentials explicitly.')
        return None


def detect_text_batch(imagefiles):
    import io
    import numpy as np
    import tempfile
    import cv2
    from google.cloud.vision_v1 import types
    

    with tempfile.TemporaryDirectory() as tmpdirname:
        current_batch_size = 0
        current_batch_images = dict()
        for path in imagefiles:
            image_name = os.path.basename(path)
            try:
                m = load_image(path, cv2.IMREAD_ANYCOLOR)
            except Exception as e:
                print("File opening error: " + image_name)
                out_json = os.path.join(outputdir, image_name + ".json")
                serialized = build_error_json(str(e))
                continue
            h, w = m.shape[:2]
            maxside = max(w, h)
            scale = downscale / maxside
            if (scale < 1):
                m = cv2.resize(m, dsize=(0, 0), fx=scale, fy=scale)
            tmp_path = os.path.join(tmpdirname, image_name) + '.jpg'
            cv2.imwrite(tmp_path, m, [int(cv2.IMWRITE_JPEG_QUALITY), 90])
            if (os.path.exists(tmp_path)):
                with io.open(tmp_path, 'rb') as image_file:
                    content = image_file.read()
                    size = len(content)
                    if (current_batch_size + size >= bytelimit or len(current_batch_images) == countlimit):
                        batch_request(current_batch_images)
                        current_batch_images.clear()
                        current_batch_size = 0
                    
                    image = types.Image(content = content)
                    current_batch_size = current_batch_size + size
                    current_batch_images[image_name] = image
            else:
                #report error
                print("Tempfile saving error: " + image_name)
                out_json = os.path.join(outputdir, image_name + ".json")
                serialized = build_error_json('Tempfile saving error! ' + image_name)
                with open(out_json, "w") as o:
                    o.write(serialized)

        if (len(current_batch_images) > 0):
            batch_request(current_batch_images)

print('Version: ' + version)

args = get_args()

inputdir = args['inputpath']
outputdir = args['outputpath']
authjson = args['credentials']

if (authjson is None):
    print('Credentials is not specified, starting auto search...')
    authjson = get_credentials()

(_, _, filenames) = next(os.walk(inputdir))

imagefiles = list()

for filename in filenames:
    fullpath = os.path.join(inputdir, filename)
    if (imghdr.what(fullpath) is not None):
        imagefiles.append(fullpath)
    else:
        print("Not an image: " + filename)
        out_json = os.path.join(outputdir, filename + ".json")
        serialized = build_error_json("Not an image.")
        with open(out_json, "w") as o:
            o.write(serialized)

if (len(imagefiles) > 0):
    detect_text_batch(imagefiles)




批处理文件包含的内容:myStart.bat

python "image2json.py" -i "C:\Project\images" -o "C:\Project\json" -c "C:\Project\\VisionCredentials.json"

批处理文件显示运行没有错误,但 image2json.py 文件没有执行。

C:\WINDOWS\system32>python "C:\Project\image2json.py" -i ./images -o ./json -c VisionCredentials.json
Version: 1.0.0.1
Traceback (most recent call last):
  File "C:\Project\image2json.py", line 202, in <module>
    (_, _, filenames) = next(os.walk(inputdir))
StopIteration


目录截图:

Screenshot

我想问是否有人可以帮助我了解如何以最佳方式修复它。

目标是在运行“Start.bat”文件时执行“image2json.py”文件。 代码的概念是 OCR 结果。详解:使用 google vision API 将图像文件的文本提取为 JSON 文件。

这是我第一次提问所以请随时问我 添加/编辑任何缺失或让你觉得可能 帮助您理解主题。 提前致谢。

【问题讨论】:

那么您目前遇到的问题是什么?您需要告诉我们发生了什么/没有发生什么、错误代码等。%-i 中的% 的目的是什么? 好的,所以您需要做的一件事是将批处理文件重命名为其他名称。 startcmd 的内部命令。所以重命名为myStart.cmd 然后在batch-file 中使用以下行,看看会发生什么。 python "%~dp0image2json.py" -i ./images -o ./json -c VisionCredentials.json 您可以通过编辑在问题中发布您的错误吗? 我很确定这是权限错误,它会看到文件,但特别说打开它时出错。凭证 JSON 文件是否具有正确的凭证?你手动测试过这些文件吗? 是的,视觉 API 可以正常工作。凭据是正确的,我只是对其进行测试以确定。 prnt.sc/119nzpo 【参考方案1】:
set ARG1="-i ./images"
set ARG2="-o ./json"
set ARG3="-c VisionCredentials.json"
python C:\Project\image2json.py %ARG1% %ARG2% %ARG3%

试试这个。

【讨论】:

谢谢,重点是控制批处理文件中的参数。因此,即使 .py 文件的目录或位置发生变化,您也应该能够通过编辑批处理文件来处理它。

以上是关于如何通过批处理文件执行 Python 代码并传递参数 - 使用 argparse的主要内容,如果未能解决你的问题,请参考以下文章

Python函数:使用批处理文件将参数从.txt文件传递给python函数并执行函数

Python核心技术与实战——十三|Python中参数传递机制

java传参调用fortran的exe可执行文件

如何通过批处理文件检查服务是否正在运行并启动它,如果它没有运行?

通过批处理文件运行 abaqus python 脚本?

Python3.7函数