You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Scrapy爬虫部署到AWS Lambda后无法将数据保存至Google BigQuery的问题排查

Scrapy爬虫部署到AWS Lambda后无法将数据保存至Google BigQuery的问题排查

我之前碰到过Scrapy在Lambda环境下管道不生效的类似问题,结合你的代码和场景,咱们一步步拆解可能的原因和解决办法:

1. 首先排查管道初始化的路径问题(最常见的坑)

你的SaveToGBQPipeline初始化时用了相对路径加载密钥文件和.env,但Lambda的工作目录与本地完全不同,很可能导致文件找不到,而Scrapy在管道初始化失败时会默默跳过该管道(不会主动抛出致命错误,除非你开启了DEBUG日志)。

解决办法:

  • 替换相对路径为环境变量存储密钥
    相对路径在Lambda中极易出错,推荐把服务账号密钥的JSON内容直接存在Lambda的环境变量中(比如命名为GBQ_SERVICE_ACCOUNT),然后在管道中直接加载:

    def __init__(self):        
        import json
        service_account_info = json.loads(os.environ['GBQ_SERVICE_ACCOUNT'])
        self.credentials = service_account.Credentials.from_service_account_info(
            service_account_info,
            scopes=["https://www.googleapis.com/auth/bigquery"],
        )
        # 其他初始化代码...
    

    这样完全避免了路径问题,也更安全(不用把密钥文件打包到部署包中)。

  • 如果坚持用文件路径:在Lambda中,你的代码根目录是/var/task/,所以可以直接用绝对路径:

    json_key_path = "/var/task/real-estate-tracker-437718-4857741a8e36.json"
    

    但要确保Docker打包时把这个JSON文件复制到了/var/task/目录下(检查你的Dockerfile的COPY命令是否包含该文件)。

2. 检查Scrapy在Lambda中的执行模式是否完整

Scrapy的CrawlerProcess.start()在本地是阻塞到爬虫全部完成的,但Lambda是事件驱动环境,可能存在爬虫爬完数据后,Lambda进程在管道执行完close_spider前就被销毁的情况(你能看到爬取数据,但管道的批量上传还没执行)。

解决办法:改用CrawlerRunner结合Twisted Reactor

CrawlerRunner更适合非标准环境的异步控制,确保所有爬虫和管道的回调都执行完毕:

from scrapy.crawler import CrawlerRunner
from twisted.internet import reactor

def real_estate_scraper(event, contxt):
    settings = get_project_settings()
    # 开启DEBUG日志,方便排查管道加载问题
    settings['LOG_LEVEL'] = 'DEBUG'
    settings['ITEM_PIPELINES'] =  {
        "real_estate_prices.pipelines.SaveToGBQPipeline": 300,
    }

    runner = CrawlerRunner(settings)

    # 链式调用多个爬虫,确保按顺序执行
    crawl_deferred = runner.crawl(KolejNa19Spider)
    crawl_deferred.addCallback(lambda _: runner.crawl(ModernMokotowSpider))
    crawl_deferred.addCallback(lambda _: runner.crawl(StacjaWolaSpider))
    crawl_deferred.addCallback(lambda _: runner.crawl(Zelazna54Spider))
    
    # 所有爬虫完成后停止Reactor
    crawl_deferred.addBoth(lambda _: reactor.stop())
    reactor.run()

3. 开启详细日志,捕获管道中的隐藏错误

你提到Lambda日志中没有报错,很可能是Scrapy默认日志级别过高,没有捕获到管道初始化或执行时的异常。

解决办法:

  • 在settings中强制开启DEBUG日志(如上一步的代码)。
  • 在管道的关键方法中添加异常捕获和打印:
    class SaveToGBQPipeline(object):
        def __init__(self):        
            try:
                # 你的初始化代码...
                print("GBQ 管道初始化成功")
            except Exception as e:
                print(f"GBQ 管道初始化失败: {str(e)}")
                raise  # 重新抛出异常,让Scrapy记录日志
    
        def process_item(self, item, spider):
            try:
                self.items.append(item)
                print(f"已添加Item到管道: {item.get('title', '未知标题')}")  # 打印Item的唯一标识
                return item
            except Exception as e:
                print(f"处理Item失败: {str(e)}")
                raise
    
        def close_spider(self, spider):      
            try:
                print(f"开始上传{len(self.items)}条数据到GBQ")
                # 你的上传代码...
                print("GBQ 数据上传完成")
            except Exception as e:
                print(f"上传GBQ失败: {str(e)}")
                raise
    
    这样任何异常都会被打印到Lambda日志中,你就能精准定位问题。

4. 验证Lambda的依赖和权限

  • 依赖检查:确保你的requirements.txt包含了所有必要的包:
    scrapy
    google-cloud-bigquery
    pandas
    pandas-gbq
    python-dotenv
    google-auth
    
    用Docker打包时要确保这些依赖都被正确安装到Lambda的任务目录中。
  • 权限检查:如果用服务账号密钥,确保该账号有BigQuery的dataEditor权限,能向目标表写入数据;如果用Lambda执行角色,要给角色添加BigQuery Data Editor的IAM权限。

5. 检查Scrapy管道的注册是否正确

确认real_estate_prices.pipelines.SaveToGBQPipeline这个路径在Lambda环境中是有效的:

  • 你的real_estate_prices包必须在Lambda的Python路径中(即/var/task/real_estate_prices/存在)。
  • 确保pipelines.py中确实定义了SaveToGBQPipeline类,没有拼写错误。

按以上步骤逐一排查,应该就能找到管道不执行的原因了!

备注:内容来源于stack exchange,提问作者KurczakChrupiacy2

火山引擎 最新活动