boto3とboto2.49.0でS3からファイルを取得する方法

S3からファイル一覧を取得し、直近2hのファイルを対象にダウンロードする処理をboto3で書きました。
これをboto2で書く必要にせまられましたが、検索してもboto3の情報ばかりで苦労したのでメモしておきます。

## boto3版

```python
# -*- coding: utf-8 -*-

import os
import boto3
import pytz
from datetime import datetime, timedelta

s3_bucket_name = os.getenv('AWS_S3_BUCKET_NAME')
s3 = boto3.client(
    's3',
    aws_access_key_id=os.getenv('AWS_S3_ACCESS_KEY_ID'),
    aws_secret_access_key=os.getenv('AWS_S3_SECRET_ACCESS_KEY')
)


# 直近2h以内に更新されたファイルを対象に取得する
def download_new_files(minutes=120):
    utc_now = datetime.now(pytz.timezone('utc')) - timedelta(minutes=minutes)
    prefix = 'baseball/'
    res = list_handler(prefix)

    # 日付降順にsort
    res_sorted = sorted(res, key=lambda x: x['LastModified'], reverse=True)

    download_path = '/var/tmp/'
    if not os.path.isdir(download_path + prefix):
        os.mkdir(download_path + prefix)

    for content in res_sorted:
        if content['LastModified'] < utc_now:
            break

        s3.download_file(s3_bucket_name, content['Key'], download_path + content['Key'])
        print(content['Key'] + ' download complete.')


# 1000件を超える場合の考慮
def list_handler(prefix):
    contents = []
    next_token = ''
    while True:
        if next_token == '':
            response = s3.list_objects_v2(Bucket=s3_bucket_name, Prefix=prefix)
        else:
            response = s3.list_objects_v2(Bucket=s3_bucket_name, Prefix=prefix, ContinuationToken=next_token)

        contents.extend(response['Contents'])
        if 'NextContinuationToken' in response:
            next_token = response['NextContinuationToken']
        else:
            break

    return contents

if __name__ == '__main__':
    download_new_files()
```

### ポイント
1000件を超えた場合を考慮してs3.list_objects_v2を使って再帰的にobject一覧を取得しています

## boto2版
```python
# -*- coding: utf-8 -*-

import os
import boto
import pytz
from dateutil.parser import parse
from datetime import datetime, timedelta
from boto.s3.bucket import Bucket

s3_bucket_name = os.getenv('AWS_S3_BUCKET_NAME')
s3_conn = boto.connect_s3(aws_access_key_id=os.getenv('AWS_S3_ACCESS_KEY_ID'), aws_secret_access_key=os.getenv('AWS_S3_SECRET_ACCESS_KEY'))
boto2_bucket = Bucket(connection=s3_conn, name=s3_bucket_name)


def download_new_files(minutes=120):
    utc_now = datetime.now(pytz.timezone('utc')) - timedelta(minutes=minutes)
    prefix = 'baseball/'
    res = boto2_bucket.list(prefix=prefix)

    # 日付降順にsort
    res_sorted = sorted(res, key=lambda x: x.last_modified, reverse=True)

    download_path = '/var/tmp/'
    if not os.path.isdir(download_path + prefix):
        os.mkdir(download_path + prefix)

    for key_object in res_sorted:
        last_modified = parse(key_object.last_modified)
        if last_modified < utc_now:
            break

        key_object.get_contents_to_filename(download_path + key_object.key)

        print(key_object.key + ' download complete.')


if __name__ == '__main__':
    download_new_files()
```

### ポイント
boto.s3.bucket.list()関数でboto.s3.bucketlistresultset.BucketListResultSetが返ってくる。中身はboto.s3.key。
keyオブジェクトにはboto3の取得結果と同様に最終更新日(last_modified)が含まれるが、datetime型ではなくて文字列なので、dateutil.parser.parseで変換している。

## 詳しい方に教えてもらいたいこと
* boto2のboto.s3.bucket.list()に件数の上限があるのかどうか。boto3版のlist_handler()みたいな考慮は必要？
* 自前でsortせずにS3から直近の更新ファイルを取得する方法

## 参考
[Boto 3 Documentation 1.9.222 ](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html)
[boto v2.49.0 API Reference](http://boto.cloudhackers.com/en/latest/ref/s3.html#module-boto.s3.bucket)
[PythonでYYYY-MM-DDTHH：mm：ss.000Z時刻形式をMM/DD/YYYY時刻形式に変換するにはどうすればよいですか？](https://codeday.me/jp/qa/20190121/168091.html)