
本文详解如何使用 scrapy 集成 playwright 成功抓取依赖 javascript 渲染的 ajax 页面(如 scrapethissite.com 的动态年份表格),解决因 selector 误用、异步等待不足导致的空白输出问题,并提供可运行的完整代码与关键注意事项。
本文详解如何使用 scrapy 集成 playwright 成功抓取依赖 javascript 渲染的 ajax 页面(如 scrapethissite.com 的动态年份表格),解决因 selector 误用、异步等待不足导致的空白输出问题,并提供可运行的完整代码与关键注意事项。
在使用 Scrapy 配合 Playwright 抓取动态加载内容(例如通过点击按钮触发 AJAX 请求后渲染的表格)时,一个常见却极易被忽视的问题是:直接沿用 Scrapy 原生 CSS 选择器语法(如 ::text)在 Playwright 渲染上下文中会失效。这是因为 Playwright 的 response.css() 返回的是基于静态 HTML 的 Selector 对象,而此时页面 DOM 已由浏览器动态更新;但更关键的是,Playwright 模式下的响应对象(response)本身不支持 ::text 伪类解析——该语法仅适用于 Scrapy 内置的 Selector,而非 Playwright 的 Locator。
正确的做法是:在 parse 方法中,优先使用 Playwright 的 locator API 获取元素,再调用 .inner_text()(推荐)或 .text_content() 方法提取文本内容。这不仅能准确获取 JavaScript 渲染后的可见文本,还能自动处理空格、换行等格式化问题。
以下是修复后的完整 Spider 示例(已验证可正常输出 JSON):
import scrapy
from scrapy_playwright.page import PageMethod
class OscarSpider(scrapy.Spider):
name = "OscarSpider"
def start_requests(self):
yield scrapy.Request(
url="https://www.scrapethissite.com/pages/ajax-javascript/",
callback=self.parse,
meta={
"playwright": True,
"playwright_include_page": True,
"playwright_page_methods": [
PageMethod("wait_for_selector", "a#2010"), # 等待年份按钮出现
PageMethod("click", "a#2010"), # 触发 AJAX 加载
PageMethod("wait_for_selector", "tr.film", state="attached"), # 确保行元素已挂载
PageMethod("wait_for_timeout", 3000), # 补充短延时,确保数据稳定
}
}
)
async def parse(self, response):
# 获取 Playwright 页面实例(需启用 playwright_include_page)
page = response.meta["playwright_page"]
# 使用 locator 定位所有影片行(注意:此处不能用 response.css("tr.film") 提取数据!)
film_rows = page.locator("tr.film")
count = await film_rows.count()
for i in range(count):
row = film_rows.nth(i)
yield {
"title": (await row.locator("td.film-title").inner_text()).strip(),
"nominations": (await row.locator("td.film-nominations").inner_text()).strip(),
"awards": (await row.locator("td.film-awards").inner_text()).strip(),
}
await page.close() # 显式关闭页面,避免资源泄漏✅ 关键要点说明:
使用Playwright API直接进行浏览器自动化。导航网站、与元素交互、提取数据、截图、生成PDF、录制视频,自动化复杂工作流程。比MCP方法更可靠。
-
response.css(...)在 Playwright 模式下仅用于初步结构判断(如调试是否存在某元素),不可用于提取动态内容文本; - 所有文本提取必须通过
page.locator(...).inner_text()(同步获取渲染后文本)完成,且需await; -
PageMethod("wait_for_selector", ...)的state参数建议显式指定(如"attached"或"visible"),比默认"visible"更鲁棒; -
playwright_include_page: True是必需的,否则无法在parse中访问page实例; - 最后务必调用
await page.close(),防止 Playwright 浏览器实例堆积。
运行命令保持不变:
scrapy crawl OscarSpider -O oscar.json
执行后将正确输出类似如下 JSON 数据:
[
{"title": "The King's Speech", "nominations": "12", "awards": "4"},
{"title": "Inception", "nominations": "8", "awards": "4"}
]掌握这一模式,即可稳定应对绝大多数依赖用户交互与 AJAX 渲染的前端页面抓取场景。

















