
本文详解为何 scrapy 在 shell 中 css 选择器能正常工作、但运行爬虫时却返回空结果——根本原因在于目标网站(stylevana.com)启用了强效 cloudflare 反爬保护,导致常规 http 请求被拦截或返回非真实 html。
本文详解为何 scrapy 在 shell 中 css 选择器能正常工作、但运行爬虫时却返回空结果——根本原因在于目标网站(stylevana.com)启用了强效 cloudflare 反爬保护,导致常规 http 请求被拦截或返回非真实 html。
在使用 Scrapy 抓取 https://www.stylevana.com/en_US/skincare.html 时,开发者常遇到一个典型矛盾现象:在 scrapy shell 中执行 response.css('li.product-item') 能成功提取到多个商品节点,且 .get() 和 .attrib['href'] 均可正常调用;但一旦将相同逻辑写入 Spider 的 parse() 方法并运行完整爬虫,CSV 输出中除 'url' 字段偶有值外,其余字段(如 'name'、'price')几乎全为空。问题并非出在 CSS 选择器语法或循环逻辑本身,而在于请求未通过 Cloudflare 挑战验证。
? 根本原因:Cloudflare 的主动防护机制
Stylevana 网站部署了 Cloudflare 的 CDN + WAF(Web Application Firewall)防护层,其行为特征包括:
- ✅ 使用 Cloudflare DNS(全球多地解析确认)
- ✅ 启用 Cloudflare Proxy/CDN(所有流量经 Cloudflare 中转)
- ❌ 未强制启用 Cloudflare SSL(但不影响防护有效性)
这意味着:
- scrapy shell 默认使用 requests 库发起请求,可能偶然命中未触发挑战的缓存响应(例如本地调试时已存在有效 Cookie 或 IP 未被标记),故 CSS 选择器“看似有效”;
- 正式爬虫运行时,Cloudflare 对批量、无浏览器指纹的请求会返回 503 页面、JS 挑战("Checking your browser...")、或空/精简 HTML,导致 response.css() 实际匹配的是防护页面而非真实商品 DOM。
⚠️ 注意:该防护强度极高,常见绕过方案(如 cloudscraper、selenium + 无头 Chrome、更换 User-Agent/Headers)在此站点均已被验证失效。Cloudflare 已对自动化工具行为建立多维识别模型(TLS 指纹、JS 执行环境、鼠标轨迹、Canvas 渲染等),单纯模拟 HTTP 头部无法持久绕过。
? 代码层面的问题也需同步修正
即使忽略 Cloudflare,原 Spider 存在几处关键错误,会加剧数据丢失:
-
response.css(...).get() 返回单个字符串,无法迭代
products = response.css('li.product-item').get() # ❌ 返回 str,不是 SelectorList for product in products: # ❌ 将遍历字符串每个字符✅ 正确写法应为:
products = response.css('li.product-item') # ✅ 返回 SelectorList for product in products: yield { 'name': product.css('div.product-item-details h2::text').get(), 'price': product.css('div.price-box').get(), 'url': product.css('a').attrib.get('href', ''), } -
分页逻辑存在严重语法错误
next_page_url = f'https://.../?p={page_num}' # ❌ page_num 未定义 for page_num in range(2,875): yield response.follow(next_page_url, callback=self.Parse) # ❌ self.Parse 应为 self.parse(大小写错误)✅ 修正后(仍无法解决 Cloudflare 问题):
for page_num in range(2, 6): # 先限制范围测试 next_url = f"https://www.stylevana.com/en_US/skincare.html?p={page_num}" yield response.follow(next_url, callback=self.parse)
✅ 可行的替代方案建议
鉴于当前技术限制,推荐以下务实路径:
| 方案 | 可行性 | 说明 |
|---|---|---|
| 官方 API 接入 | ★★★★★ | 检查网页 Network 面板,Stylevana 实际通过 AJAX 加载商品(如 /rest/V1/products?searchCriteria[filter_groups][0][filters][0][field]=category_id&...)。优先尝试抓取其 JSON 接口(需处理认证/Referer/CSRF Token) |
| 商业反爬服务(如 Bright Data、ScraperAPI) | ★★★☆☆ | 这些平台内置 Cloudflare 绕过能力,支持自动轮换代理与浏览器指纹,但需付费且需适配请求结构 |
| 合法数据采购或 RSS 订阅 | ★★☆☆☆ | 查看官网是否提供产品数据 Feed、邮件订阅或 Partner API,符合合规采集原则 |
总结
Scrapy 中 CSS 选择器“本地有效、线上失效”的典型陷阱,往往指向前端渲染依赖或服务端防护。对于 Stylevana 这类重度 Cloudflare 防护站点,不应执着于“修复爬虫”,而应转向分析其真实数据加载机制。优先排查 AJAX 接口、验证请求头完整性(X-Requested-With, Referer, Cookie),并始终遵守 robots.txt 与网站 Terms of Service。自动化采集必须以尊重服务端资源与法律边界为前提——技术可行性不等于合规性许可。










