3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

なんちゃってエンジニアがAWSでそれっぽいことをしてみた part4

Last updated at Posted at 2025-12-07

まさかの2年越しの続編投稿です
前回part3はこちら

前回part3はsuumoから不動産の販売情報をスクレイピングで取得してBing Mapにマッピングするというプログラムをpythonで書きました。まだ当時、AIコードアシスタントはメジャーではなかったので、チャッピーと壁打ちしながら、時にはソースそのままぶっ込んで修正おなしゃす!とかやりながら、仕上げていた記憶です。デプロイもしてなくて、ローカル上でしこしこ動かして悦に入っていたっぽい。

2年越しの投稿ということで、もう少し私の成長っぷりをみせつけたい。そうはいっても概ねAI駆動開発の進歩の産物なんですが(笑)本人のスキル向上とは別のところで、技術進歩により開発工程も、アウトプットもぐっと洗練された様子をお届けしようと思います。

今回やったこと

①データ取得をサーバサイドで実行し、最新の情報を非同期で反映できるようにする。
②①で取得した販売情報データを地図にマッピングして、可視化する。フィルタ機能をつけて、分析しやすくする。それをどこかの環境にデプロイして、サービスとしてプレビュー版公開する。(自分でみてニヤニヤするだけ)
(注記)スクレイピング処理の実行について スクレイピングはデータ活用における強力な武器である一方、やり方を間違えると「サーバー攻撃とみなされるリスク」や「法的トラブルにつながるおそれ」があります。

本記事におけるスクレイピング処理の実行にあたっては、以下の点を前提として実施しています。

対象となるWebサイト(SUUMO)については、事前に利用規約を確認し、本記事のような「私的な学習の範囲」かつ「通常の利用を妨げない範囲」において、明確に禁止されていないことを確認した上で実施しています。また、使用するプログラムには不正アクセスやデータの破壊など有害な動作を行う意図・機能は一切含まれていません。

スクレイピングの是非は、対象サイトの規約や実施方法・手法等によって判断が分かれます。明確に禁止が謳われている場合以外でも、スクレイピングマナーを守り、相手方のサーバ負荷への最大限の配慮を行うとともに、営利活動への影響がないようにしましょう。

(スクレイピングマナー)
・Time.sleep(アクセス間隔)の確保: 連続的なリクエストによるサーバーダウンや帯域圧迫を防ぐため、リクエストごとに十分な待機時間(数秒〜数十秒)を設け、人間がブラウザで閲覧するのと同等、あるいはそれ以下の頻度に留める。
・オフピークタイムでの実行: サービスの利用者数が多い時間帯を避け、サーバー負荷が低い深夜や早朝などのオフピーク時間に限定してプログラムを実行する  など

①データ取得(スクレイピング)の自動化

改めて作成してもよろしいのですが、過去の作ったものをリバースエンジニアリングする形で制作していこうと思います ※Geminiが

image.png

こんな雑プロンプトから、次のような提案をしてくれました。

1. Pythonコードの修正

ローカル実行用のコードを、Lambdaで動くように修正します。主な変更点は以下の2つです。
・処理全体を lambda_handler 関数内に収める。
・to_csv でのローカル保存を廃止し、boto3 を使ってメモリ上から直接S3へアップロードする。

修正後のコードイメージ (app.py)

    import pandas as pd
    import boto3
    import io
    import os

    # S3設定
    S3_BUCKET_NAME = "your-bucket-name" # 作成したバケット名
    S3_FOLDER_NAME = "suumo_data/"

    def lambda_handler(event, context):
        print("job start")
    
        # ... スクレイピング処理 (省略) ...
    
        # DataFrame作成
        df = pd.DataFrame(data, columns=['物件名', ...])
    
        # CSVをメモリバッファに書き込み
        csv_buffer = io.StringIO()
        df.to_csv(csv_buffer, index=False, encoding='utf-8-sig')
    
        # S3へアップロード
        s3 = boto3.client('s3')
        file_name = f"suumo_bukken_{date_string}.csv"
        key = f"{S3_FOLDER_NAME}{file_name}"
    
        s3.put_object(Bucket=S3_BUCKET_NAME, Key=key, Body=csv_buffer.getvalue())
    
        print(f"Uploaded to s3://{S3_BUCKET_NAME}/{key}")
        return {'statusCode': 200, 'body': 'Success'}

2. 環境構築(Dockerを使ったデプロイ)

pandas や BeautifulSoup4 (bs4) はLambdaの標準環境に含まれていません。Lambda Layersを使う手もありますが、依存関係を確実に管理するためにDockerコンテナイメージを使ってデプロイする方法を採用しました。

ディレクトリ構成
    project-folder/
     │
     ├─ app.py          # 修正したPythonコード
     ├─ requirements.txt # 依存ライブラリ
     └─ Dockerfile      # コンテナ定義
requirements.txt (依存ライブラリ)

ここで重要なのが numpy のバージョンです。最新版だとLambda環境でのビルド時にコンパイルエラー(gcc不足)が発生したため、バイナリが提供されている安定版を指定しました。

Dockerfile (コンテナ定義)

AWSが提供するLambda用のベースイメージを使います。

    FROM public.ecr.aws/lambda/python:3.11

    # 依存関係をインストール
    COPY requirements.txt ${LAMBDA_TASK_ROOT}
    RUN pip install -r requirements.txt

    # スクリプトをコピー
    COPY app.py ${LAMBDA_TASK_ROOT}

    # 実行ハンドラを指定
    CMD [ "app.lambda_handler" ]

3.AWS CloudShellを使ったデプロイ

ローカルPCにDocker Desktopを入れるのは重いし手間がかかるため、AWS上のブラウザで使えるターミナル AWS CloudShell を使ってビルドを行いました。これが一番手軽です。

手順
(1)ECRリポジトリの作成

AWSコンソールで Elastic Container Registry (ECR) を開き、リポジトリを作成します(例: suumo-scraper)。

(2)CloudShellでビルド & プッシュ

CloudShellに3つのファイルをアップロードし、ECRの「プッシュコマンド」に従ってコマンドを実行します。

    # ECRへのログイン
    aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [AWSアカウントID].dkr.ecr.ap-northeast-1.amazonaws.com

    # ビルド
    docker build -t suumo-scraper .

    # タグ付け & プッシュ
    docker tag suumo-scraper:latest [URI]:latest
    docker push [URI]:latest

4. Lambda関数の作成と設定

AWS Lambdaコンソールで関数を作成します。

(1)関数の作成

「コンテナイメージ」を選択し、先ほどプッシュしたECRイメージを指定。

(2)権限設定

実行ロールに AmazonS3FullAccess(または対象バケットへの書き込み権限)を付与。

【重要】タイムアウトとメモリの設定

スクレイピングは処理時間が長く、メモリも消費します。デフォルト設定(3秒 / 128MB)では確実に失敗するため、以下のチューニングを行いました。
メモリ: 512MB → 2048MB (2GB)
※512MBでは処理途中でメモリ不足エラーが発生しました。

タイムアウト: 3秒 → 10分
※Lambdaの最大実行時間は15分。

5. 実行結果

テスト実行を行い、CloudWatch Logsで job end を確認。 指定したS3バケットを見に行くと、無事にCSVファイルが生成されていました!

S3バケット

image.png

csvの中身

image.png

GitHubリポジトリ

今回のコード一式はこちらで公開しています。
https://github.com/misonosuke/suumo-scraper

なおこの先の作業をやっていて、地図にマップするための緯度経度情報がないことに気づき、後でgeocoderで住所から緯度経度情報与えるプログラムを追加作成しています。

ここまででだいぶ盛りだくさんな内容となったため、デプロイ②については後半part5に
持ち越しさせていただきたいと思います。

乞うご期待。

後半part5はこちら

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?