Scrapy+Splash:爬取动态渲染的 JavaScript 页面

当网页内容通过 JavaScript 动态渲染时,传统爬虫无法直接获取完整数据。Scrapy(Python 爬虫框架)结合 Splash(JavaScript 渲染服务)可解决此问题。以下是完整实现流程:


1. 核心原理
  • Scrapy:负责爬虫逻辑、请求调度和数据提取
  • Splash:作为轻量级浏览器渲染引擎,执行 JavaScript 并返回渲染后的 HTML
  • 交互流程
    graph LR
    A[Scrapy] -->|发送渲染请求| B[Splash]
    B -->|执行JS渲染| C[目标网站]
    C -->|返回完整HTML| B
    B -->|返回渲染结果| A
    


2. 环境配置
(1) 安装 Splash 服务
# 通过 Docker 运行 Splash
docker run -p 8050:8050 scrapinghub/splash

(2) 安装 Scrapy 依赖
pip install scrapy scrapy-splash

(3) Scrapy 配置 (settings.py)
# 启用 Splash 中间件
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashMiddleware': 725
}

# 设置 Splash 服务地址
SPLASH_URL = 'http://localhost:8050'

# 添加去重过滤器
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'


3. 爬虫实现
(1) 创建 Splash 请求
import scrapy
from scrapy_splash import SplashRequest

class DynamicSpider(scrapy.Spider):
    name = 'js_spider'
    
    def start_requests(self):
        url = 'https://example.com/dynamic-page'
        yield SplashRequest(
            url,
            callback=self.parse,
            # 关键参数:等待渲染完成
            args={'wait': 2.5},  
            endpoint='render.html'
        )

(2) 处理渲染结果
    def parse(self, response):
        # 提取渲染后的数据
        title = response.css('h1::text').get()
        dynamic_content = response.xpath('//div[@id="dynamic-area"]/text()').get()
        
        yield {
            'title': title,
            'content': dynamic_content
        }


4. 高级渲染控制
(1) 执行自定义 JavaScript
yield SplashRequest(
    url,
    args={
        'lua_source': """
        function main(splash)
            splash:go(splash.args.url)
            splash:wait(1)
            splash:runjs('document.querySelector("button.more").click()')
            splash:wait(2)
            return splash:html()
        end
        """
    }
)

(2) 处理 AJAX 加载
args={
    'wait': 0.5,
    'resource_timeout': 10,  # 资源加载超时时间
    'images': 0,  # 禁用图片加速
}


5. 常见问题解决
问题现象 解决方案
数据加载不全 增加 wait 参数值 (0.5-3秒)
点击事件未触发 使用 runjs 模拟点击操作
内存泄漏 设置 splash:set_viewport_full()
反爬虫检测 添加 splash:set_user_agent()

6. 性能优化建议
  1. 并发控制:在 settings.py 中调整
    CONCURRENT_REQUESTS = 8  # 根据服务器性能调整
    

  2. 缓存复用:启用 Splash 缓存
    args={'wait': 1, 'cache_args': ['lua_source']}
    

  3. 请求过滤:使用 SplashAwareDupeFilter 避免重复渲染

提示:对于复杂 SPA(单页应用),建议结合 scrapy-playwright 方案,但 Splash 在资源消耗和部署便捷性上仍有优势。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐