使用Pyppeteer抓取Digikala商品页面时返回None或空内容的问题求助
使用Pyppeteer抓取Digikala商品页面时返回None或空内容的问题求助
我完全理解你遇到的这种 frustration——动态渲染的电商页面反爬机制通常很严格,Pyppeteer 看似配置正确但就是拿不到内容的情况确实很头疼。结合你的代码和尝试过的方法,我来帮你一步步排查和解决问题:
1. 核心问题:Digikala 检测到了 Pyppeteer 的自动化特征
Digikala 这类电商平台会通过多种方式识别爬虫,比如检测 window.navigator.webdriver 标志、无头浏览器特征、异常的请求头或浏览器启动参数。你的当前代码没有做任何反检测处理,大概率是被识别为爬虫,直接返回了空内容或者触发了超时。
解决办法:隐藏自动化特征 + 模拟真实浏览器
修改你的 launch 参数和页面配置,添加反检测的关键设置:
a. 调整浏览器启动参数
在 launch 中添加以下 args,绕过常见的自动化检测:
browser = await launch( executablePath=self.chromium_path, headless=True, # 可以先临时设为 False,手动观察页面是否加载正常 args=[ '--no-sandbox', '--disable-setuid-sandbox', '--disable-blink-features=AutomationControlled', # 禁用自动化控制检测 '--disable-dev-shm-usage', # 解决内存不足问题 '--start-maximized', # 模拟窗口最大化 ] )
b. 清除 webdriver 标志
在创建页面后,通过 JS 覆盖 navigator.webdriver 属性,避免被检测:
page = await browser.newPage() # 添加这一段代码隐藏自动化特征 await page.evaluate('''() => { Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) }''')
c. 配置真实的请求头
确保你设置了完整的请求头,至少包含和真实浏览器一致的 User-Agent:
# 可以从你自己的浏览器开发者工具中复制真实的 User-Agent default_headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'Referer': 'https://www.digikala.com/' } if headers: default_headers.update(headers) await page.setExtraHTTPHeaders(default_headers)
2. 优化页面等待逻辑:避免依赖固定 sleep
你的代码里用了 await asyncio.sleep(2),这其实不可靠——页面渲染时间可能因网络波动或反爬机制变长。换成等待关键元素加载完成的方式更稳妥:
# 替换 await asyncio.sleep(2) try: # 等待商品页的核心元素加载(比如你要抓取的标题容器) await page.waitForSelector('h1.text-h5-180', timeout=30000) except TimeoutError: print("关键元素加载超时,可能触发反爬") return None
3. 完善错误排查:捕获所有异常并输出详情
你的当前代码只捕获了 TimeoutError,但可能还有其他错误(比如浏览器启动失败、页面加载被中断)导致 content 为 None。扩大异常捕获范围,打印具体错误信息:
except TimeoutError: print(f'Timeout while loading {url} or waiting for elements') return None except Exception as e: print(f"发生未知错误:{str(e)}") return None
4. 验证 Chromium/Chrome 兼容性
你指定的是 Chrome 而非 Chromium 路径,虽然两者核心一致,但 Pyppeteer 对 Chromium 的兼容性更好。如果问题仍存在,可以尝试:
- 让 Pyppeteer 自动下载兼容版本的 Chromium(去掉
executablePath参数,首次运行会自动下载) - 确认你的 Chrome 版本和 Pyppeteer 版本兼容(比如 Pyppeteer v2.0+ 支持 Chrome 115+)
修改后的完整 fetch_content 方法示例
async def fetch_content(self, url, headers=None): # 默认请求头,可被传入的 headers 覆盖 default_headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Referer': 'https://www.digikala.com/' } if headers: default_headers.update(headers) try: browser = await launch( executablePath=self.chromium_path, headless=True, # 先设为 False 观察页面加载状态 args=[ '--no-sandbox', '--disable-setuid-sandbox', '--disable-blink-features=AutomationControlled', '--disable-dev-shm-usage', '--start-maximized' ] ) page = await browser.newPage() # 隐藏 webdriver 标志 await page.evaluate('''() => { Object.defineProperty(navigator, 'webdriver', { get: () => undefined }) }''') await page.setExtraHTTPHeaders(default_headers) await page.goto(url, {'waitUntil': 'networkidle2', 'timeout': 60000}) # 等待核心元素加载 await page.waitForSelector('h1.text-h5-180', timeout=30000) content = await page.content() await browser.close() return content except TimeoutError: print(f'Timeout while loading {url} or waiting for elements') return None except Exception as e: print(f"Error fetching {url}: {str(e)}") return None
最后一步:手动验证页面状态
把 headless 设为 False,运行代码后观察弹出的 Chrome 窗口:
- 页面是否正常加载?有没有跳转到人机验证页面?
- 控制台有没有报错?有没有资源加载失败的提示?
如果看到验证码,那说明 Digikala 触发了更严格的反爬,这时候可能需要添加代理 IP 或处理验证码逻辑,但大部分情况下,上面的修改已经能绕过基础检测。
内容来源于stack exchange
相关产品推荐
相关产品推荐

