Scrapy结合Splash发起爬取请求返回空字符串问题咨询
问题修复方案
爬取返回空是三个核心问题导致的,按下面的步骤改就能拿到数据:
- 错误的请求头配置:你代码里写的headers是浏览器加载图片资源时用的请求头,
accept字段声明要拿图片资源、sec-fetch-dest标记请求目标是图片、referer指向CSS文件路径,还带了Splash无法正确处理的HTTP/2伪头:authority,网站会直接把请求判定为异常,不会返回正常的菜谱页面HTML。 - XPath选择器逻辑错误:目标页面的菜谱名称存放在
class包含text-center的div下嵌套的h1标签内,你直接取div的直接文本节点,自然拿不到值。 - 页面等待逻辑不可靠:只设置固定10秒等待,若页面JS渲染速度波动,核心内容还没挂载到DOM树Splash就返回源码,也会导致选择器匹配不到内容。
具体修改步骤
- 先确认
settings.py配置正确,除了scrapy-splash官方文档的1-5步配置,补充核对以下内容:
SPLASH_URL = 'http://localhost:8050' # 确保本地Splash服务正常启动,端口匹配 DOWNLOADER_MIDDLEWARES = { 'scrapy_splash.SplashCookiesMiddleware': 723, 'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810, } SPIDER_MIDDLEWARES = { 'scrapy_splash.SplashDeduplicateArgsMiddleware': 100, } DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter' HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage' # 配置正常的浏览器UA,不要用版本过旧的Chrome79,容易被反爬识别 USER_AGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
- 替换爬虫代码,去掉错误的自定义请求头,改用Lua脚本控制Splash等待指定元素加载完成后再返回源码,同时修正XPath:
import scrapy from scrapy_splash import SplashRequest class CookingSpider(scrapy.Spider): name = 'cooking' # Lua脚本:等菜谱名的h1标签加载完成再返回页面,比固定等待效率更高更稳定 lua_render = """ function main(splash, args) splash:set_user_agent(args.ua) assert(splash:go(args.url)) splash:wait_for_selector('h1', 10) return splash:html() end """ def start_requests(self): url = 'https://akispetretzikis.com/en/recipe/6641/patates-twn-15-wrwn' yield SplashRequest( url=url, callback=self.parse, endpoint='execute', args={ 'lua_source': self.lua_render, 'ua': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } ) def parse(self, response): yield { "name": response.xpath('//div[contains(@class, "text-center")]/h1/text()').get(default='').strip() }
排查提示
- 运行爬虫前必须先启动Splash服务,本地部署直接执行命令
docker run -p 8050:8050 scrapinghub/splash即可。 - 如果调整后还是拿不到数据,先在
parse方法里加with open('test.html', 'w', encoding='utf-8') as f: f.write(response.text)把返回的源码存到本地,看是返回了反爬拦截页、403页面还是空白页,再对应调整参数,不要盲目写选择器。 - 不要直接复制浏览器开发者工具里的全量请求头,尤其是带资源类型标记、HTTP/2伪头的字段,很容易触发反爬。
内容的提问来源于stack exchange,提问作者gkasap
相关产品推荐
相关产品推荐

