scrapy无法直接抓取ajax瀑布流内容,因其不执行javascript,需模拟xhr接口请求;应分析network中真实ajax请求,提取参数与headers构造scrapy.request,避免使用渲染服务除非必要。

Scrapy本身不执行JavaScript,无法直接抓取Ajax瀑布流内容
Scrapy是纯HTTP协议爬虫,它只下载HTML源码,不会运行页面里的JavaScript。而Ajax瀑布流的数据通常由JS在页面加载后动态请求并渲染,原始HTML里根本不存在这些数据。直接用response.css()或response.xpath()去提取,只会拿到空容器或占位符。
常见错误现象包括:SelectorList为空、提取字段全是None、翻页链接抓不到、列表长度远小于页面显示数量。
- 确认是否为Ajax加载:打开浏览器开发者工具 → Network → 切换到XHR/Fetch标签,滚动页面触发加载,观察是否有新请求发出(如
/api/v1/items?page=2) - 如果存在XHR请求,优先模拟该接口,而不是试图让Scrapy“渲染页面”
- 若接口有签名、时间戳、Referer校验或登录态,需从原始页面中提取关键参数(如
csrf_token、session_id)再构造请求
用Scrapy + Requests手动模拟Ajax接口最稳妥
多数瀑布流背后是RESTful API,结构清晰、参数明确。Scrapy配合scrapy.Request发JSON请求,比引入无头浏览器更轻量、稳定、可调试。
典型使用场景:电商商品瀑布流、新闻列表、评论区分页加载。关键点在于复现请求头和参数。
- 复制浏览器真实请求的
headers(尤其是User-Agent、Referer、X-Requested-With) - 注意URL中的动态参数,比如
offset=20或cursor=abc123,它们往往来自上一页响应的next_cursor字段 - 若接口返回JSON,用
response.json()解析,避免用XPath处理JSON字符串 - 示例:抓取某站瀑布流第2页,假设接口为
https://api.example.com/feed?limit=20&offset=20,可在parse方法中yield新请求:
yield scrapy.Request(
url="https://api.example.com/feed?limit=20&offset=20",
headers={"User-Agent": "Mozilla/5.0...", "X-Requested-With": "XMLHttpRequest"},
callback=self.parse_api
)
需要渲染JS时,用Splash或Playwright替代Scrapy内置机制
仅当Ajax请求逻辑被混淆(如参数由JS加密生成)、或页面依赖大量前端路由跳转时,才考虑接入渲染服务。这不是Scrapy的强项,硬塞会增加维护成本。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
Splash适合简单场景(支持Lua脚本、轻量部署),Playwright更现代但资源占用高。二者都需额外部署服务,并修改Scrapy设置。
- 不要在Scrapy中直接调用
playwright.sync_api.sync_playwright()——会阻塞异步引擎,导致性能崩溃 - 若选Splash,需配置
SPLASH_URL,并在settings.py启用SplashMiddleware,请求改用SplashRequest - Playwright建议单独写脚本导出数据,再交由Scrapy后续清洗,而非混合在同一个爬虫流程里
- 容易踩的坑:
wait_for时间设太短导致元素未加载,或未等待AJAX完成就提取DOM;Splash默认不执行document.addEventListener("DOMContentLoaded")之后的逻辑
滚动触发的瀑布流要模拟分页逻辑,而非真实滚动动作
浏览器滚动只是用户交互方式,后端真正响应的是“请求更多数据”的信号。这个信号通常对应一个API调用,而不是DOM事件本身。
重点不是模拟window.scrollTo(),而是识别分页机制:是基于offset/limit、page/size,还是游标(cursor)、时间戳(since_id)?
- 查看XHR请求的Query String或Request Payload,找变化的字段
- 检查响应体中是否包含下一页标识,如
"has_more": true和"next_cursor": "xyz" - 避免死循环:加
max_pages限制,或当has_more为false时终止递归 - 注意反爬节奏:瀑布流接口常有频率限制,建议在
download_delay基础上,对API请求单独加time.sleep()或使用scrapy.downloadermiddlewares.retry.RetryMiddleware
真正难的不是技术选型,而是逆向分析那个隐藏在JS里的请求构造逻辑——参数怎么来、怎么变、怎么校验。这部分没法自动化,得一行行看Network里的真实请求。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










