使用来自 mediainfo AWS Lambda 的请求发送 json 时出现属性错误

Attribute error when sending json with Requests from mediainfo AWS Lambda

我正在尝试将视频元数据从 s3 存储桶发送到 MongoDB Atlas,媒体信息作为 Python 3.7 中的 AWS Lambda。当我对数据进行硬编码时它可以工作,但我收到对象键错误或属性错误。我尝试导入 json 并使用 json.loads() 和 json.dumps() 并收到错误。这是代码,

import boto3
from botocore.client import Config
from botocore.exceptions import ClientError
import json
import xmltodict
import subprocess
import os
import uuid
import requests
import json

# Generate a presigned URL for S3 Object
def get_presigned_url(expiration, objBucket, objKey):
    s3 = boto3.client('s3', 'us-east-1', config=Config(s3={'addressing_style': 'virtual'}))
    Params={
        'Bucket': objBucket,
        'Key': objKey
    }
    print ('CORE:: Media Evaluator:: Bucket Name: ' + objBucket)
    print ('CORE:: Media Evaluator:: Object Key: ' + objKey)
    try:
        response = s3.generate_presigned_url('get_object', Params, ExpiresIn=expiration)
        print('this is the response !!!!!!!!!', response)
    except ClientError as e:
        print (e)
        raise
        return None
    return response

# Get MD5 from S3 Object Tag
def get_md5_from_objectTag(objBucket, objKey):
    s3 = boto3.client('s3', 'us-east-1', config=Config(s3={'addressing_style': 'virtual'}))
    response = s3.get_object_tagging(
        Bucket=objBucket,
        Key=objKey
    )
    for tag in response['TagSet']:
        if tag['Key'] == 'MD5':
            md5 = tag['Value']
    return md5

# Evaluate the media using MediaInfo
def get_mediainfo(presignedURL):
    print("presignedURL !!!!!!!!!!!!!", presignedURL)
    try:
        output = subprocess.check_output(['./mediainfo', '--full', '--output=JSON', presignedURL], shell=False, stderr=subprocess.STDOUT)
        #  subprocess.check_output(["./mediainfo", "--full", "--output=JSON", presignedURL], stdin=None, stderr=subprocess.STDOUT, shell=True)    
        print("this si the output !!!!!!!!!!!!!!!!!", output) 
        json_output = json.loads(output)
        print("this is the JOSN output!!!!!!", json_output)
        # Prepare the short media analysis JSON
        json_track = json_output['media']
        for f in json_track['track']:
            if f['@type'] == 'General':
                wrapper = f['Format']
            
            if f['@type'] == 'Video':
                wrapperType = f['Format_Profile']
                codec = f['Format']
                bitRate = f['BitRate']
                #frameRate = f['FrameRate']
                #som = f['TimeCode_FirstFrame']
                width = f['Width']
                height = f['Height']
                #framecount = f['FrameCount']
            #if f['@type'] == 'Other' and f['Type'] == 'Time code':
                #som = f['TimeCode_FirstFrame']
        mediaResult = {
            "Wrapper": wrapper + wrapperType,
            "Codec": codec,
            "BitRate": bitRate,
            #"FrameRate": frameRate,
            #"SOM": som,
            "Resolution": width + 'X' + height,
            #"FrameCount": framecount
        }
    except Exception as e:
        print (e)
        raise
        return None
    return mediaResult

def lambda_handler(event, context):
    print("this is the event !!!!!!!!!!!!!!!", event)
    bucketName = event['bucketName']
    objectName = event['objectKey']
    signed_url = get_presigned_url(3600, bucketName, objectName)
    print ('CORE:: Media Evaluator:: Presigned URL: ' + signed_url)
    mediaAnalysis = get_mediainfo(signed_url)
    print('CORE:: Media Evaluator:: Parsed Media Analysis: ' + json.dumps(mediaAnalysis, indent=4))
    #md5 = get_md5_from_objectTag(bucketName, objectName)
    #print('CORE:: Media Evaluator:: MD5 Value from Object Tag: ' + md5)
    ingestData = {
        "MediaEvaluation": mediaAnalysis,
        #"MD5": md5,
        "AssetID": objectName.partition(".")[0],
        "AssetUID": uuid.uuid4().hex,
        "Bucket": bucketName,
        "ObjectKey": objectName
    } 
    print('this is ingestData !!!!!!!!!!!!!!!!!!!!!!!', ingestData)
    print('this is mediaAnalysis !!!!!!!!!!!!!!!!!!!!!!!', mediaAnalysis)

    #ingestDataJson = json.dumps(ingestData)
    #mediaAnalysisJson = json.dumps(mediaAnalysis)

    dataNotFake = { 's3url': ingestData.Bucket + '.s3.amazonaws.com/' + ingestData.objectKey, 
 'Codec': mediaAnalysis.Codec, 'resolution': mediaAnalysis.Resolution}

    r = requests.post(url ='<mongobdAtlasUrlConnectStringHere>', data = dataNotFake)
    
    return ingestData

我发送的 Lambda 是,

{
  "bucketName": "<s3-bucket-name>",
  "objectKey": "<video-file-name>"
}

编辑: 初始响应

{
  "errorMessage": "'str' object has no attribute 'Bucket'",
  "errorType": "AttributeError",
  "stackTrace": [
    "  File \"/var/task/mediaEvaluator.py\", line 107, in lambda_handler\n    dataNotFake = { 's3url': ingestDataJson.Bucket + '.s3.amazonaws.com/' + ingestDataJson.objectKey, 'Codec': mediaAnalysisJson.Codec, 'resolution': mediaAnalysisJson.Resolution}\n"
  ]
}

然后是日志

7c4Uwzk422qMqIJfcFOZr6kwDasq3AEIy%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2MTYwODIzMjAyOTEiDHJGza1WClZUa%2BZKEyqwAWPyeYiNirreNeRtXlelQjCxUnEj3HMZiMF2UlPLpzwY3RRNo5LBpieIuIRUm7HtbWqXp19lDsUBHiGSoZqmNW5i5EN5nTPe6c6LNdKYFXYutvd4X1dsVEij8srY0DW%2FjBpiZxGt3DlhLWiDtoA8EjgXEe4JcpvU6Z9EpJeotjFhBzfe%2BM7xoPYE%2BoYS4ipx0nyntPQ4Qia1Cdh9LBwsHbcPL59JeI27lVmkggCFevZXMLqPzIEGOuABHPLi%2B3fu1bxwoDJYaA0HOwnAbF%2FncPMWpIR9NATDHyq%2B6BbaOxFAygyNXC%2FAjjqCEOezv1yfZ0VCMAP9i0Wi%2BBqgL8s4Qbuwk1PdgSfZdwqxrSOynSeX6s7Z5au9QYn%2BY%2F5upVr%2F5dt6Q8veRAWuqEQx4muzEix0jorBm4j1KAmuTYfv3A71Hv9YfhMmbR6h4XZv1U8nQpqNJNIJ%2FC%2BBBbRuXDWMhbfnK6IiXw9e3VWqQa7Esjj0WqHgOZ1wWGLZvqqy5Re%2Bm%2BF9eFdE%2F3mUv516aeU31eZ0gkHxnZGZ6HY%3D&Expires=1613960653', 'track': [{'@type': 'General', 'ID': '1', 'VideoCount': '1', 'MenuCount': '1', 'FileExtension': 'mpg?AWSAccessKeyId=ASIAY64K6FOR54JVBB5W&Signature=b16%2BkSWWYrrZvBlYA5tvs7DsqO4%3D&x-amz-security-token=IQoJb3JpZ2luX2VjEML%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIQCyP7t3a9Y6%2F4brzVhIOH5GEMpkargZlHCnX55tbiJKwQIgdBNqAwljhCiLZbf%2F7c4Uwzk422qMqIJfcFOZr6kwDasq3AEIy%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2MTYwODIzMjAyOTEiDHJGza1WClZUa%2BZKEyqwAWPyeYiNirreNeRtXlelQjCxUnEj3HMZiMF2UlPLpzwY3RRNo5LBpieIuIRUm7HtbWqXp19lDsUBHiGSoZqmNW5i5EN5nTPe6c6LNdKYFXYutvd4X1dsVEij8srY0DW%2FjBpiZxGt3DlhLWiDtoA8EjgXEe4JcpvU6Z9EpJeotjFhBzfe%2BM7xoPYE%2BoYS4ipx0nyntPQ4Qia1Cdh9LBwsHbcPL59JeI27lVmkggCFevZXMLqPzIEGOuABHPLi%2B3fu1bxwoDJYaA0HOwnAbF%2FncPMWpIR9NATDHyq%2B6BbaOxFAygyNXC%2FAjjqCEOezv1yfZ0VCMAP9i0Wi%2BBqgL8s4Qbuwk1PdgSfZdwqxrSOynSeX6s7Z5au9QYn%2BY%2F5upVr%2F5dt6Q8veRAWuqEQx4muzEix0jorBm4j1KAmuTYfv3A71Hv9YfhMmbR6h4XZv1U8nQpqNJNIJ%2FC%2BBBbRuXDWMhbfnK6IiXw9e3VWqQa7Esjj0WqHgOZ1wWGLZvqqy5Re%2Bm%2BF9eFdE%2F3mUv516aeU31eZ0gkHxnZGZ6HY%3D&Expires=1613960653', 'Format': 'MPEG-TS', 'FileSize': '102004664', 'Duration': '200.236328125', 'OverallBitRate_Mode': 'CBR', 'OverallBitRate': '4075040', 'StreamSize': '7646822', 'extra': {'OverallBitRate_Precision_Min': '4075030', 'OverallBitRate_Precision_Max': '4075051', 'FileExtension_Invalid': 'ts m2t m2s m4t m4s tmf ts tp trp ty'}}, {'@type': 'Video', 'StreamOrder': '0-0', 'ID': '481', 'MenuID': '1', 'Format': 'AVC', 'Format_Profile': 'Main', 'Format_Level': '4.1', 'Format_Settings_CABAC': 'Yes', 'Format_Settings_RefFrames': '1', 'Format_Settings_GOP': 'M=1, N=15', 'CodecID': '27', 'Duration': '194.867', 'BitRate': '3873733', 'Width': '1280', 'Height': '720', 'Sampled_Width': '1280', 'Sampled_Height': '720', 'PixelAspectRatio': '1.000', 'DisplayAspectRatio': '1.778', 'ColorSpace': 'YUV', 'ChromaSubsampling': '4:2:0', 'BitDepth': '8', 'ScanType': 'Progressive', 'Delay': '10.000000', 'StreamSize': '94357842'}, {'@type': 'Menu', 'StreamOrder': '0', 'ID': '480', 'MenuID': '1', 'Format': 'AVC / KLV', 'Duration': '200.236328125', 'Delay': '0.001107222', 'List_StreamKind': '1 / ', 'List_StreamPos': '0 / ', 'extra': {'pointer_field': '0', 'section_length': '55'}}]}}
CORE:: Media Evaluator:: Parsed Media Analysis: {
    "Wrapper": "MPEG-TSMain",
    "Codec": "AVC",
    "BitRate": "3873733",
    "Resolution": "1280X720"
}
this is ingestData !!!!!!!!!!!!!!!!!!!!!!! {'MediaEvaluation': {'Wrapper': 'MPEG-TSMain', 'Codec': 'AVC', 'BitRate': '3873733', 'Resolution': '1280X720'}, 'AssetID': 'Day Flight', 'AssetUID': 'cb0651e1151f41a5a890425d41bda3cb', 'Bucket': 'video-uploads-94viwznlhm88', 'ObjectKey': 'Day Flight.mpg'}
this is mediaAnalysis !!!!!!!!!!!!!!!!!!!!!!! {'Wrapper': 'MPEG-TSMain', 'Codec': 'AVC', 'BitRate': '3873733', 'Resolution': '1280X720'}
[ERROR] AttributeError: 'str' object has no attribute 'Bucket'
Traceback (most recent call last):
  File "/var/task/mediaEvaluator.py", line 107, in lambda_handler
    dataNotFake = { 's3url': ingestDataJson.Bucket + '.s3.amazonaws.com/' + ingestDataJson.objectKey, 'Codec': mediaAnalysisJson.Codec, 'resolution': mediaAnalysisJson.Resolution}
END RequestId: bfcf3bb8-d709-44c5-9e42-8c7a6a31a879
REPORT RequestId: bfcf3bb8-d709-44c5-9e42-8c7a6a31a879  Duration: 6679.29 ms    Billed Duration: 6680 ms    Memory Size: 128 MB Max Memory Used: 104 MB Init Duration: 382.19 ms

我仍然无法深入了解 ingestData,但我设法通过传递 bucketName 和 objectName 来创建 s3 URL 到 link 到 mongo 中的上传数据来避免这个问题,并且将整个 mediaAnalysis 传递给 mongo.

  dataNotFake = { "s3url": bucketName + '.s3.amazonaws.com/' + objectName, "mediaAnalysis": mediaAnalysis}

我觉得这里

dataNotFake = { 's3url': ingestData.Bucket + '.s3.amazonaws.com/' + ingestData.objectKey,

考虑这些

ingestData = {'MediaEvaluation': {'Wrapper': 'MPEG-TSMain',
  'Codec': 'AVC',
  'BitRate': '3873733',
  'Resolution': '1280X720'},
 'AssetID': 'Day Flight',
 'AssetUID': 'cb0651e1151f41a5a890425d41bda3cb',
 'Bucket': 'video-uploads-94viwznlhm88',
 'ObjectKey': 'Day Flight.mpg'}

mediaAnalysis = {
'Wrapper': 'MPEG-TSMain', 'Codec': 'AVC', 'BitRate': '3873733', 'Resolution': '1280X720'}

你应该使用这样的东西

dataNotFake = { 
's3url': f'{ingestData["Bucket"]}.s3.amazonaws.com/{ingestData["ObjectKey"]}', 
'Codec': mediaAnalysis['Codec'],
'resolution': mediaAnalysis['Resolution']
}