macにインストールしたscrapyをzip化してaws lambdaで使うとこんなエラーが発生。
{
"errorMessage": "Unable to import module 'lambda_function':
cannot import name 'etree' from 'lxml' (/var/task/lxml/__init__.py)",
"errorType": "Runtime.ImportModuleError"
}
etree.hはC言語の拡張を使っている、ビルドするOSに関係するのかな?
ということで、lambdaを動かしているOSでビルドすればいいじゃないかと考え、amazon linuxでscrapyライブラリをzip化することにしました。
scrapyのライブラリを用意するためのインスタンスを作成します。「Amazon Linux 2 AMI (HVM), SSD Volume Type」のt2.nano、ts.microぐらいの小規模なものでOK。
インスタンスが立ち上がったらローカルからsshで接続します
#ローカル→EC2
$ssh -i hoge.pem ec2-user@111.222.333.444
#EC2
$sudo yum install git
$git clone git://github.com/yyuu/pyenv.git ~/.pyenv
$vi ~/.bash_profile
.bash_profileを書き換えます
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
諸々必要なライブラリとpython3.8.0をインストールします。
#EC2
$sudo yum install libffi-devel
$sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel -y
$pyenv install 3.8.0
$pyenv global 3.8.0
$pyenv rehash
$python --version
lambdaは/opt/python以下のライブラリを読む仕様なのでpythonフォルダを作成し、以下にscrapyをインストールし、zip化します。
#EC2
$mkdir python
$pip install -t ./python scrapy
$zip -r scrapy.zip python
一旦、zipファイルをローカルにダウンロードします。
#ローカル
$scp -i xxx.pem ec2-user@111.222.333.444:/home/ec2-user/dev/scrapy.zip ./
ローカルにダウンロードしたzipファイルをlambdaレイヤーに登録します。lambdaレイヤーに登録したライブラリは共通ライブラリとしてどのlambdaからも使用することが可能です。
lambdaにScrapy(CrawlerProcess)を使った処理を記載して実行。エラーなく実行できた!
import logging
import scrapy
from scrapy.crawler import CrawlerProcess
logger = logging.getLogger()
logger.setLevel(logging.INFO)
class MySpider(scrapy.Spider):
name = 'testspider'
start_urls = [
'http://www.xxx.go.jp/'
]
def start_requests(self):
logger.info('start_requests():')
・・・
def parse(self, response):
logger.info('parse():')
・・・
def lambda_handler(event, context):
process = CrawlerProcess({
'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
})
process.crawl(MySpider)
process.start() # the script will block here until the crawling is finished
初回実行は問題なし。2回実行すると次のようなエラーが発生。
Response:
{
"errorType": "ReactorNotRestartable",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 77, in lambda_handler\n process.start() # the script will block here until the crawling is finished\n",
Scrapyのサンプルプログラムに書かれているコメント「the script will block here until the crawling is finished」を見るに、クローリングが終了していない扱い?謎
stack overflowなどに投稿されている方がいますが、解決できてない模様。引き続き調査
TOP