You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合Scrapy与Selenium爬取网页?为何page_source缺失目标内容?

问题分析:为什么page_source找不到内容但find_element可以?

这种情况大概率是动态内容的渲染时机不匹配导致的:

  • 当你调用driver.get(url)后,浏览器会先加载页面的基础HTML结构(也就是page_source当时返回的内容),但目标内容可能是通过AJAX请求异步获取后,再由JavaScript插入到DOM中的。这时候你立刻获取page_source,异步内容还没加载完成,自然找不到。
  • 而find_element_by_css_selector()方法(注意这个方法在Selenium 4+已经被弃用,推荐用find_element(By.CSS_SELECTOR, ...))会尝试查找元素——如果你的代码执行到这一步时,刚好异步内容已经加载完成,或者Selenium隐式等待(默认是0,但如果之前设置过driver.implicitly_wait(10))生效了,就能成功定位到元素。

另外还有一种小概率情况:目标内容存在于<iframe>标签中,此时page_source是主页面的HTML,而你调用find_element前可能无意中切换到了iframe(不过从你的代码看这种可能性很低)。


如何结合Scrapy与Selenium爬取目标贴吧内容?

要实现Scrapy和Selenium的结合,最优雅的方式是通过自定义下载中间件,让Scrapy在需要时调用Selenium渲染页面,而不是直接在Spider里写Selenium代码。下面针对你提供的贴吧链接给出完整实现步骤:

1. 准备工作

确保你已经安装了所需依赖:

pip install scrapy selenium

同时下载对应版本的ChromeDriver,并确保它在系统PATH中,或者在代码中指定路径。

2. 编写自定义下载中间件

在你的Scrapy项目的middlewares.py中添加以下代码:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from scrapy.http import HtmlResponse
import time

class SeleniumMiddleware:
    def __init__(self):
        # 配置Chrome无头模式,减少资源占用
        chrome_options = Options()
        chrome_options.add_argument("--headless=new")
        chrome_options.add_argument("--disable-gpu")
        chrome_options.add_argument("--no-sandbox")
        chrome_options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36")
        
        self.driver = webdriver.Chrome(options=chrome_options)
        # 设置显式等待超时时间
        self.wait = WebDriverWait(self.driver, 15)

    def process_request(self, request, spider):
        # 只对指定的贴吧请求使用Selenium渲染
        if "tieba.baidu.com/p/" in request.url:
            self.driver.get(request.url)
            # 等待目标元素加载完成(这里对应贴吧楼层的回复内容选择器)
            try:
                self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".d_post_content.j_d_post_content")))
                # 等待页面完全渲染(可选,针对需要滚动加载的内容)
                time.sleep(2)
                # 获取当前渲染后的页面源码
                body = self.driver.page_source
                return HtmlResponse(
                    url=self.driver.current_url,
                    body=body,
                    encoding='utf-8',
                    request=request
                )
            except Exception as e:
                spider.logger.error(f"Selenium渲染失败: {str(e)}")
                return None
        # 其他请求使用默认下载器
        return None

    def __del__(self):
        # 关闭浏览器,释放资源
        self.driver.quit()

3. 启用中间件

在项目的settings.py中,修改DOWNLOADER_MIDDLEWARES配置:

DOWNLOADER_MIDDLEWARES = {
    # 替换成你的项目名
    'your_project_name.middlewares.SeleniumMiddleware': 543,
    # 禁用默认的HttpCompressionMiddleware(可选,避免编码问题)
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': None,
}

4. 编写Spider

在spiders目录下创建tieba_spider.py:

import scrapy

class TiebaSpider(scrapy.Spider):
    name = 'tieba'
    allowed_domains = ['tieba.baidu.com']
    start_urls = ['http://tieba.baidu.com/p/5513911529']

    def parse(self, response):
        # 从渲染后的页面中提取目标内容(红圈中的楼层回复文本)
        posts = response.css(".l_post.j_l_post.l_post_bright")
        for post in posts:
            yield {
                '楼层作者': post.css(".p_author_name::text").get().strip(),
                '回复内容': post.css(".d_post_content.j_d_post_content::text").get().strip(),
                '发布时间': post.css(".tail-info::text").getall()[1] if len(post.css(".tail-info::text").getall())>=2 else None
            }

5. 运行爬虫

在终端执行:

scrapy crawl tieba -o tieba_posts.json

关键注意事项

  • 等待策略:一定要使用显式等待(WebDriverWait)代替固定time.sleep(),这样既保证元素加载完成,又不会浪费不必要的时间。
  • Selenium版本兼容:如果使用Selenium 4+,请确保导入from selenium.webdriver.common.by import By,并使用find_element(By.CSS_SELECTOR, selector)代替旧的find_element_by_css_selector()方法。
  • 反爬处理:贴吧有反爬机制,建议添加合理的User-Agent,必要时可以配置登录后的Cookie来绕过限制。
  • 资源释放:中间件中通过__del__方法关闭浏览器,避免长时间运行导致内存泄漏。

内容的提问来源于stack exchange,提问作者YoarkYANG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:40:15