前提
S3にアップロードされたcsvを
ストリームで読み込み、型変換してOpensearchへ転送する。
その際、一部の型をintやdatetimeへ変換して転送する必要がある。
問題
datetime変換エラーとなり転送できない
実現したいこと
- ストリームで読み込ん任意の項目をdatetime型に変換したい
 
取り込むcsv
ヘッダ8個,データ8個
vmanage_host, systemip, hostname , devicemodel, bfdSessionsUp, bfdSessions, dt, IPsecTunnel vmanageABC, 123.456.789.012, vedgeABC, deviceABC, 99, 999, 2022/1/1 01:01, 123
発生している問題・エラーメッセージ
datetime変換エラーとなり転送できない
[ERROR] TypeError : Object of type datetime is not JSON serializable
該当のソースコード
Python(Lambda)
1 2import boto3 3import re 4import requests 5import csv 6import io 7from datetime import datetime 8from requests_aws4auth import AWS4Auth 9 10#配列(不要指摘→後に削除) 11#vmanage_host = [] 12#systemip = [] 13#hostname = [] 14#devicemodel = [] 15#bfdSessionsUp = [] 16#bfdSessions = [] 17#datetime = [] 18#IPsecTunnel = [] 19 20 21region = '(略)' # e.g. us-west-1 22service = 'es' 23credentials = boto3.Session().get_credentials() 24awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token) 25 26host = '(略)' # the OpenSearch Service domain, e.g. https://search-mydomain.us-west-1.es.amazonaws.com 27index = 'lambda-s3-index_test' 28type = '_doc' 29url = host + '/' + index + '/' + type 30 31headers = { "Content-Type": "application/json" } 32 33s3 = boto3.client('s3') 34 35# Lambda execution starts here 36def handler(event, context): 37 for record in event['Records']: 38 39 # Get the bucket name and key for the new file 40 bucket = record['s3']['bucket']['name'] 41 key = record['s3']['object']['key'] 42 43 # Get, read, and split the file into lines 44 obj = s3.get_object(Bucket=bucket, Key=key) 45 body = obj['Body'].read() 46 textIo = io.TextIOWrapper(io.BytesIO(body)) 47 48 skiptext = next(textIo) 49 50 # Match the regular expressions to each line and index the JSON 51 for row in csv.reader(textIo): 52 53 print(row) 54 vmanage_host = row[0] 55 systemip = row[1] 56 hostname = row[2] 57 devicemodel = row[3] 58 bfdSessionsUp = row[4] 59 bfdSessions = row[5] 60 infgettime = row[6] 61 IPsecTunnel = row[7] 62 63 print(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]) 64 65 document = { 66 "vmanage_host ": vmanage_host , 67 "systemip ": systemip , 68 "hostname ": hostname , 69 "devicemodel ": devicemodel , 70 "bfdSessionsUp": [int(bfdSessionsUp)], 71 "bfdSessions ": [int(bfdSessions)], 72 "infgettime ": [datetime.strptime(infgettime , `%Y/%m/%d %H:%M`)], 73 "IPsecTunnel ": [int(IPsecTunnel)], 74 } 75 r = requests.post(url, auth=awsauth, json=document, headers=headers)
試したこと
【Python】日付時刻・文字列・数値型データの相互変換方法|datetime・dateモジュールの基本操作入門
https://di-acc2.com/programming/python/22894/#index_id1
を参考に修正したが、いずれも事象解消には至らず。
補足情報(FW/ツールのバージョンなど)
Python3.9
最初に、
vmanageABC, 123.456.789.012, vedgeABC, deviceABC, 1, 2, 3, 2022/1/1 01:01, 123
の行は 9 個の要素がありますが、ヘッダには 8 個のカラムしかありません。
それから datetime というクラス名がバッティングしています。
from datetime import datetime
datetime = []     # コードの先頭部分
datetime = row[6] # for loop 内
for loop 内で使っている datetime(変数名)を変更する必要があります。また、「# 配列」というコメント以降の初期化部分は不要でしょう。
melianさん
ご指摘ありがとうございます。
以下修正いたしました
>vmanageABC, 123.456.789.012, vedgeABC, deviceABC, 1, 2, 3, 2022/1/1 01:01, 123
>の行は 9 個の要素がありますが、ヘッダには 8 個のカラムしかありません。
要素は8,ヘッダも8になります。
>from datetime import datetime
>
>datetime = [] # コードの先頭部分
>datetime = row[6] # for loop 内
>
>for loop 内で使っている datetime(変数名)を変更する必要があります。また、「# 配列」というコメント以降の初期化部分は不要でしょう。
変数名を変更しました。
datetime を infgettime へ変更
「for row in lines csv.reader(textIo):」行や
「"infgettime ": [datetime.strftime(infgettime , `%Y/%m/%d %H:%M`)]」行などで
構文エラーになるようです。実際のコードと相違はないでしょうか。
さらに上記コードが正しいとしても
infgettime変数はstr型のはずなのでdatetime.strftimeでTypeErrorが発生するはずです。
melianさん
ご指摘ありがとうございます。
転記ミス申し訳ありません。
>「for row in lines csv.reader(textIo):」行
以下修正いたしました
for row in csv.reader(textIo):
>"infgettime ": [datetime.strftime(infgettime , `%Y/%m/%d %H:%M`)]
以下修正いたしました
"infgettime ": [datetime.strptime(infgettime , `%Y/%m/%d %H:%M`)]
そうなりますと、簡単な対応方法としては json.dumps に default のコンバータを指定することかと思います。以下の様にすると、datetime 型インスタンスを文字列に変換してから requests.post() に渡します。
r = requests.post(url, auth=awsauth, data=json.dumps(document, default=str), headers=headers)
回答1件
あなたの回答
tips
プレビュー