AWS lambda+scrapy로 정기적으로 서버리스 스크래핑 1.8

소개



먼저 결론을 쓰면 Lambda에서 움직이는 곳까지 갈 수 없었습니다.
다른 방법의 대처는 있으므로, 그쪽이 잘 되면 추기, 혹은 다른 기사로서 들려고 생각합니다.

이번에는 마지막 (그 1) 작성한 weather_spider.py를 AWSlambda에 올려서 서버리스로 실행할 수 있도록 하겠습니다.
전회부터 상당한 시간이 비어 버렸습니다만, 이유는 나중에・・・.

목표



Lambda를 사용하여 Yahoo! 날씨 (도쿄)의 데이터를 6 시간 간격으로 가져옵니다.

방법



이번에는 서버리스 애플리케이션 모델(SAM)을 사용하여 lambda를 구축해 나갈 것입니다.

SAM에 대한 자세한 내용은 여기을 참조하십시오.

다음은 aws 명령, sam 명령을 실행할 수 있다고 가정합니다.

해보자



1.SAM Project 만들기(sam init)



이번에는 Python3.7에서 구현하기 때문에 runtime에 python3.7을 지정하여 sam init합니다.
$ sam init --runtime python3.7
[+] Initializing project structure...

Project generated: ./sam-app

Steps you can take next within the project folder
===================================================
[*] Invoke Function: sam local invoke HelloWorldFunction --event event.json
[*] Start API Gateway locally: sam local start-api

Read sam-app/README.md for further instructions

[*] Project initialization is now complete

이런 식으로 한순간에 sam project가 만들어집니다.

폴더 구성은 이하.

sam-app
├── README.md
├── events
│   └── event.json
├── hello_world
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-37.pyc
│   │   └── app.cpython-37.pyc
│   ├── app.py
│   └── requirements.txt
├── template.yaml
└── tests
    └── unit
        ├── __init__.py
        ├── __pycache__
        │   ├── __init__.cpython-37.pyc
        │   └── test_handler.cpython-37.pyc
        └── test_handler.py

sam-app 바로 아래에 마지막으로 만든 yahoo_weather_crawl 복사
$ cp -r yahoo_weather_crawl sam-app/

$ cd sam-app/
$ ls
README.md       hello_world     tests
events          template.yaml       yahoo_weather_crawl

2.weather_spider.py 수정



lambda에서 킥할 수 있도록 handler를 추가합니다.

spider/weather_spider.py

# -*- coding: utf-8 -*-
import scrapy
from yahoo_weather_crawl.items import YahooWeatherCrawlItem
from scrapy.crawler import CrawlerProcess

# spider
class YahooWeatherSpider(scrapy.Spider):

    name = "yahoo_weather_crawler"
    allowed_domains = ['weather.yahoo.co.jp']
    start_urls = ["https://weather.yahoo.co.jp/weather/jp/13/4410.html"]

    # レスポンスに対する抽出処理
    def parse(self, response):
        # 発表日時
        yield YahooWeatherCrawlItem(announcement_date = response.xpath('//*[@id="week"]/p/text()').extract_first())
        table = response.xpath('//*[@id="yjw_week"]/table')

        # 日付ループ
        for day in range(2, 7):

            yield YahooWeatherCrawlItem(
                # データ抽出
                date=table.xpath('//tr[1]/td[%d]/small/text()' % day).extract_first(),
                weather=table.xpath('//tr[2]/td[%d]/small/text()' % day).extract_first(),
                temperature=table.xpath('//tr[3]/td[%d]/small/font/text()' % day).extract(),
                rainy_percent=table.xpath('//tr[4]/td[%d]/small/text()' % day).extract_first(),
                )

    # lambda handler
    def lambda_handler(event,context):
        process = CrawlerProcess({
            'FEED_FORMAT': 'json',
            'FEED_URI': '/tmp/result.json'
        })

        process.crawl(YahooWeatherCrawler)
        process.start()
        print('crawl success')


3.template.yaml 수정



이전에 sam init 명령으로 만든 tamplate.yaml를 수정합니다.

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Yahoo weather crawler template on SAM

Globals:
  Function:
    Timeout: 3

Resources:
  WeatherCrawlerFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: ./yahoo_weather_crawl/spiders
      Handler: weather_spider.lambda_handler
      Runtime: python3.7
      Events:
        WeatherCrawlEvent:
          Type: Schedule
          Properties:
            #毎日6時間おきに実行
            Schedule: cron(0 */6 * * ? *)

여기에서는 Events에 매일 6 시간 간격으로 실행하는 cron을 넣고,
Cloudwatch 이벤트에서 시작하도록 합니다.

4. build (배포 할 모듈을 모으기) 용 쉘 만들기



AWS에 배포할 때 필요한 모듈을 build라는 폴더에 연결합니다.

하지만 그 전에 이번에 scrapy를 가져오고 파이썬을 실행하지만 scrapy 종속 라이브러리
안에 lxml라는 라이브러리가 있습니다.
pip install scrapy 그렇다면 lxml도 자동으로 설치됩니다.
Python3.7 런타임의 AWS Lambda에 업로드하면 그대로 모듈을 로드할 수 없습니다.
(여기에 고전하고, 꽤 시간이 걸렸습니다・・・.)

따라서 이번에는 이 기사에서 만든 비전 소스 (EC2에서 컴파일 된 lxml 라이브러리, 자세한 내용은 기사 참조)를 lib라는 폴더에 저장하고 build 셸의 build 폴더에 복사 해야 합니다.

build.sh
# build

dir=yahoo_weather_crawl

echo '仮想環境を作成します'
python3 -m venv .venv

echo '仮想環境を有効化します'
. .venv/bin/activate

rm -rf ${dir}/build

# buildフォルダの作成
echo '${dir}をbuildします'
mkdir ${dir}/build

# buildフォルダにpip install
echo 'requirements.txtからpip installします'
pip3 install -r ${dir}/requirements.txt -t ${dir}/build

# libフォルダからbuildフォルダへコピー
echo 'libフォルダからbuildフォルダへ必要モジュールをコピーします'
cp -rf ./lib/* ${dir}/build

# pyファイルのコピー
echo 'pyファイルをbuildフォルダにコピーします'
cp -f ${dir}/*.py ${dir}/build
cp -f ${dir}/spiders/*.py ${dir}/build

# echo '仮想環境を無効化します'
deactivate

echo 'ビルドが完了しました'

5.sam-deploy에 대한 쉘 만들기



명령에서 배포할 수 있도록 deploy용 셸을 만듭니다.

deploy.sh

# build
echo 'YahooWeatherCrawlerをビルドします'
sh build.sh

# templateをuploadするためのS3バケットの作成
# バケット名は世界中で一意にする必要があるので、コピペで作成する場合はバケット名を変更してください。
if  aws s3 ls "s3://weather-crawl-bucket" 2>&1 | grep -q 'NoSuchBucket' ; then
    echo "weather-crawl-bucketを作成します。"
    aws s3 mb s3://weather-crawl-bucket
else
    echo "weather_crawl-bucketを空にします。"
    aws s3 rm s3://weather-crawl-bucket --recursive
fi

# デプロイ用パッケージの作成
# 作成されたパッケージをS3にuploadします。作成したバケット名を指定してください。
echo "デプロイ用のパッケージを作成します。"
aws cloudformation package --template-file template.yaml \
--output-template-file output-template.yaml \
--s3-bucket weather-crawl-bucket

# デプロイ
aws cloudformation deploy --template-file output-template.yaml \
--stack-name weather-crawler \
--capabilities CAPABILITY_IAM

6. 배포


sam-app $sh deploy.sh
..
Successfully created/updated stack - weather-crawler

7. 실행



AWS 콘솔로 이동하여 실행!


이제 다른 모듈의 ImportError ...
Mac의 로컬에서 빌드하는 것은 조금 힘들 것 같기 때문에 다른 방법을 생각하고 싶습니다.

끝에



매주 Qiita에 기사를 올리기로 결정한 지 한 달 이상 지났지만,
올해는 결국 세 기사밖에 걸리지 않았습니다. (한 번 빠지면 빠질 수 없다!)

내년도? 계속해서 노력해 가기 때문에, 잘 부탁드리겠습니다.

좋은 웹페이지 즐겨찾기