- 要件定義〜python環境構築
- サイトのスクレイピング機構を作る
- ダウンロードしたファイル(xls)を加工し、最終成果物(csv)を作成するようにする
- S3からのファイルダウンロード / S3へのファイルアップロードをつくる
- 2captchaを実装
- Dockerコンテナで起動できるようにする
- AWS batchに登録
S3の操作
ファイル構成の変更
前回までで スクレイピング〜ファイルの加工までをだらだら書いていきましたが、このタイミングでファイルの分割をしました。
S3につなげる=Inputとなるwordsが大量になる=テスト実行に時間がかかる
ということで、テストモードを作るのがひとつの目的です。
今回はこんな感じに分けてみました。
ファイル構成
├── app
│ ├── drivers seleniumドライバーを置く
│ └── source
│ ├── run.py メイン実行ファイル
│ ├── scraping.py スクレイピング処理(第2回)
│ ├── make_outputs.py ダウンロードしたファイルの加工処理(第3回)
│ ├── s3_operator.py S3に関する処理(今回:第4回)
│ └── configs.py 環境変数やパスワードなど
└── tmp
├── files
│ ├── fromS3 メイン実行
│ ├── toS3 メイン実行
│ └── download スクレイピングでダウンロードしたファイルを置く
└── logs ログ(seleniumログなど)
メインの実行ファイル=run.py から、各ファイルの処理を呼び出します。
S3から取ってくるwordsは膨大なので、テスト時は実行時間が短くなるように「テスト実行モード」ができるようにしておきます。
run.py
if __name__ == '__main__':
#テスト実行モードを作れるようにしておく
parser = argparse.ArgumentParser(description='scraping batch')
parser.add_argument('--run_mode', dest='run_mode', default = 'normal', help='run_mode: test | normal')
args = parser.parse_args()
# 環境ごとの変数を取ってくる
env = os.getenv('BATCH_ENV', 'LOCAL')
config = configs.load(env)
#メイン処理
words = s3_operator.getFromS3(config) #S3からファイルを取得し、INPUTたるwordsを得る
scraping.main(config,args,words) #スクレイピング処理(テスト実行時は2件で終わるようにしている)
make_outputs.main(config,words) #ファイル処理
s3_operator.sendToS3(config) #S3にファイルを送る
ちなみに、configs.pyはこんな感じです
configs.py
class Config:
login_url = "XXXXXXXXXX"
login_id = "XXXXXXXXXX"
login_password = "XXXXXXXXX"
#S3
region_name ="XXXXXXXXXX"
input_path = "XXXXXXXXXXX"
output_path = "XXXXXXXXXX"
@staticmethod
def load(env_name):
if env_name == 'PRD':
return PrdConfig()
elif env_name == 'STG':
return StgConfig()
elif env_name == 'DEV':
return DevConfig()
else:
return LocalConfig()
class LocalConfig(Config):
access_key_id = 'XXXXXXXXX'
secret_access_key = 'XXXXXXXXXX'
bucket_name = 'XXXXX'
#...以下 DevConfig,StgConfig,PrdConfigも同様
S3からファイルを取得する処理
S3からファイルを取得する処理を書いていきます。
- ダウンロードファイルの格納先を作る
- S3のファイル名の一覧を取得
- 一つずつダウンロード
- ダウンロードしたファイルから取得
※実際にはファイルが複数あったので上記の流れにしたのですが…この記事では/YYYYMMDD/words.csv
しか取得しないことにするのでちょっと冗長になっちゃうなあ。まあいいか。
s3_operator
def getFromS3(config):
#S3からダウンロードしたファイルの格納先を作る
date = datetime.now().strftime('%Y%m%d')
dldir_name = os.path.abspath(__file__ + '/../../../tmp/files/fromS3/'.format(date))
dldir_path = Path(dldir_name)
dldir_path.mkdir(exist_ok=True)
download_dir = str(dldir_path.resolve())
#S3に接続するクライアント情報を定義
s3_client = boto3.client(
's3',
region_name=config.region_name,
aws_access_key_id=config.access_key_id,
aws_secret_access_key=config.secret_access_key,
)
#指定したbucket内の指定パスなファイルの一覧を取得
key_prefix = config.output_path + '/{}/'.format(date)
response = s3_client.list_objects_v2(Bucket=config.bucket_name,Prefix=key_prefix)
if response["KeyCount"] == 0:
print('オブジェクトが存在しません:{}'.format(key_prefix))
return
#ファイルを一つずつダウンロード
for object in response["Contents"]:
object_name = object["Key"]
download_file_name = os.path.basename(object["Key"])
if len(download_file_name) == 0:
continue
download_file_name = download_dir + '/' + download_file_name
s3_client.download_file(Bucket=config.bucket_name, Key=object_name, Filename=download_file_name)
print('オブジェクト「{}」をダウンロードしました。ダウンロード先:{}'.format(object_name,download_file_name))
#wordsを得る
download_file_name = download_dir + '/words.csv'
return pd.read_csv(download_file_name).values.tolist()
S3にファイルを送る処理
こちらは、ファイルを送る処理。こっちは作ったものを送るだけなので簡単です
s3_operator
def exportToS3(config):
date = datetime.now().strftime('%Y%m%d')
s3_client = boto3.client(
's3',
region_name=config.region_name,
aws_access_key_id=config.access_key_id,
aws_secret_access_key=config.secret_access_key,
)
upfiles = glob.glob(os.path.abspath(__file__ + '/../../../tmp/files/toS3/{}/*'.format(date)))
for f in upfiles :
filename = os.path.split(f)[1]
object_name = config.input_path + "/{}/{}".format(date,filename)
s3_client.upload_file(f,config.bucket_name,object_name)
完成
これで、python run.py
すれば、目的を達成できるプログラムになりました。
が…
- 毎週実行するには自分のPCで叩かなければならない
- reCAPTCHAを自分で解除しなければならない
- 実行中はPCを立ち上げっぱなしにする必要がある
という状況なので、次回からはそれをなんとかしていきます。