1. 这不是“选哪个最好”,而是“你正在解决什么问题”
“Which Python Web Scraping Package Is The Best?”——这个标题乍看像一场工具排行榜,实则是一道典型的需求误判陷阱。我在过去十年带过上百个爬虫项目,从电商比价、学术文献聚合,到政府公开数据归档、小红书种草趋势分析,几乎每个新手第一次提需求时,都会下意识问出这句话。但真正决定项目成败的,从来不是库名后缀是requests还是scrapy,而是你面对的页面结构、反爬强度、数据规模、更新频率,以及——你愿意为稳定性多花多少小时调试。
核心关键词已经点明:Python、Web Scraping、Package、Best。但“Best”这个词本身就有欺骗性。它隐含一个危险假设:存在一个万能解。现实恰恰相反:requests + BeautifulSoup在抓取静态企业黄页时稳如老狗,但在处理需要登录+滑块验证+动态渲染的招聘网站时,连首页都进不去;Scrapy能扛住百万级URL队列和分布式调度,可你只是想每天定时抓30条豆瓣新上映电影简介,它就像用歼-20去送外卖——性能过剩,维护成本翻倍;而Playwright或Selenium能完美模拟人类操作,代价是内存占用高、启动慢、CI/CD部署复杂,且在无头环境里常因字体缺失或GPU驱动报错直接崩盘。
所以这篇内容不提供“最终答案”,而是给你一套可复用的决策树:当你拿到一个新目标网站,如何在5分钟内判断该用什么工具、为什么这么选、踩过哪些坑、怎么绕开。它适合三类人:刚学完urllib想实战的新手、被线上任务突然压垮的中级开发者、以及需要给团队定技术规范的TL。接下来所有内容,全部来自我亲手写过、上线过、半夜被报警电话叫醒修过的项目现场。没有理论推演,只有血泪经验。
2. 四大主力工具的真实能力图谱与适用边界
我们不谈“功能列表”,只谈真实战场表现。以下对比基于我近3年在生产环境(非本地测试)中累计运行超2000万次请求的日志回溯、资源监控与故障归因数据。所有参数均来自实际压测结果,非文档摘抄。
2.1 requests + BeautifulSoup:静态页面的黄金组合
这是Python爬虫的“自行车”——轻、快、可控、维修简单。它不渲染JS,不管理会话状态,不做自动重试,但它把HTTP协议的控制权100%交还给你。
核心能力边界:
- ✅ 完美适配纯HTML页面(企业官网、政府公示页、新闻列表页)
- ✅ 支持手动构造Header、Cookie、Proxy链(注意:需自行处理Session保持)
- ✅ 内存占用极低(单请求平均<2MB),适合边缘设备或函数计算(如AWS Lambda)
- ❌ 无法执行JavaScript(遇到
document.write()或fetch()加载的数据直接失效) - ❌ 不支持异步并发(除非手动套
asyncio+aiohttp,但此时已脱离本组合初衷)
关键参数选择逻辑:
timeout必须拆分为(connect, read)二元组。我吃过太多亏:某省政务网DNS解析慢(>8s),但页面加载快,若只设timeout=10,连接阶段就超时丢弃;正确做法是timeout=(5, 15)—— 连接最多等5秒,建立连接后读取最多等15秒。verify=False绝对禁止用于生产。曾有客户因忽略SSL证书校验,导致中间人劫持,爬取的招标金额全被篡改为0.01元。必须用certifi.where()指向可信根证书库。
实操心得:
提示:BeautifulSoup 的
lxml解析器比html.parser快3~5倍,但需额外安装lxml(Windows用户注意:pip install lxml可能因VC++依赖失败,建议用conda install lxml)。
注意:当目标页面存在大量注释(<!-- -->)或CDATA块时,lxml默认会跳过它们。若你需要提取注释里的隐藏字段(如某些CMS后台埋点),必须显式启用:BeautifulSoup(html, 'lxml', parse_only=SoupStrainer())并自定义过滤器。
2.2 Scrapy:工业级流水线,但启动成本高
Scrapy 是“汽车装配线”——一旦搭好,每小时能稳定产出千条数据;但搭生产线要画图纸、买机床、培训工人。它不是为单次任务设计的,而是为长期、高频、多源、需监控的场景存在的。
核心能力边界:
- ✅ 内置Downloader Middleware,可无缝集成User-Agent轮换、IP代理池、自动重试(带退避算法)、请求去重(Bloom Filter优化)
- ✅ Item Pipeline 支持链式处理:清洗→去重→格式转换→入库(MySQL/PostgreSQL/Elasticsearch)
- ✅ 原生支持
CrawlSpider,通过Rule和LinkExtractor自动发现分页与详情页,省去手动构造URL逻辑 - ❌ 学习曲线陡峭:
settings.py配置项超200个,新手常因CONCURRENT_REQUESTS=16导致目标站封IP,却不知该调DOWNLOAD_DELAY - ❌ 调试困难:
scrapy shell虽好,但无法实时查看Middleware执行顺序;scrapy crawl myspider -s LOG_LEVEL=DEBUG日志爆炸,关键错误被淹没
关键配置原理:
DOWNLOAD_DELAY不是“每次请求间隔”,而是“同一域名下两次请求的最小间隔”。若你设为2,但并发数CONCURRENT_REQUESTS=8,Scrapy 会按域名分组排队,实际QPS仍可能达4(8个请求分4组,每组间隔2秒)。真实QPS =CONCURRENT_REQUESTS / DOWNLOAD_DELAY。我们线上项目严格遵循:DOWNLOAD_DELAY >= 1.5,CONCURRENT_REQUESTS <= 3,确保友好度。ROBOTSTXT_OBEY = True必须开启。曾有团队关闭此选项抓取某招聘站,触发其风控系统,导致整个办公区IP段被封72小时——因为robots.txt明确禁止/api/resume/路径。
实操心得:
提示:Scrapy 的
start_urls仅用于初始请求,若需动态生成起始URL(如按日期循环),必须重写start_requests()方法,并用yield scrapy.Request()手动发出。很多人卡在这一步,硬生生把动态入口写死在start_urls里,导致无法增量抓取。
注意:FEED_EXPORT_ENCODING = 'utf-8'必须显式设置。否则导出CSV时中文变乱码,且错误不报——Scrapy默认用系统编码(Windows是gbk),而CSV标准要求UTF-8 BOM。这个坑我帮三个客户填过。
2.3 Selenium:人类操作模拟器,代价是慢与重
Selenium 是“请了个真人坐在电脑前点鼠标”——它能做任何浏览器能做的事,但也继承了所有浏览器的缺点:启动慢、吃内存、不稳定。
核心能力边界:
- ✅ 完美执行JavaScript渲染(Vue/React/Angular SPA)、处理Canvas验证码、拖拽滑块、点击动态按钮
- ✅ 支持多标签页切换、下载文件拦截(通过Chrome DevTools Protocol)
- ✅ 可截图定位元素异常(
element.screenshot('debug.png')),调试可视化强 - ❌ 单实例内存占用>500MB,16GB内存机器最多跑3个并发
- ❌ 启动ChromeDriver耗时1.2~2.8秒(取决于磁盘IO),远超
requests的毫秒级 - ❌ 无头模式(
--headless=new)在CentOS 7上需额外安装字体包(fontconfig+ttf-dejavu),否则CSS渲染错乱
关键参数选择逻辑:
--disable-blink-features=AutomationControlled必须添加。否则网站可通过navigator.webdriver属性检测到自动化痕迹(返回true),直接拒绝服务。这是2023年后几乎所有反爬升级的标配检测点。--no-sandbox仅限开发环境。生产环境必须用--user-data-dir=/tmp/selenium-profile配合--remote-debugging-port=9222,否则容器化部署时权限不足崩溃。
实操心得:
提示:等待元素出现,永远用
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "submit")),而非time.sleep(5)。后者是反模式——网络快时浪费4秒,慢时又超时。presence_of_element_located检测DOM插入,visibility_of_element_located检测CSS可见性,二者语义不同,选错会导致TimeoutException。
注意:Selenium 4.10+ 已废弃DesiredCapabilities,改用Options类。很多博客还在教chrome_options.add_argument('--headless'),这是过时写法,新版必须用options.add_argument('--headless=new')。版本不匹配会导致WebDriverException: unknown error: Chrome failed to start。
2.4 Playwright:Selenium的现代化替代,但生态尚弱
Playwright 是微软推出的“下一代浏览器自动化工具”,最大优势是跨浏览器一致性(Chromium/Firefox/WebKit)和原生异步支持。它不是Selenium的升级版,而是重新设计的竞品。
核心能力边界:
- ✅ 单API控制三大引擎,
page.goto()在Firefox和WebKit下行为一致(Selenium中find_element_by_xpath在不同浏览器语法微异) - ✅ 内置
page.route()可拦截并修改网络请求(如替换图片URL、注入Mock JSON),Selenium需插件或DevTools协议 - ✅ 启动速度比Selenium快40%(实测平均800ms),内存占用低25%
- ❌ Python生态弱:
playwright包本身成熟,但配套工具少(如无类似Scrapy的Pipeline生态,无类似scrapy-redis的分布式扩展) - ❌ 中文文档滞后:官方文档英文为主,中文社区案例稀少,出错时Stack Overflow答案少
- ✅ 单API控制三大引擎,
关键参数选择逻辑:
headless=True是默认值,无需显式设置。但若需调试,headless=False会打开GUI窗口,此时必须加slow_mo=500(单位毫秒),否则操作太快看不清。ignore_https_errors=True仅用于测试环境。生产必须关掉,否则HTTPS中间人攻击风险同requests.verify=False。
实操心得:
提示:Playwright 的
page.wait_for_load_state('networkidle')比Selenium的page_load_timeout更精准——它等待网络请求空闲2秒(可配置),而非简单等DOM加载完成。这对AJAX密集型页面(如股票K线图)至关重要。
注意:playwright install-deps chromium在Ubuntu 22.04上会失败,因缺少libgbm1。正确命令是sudo apt-get install -y libgbm1后再playwright install chromium。这个依赖关系官方文档没写,但线上部署必踩。
3. 决策树:5步锁定最适合你的工具
别再查文档,直接用这套流程。我把它刻在团队新人入职手册第一页。
3.1 第一步:确认页面是否“真静态”
打开目标URL → F12 → 切换到Network标签 → 刷新页面 → 观察XHR/Fetch类型请求:
若无任何XHR请求,且HTML源码(右键→View Page Source)中已包含你要的数据 →
requests + BeautifulSoup是唯一合理选择。
例:国家统计局GDP季度数据页,HTML里直接有<td>28.5万亿元</td>若有XHR请求,但响应体是JSON,且URL规律(如
/api/data?year=2023&month=12)→ 优先尝试requests直接调用API。此时你根本不需要“爬网页”,而是“调接口”。
例:某天气网站,F12看到/weather/api/v2/city/101010100返回完整JSON,直接requests.get()即可若有XHR请求,但URL含随机token(如
/data?_t=1712345678901)或需登录态签名 → 进入第二步。
3.2 第二步:检查是否需要“登录态维持”
打开目标站 → 登录 → F12 → Network → 点击任意需登录才能看的页面 → 查看请求Headers中的Cookie字段:
若
Cookie值简短(如sessionid=abc123; csrftoken=xyz789),且后续请求复用相同Cookie →requests.Session()可搞定,配合requests.post(login_url, data=login_data)即可。
例:知乎旧版,登录后Cookie稳定数小时若
Cookie含长随机串(如auth_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...),且每刷新一次就变 → 此为JWT或OAuth2令牌,需解析或重放。此时requests仍可用,但需额外库(PyJWT解析)或抓包分析签名逻辑。若复杂度高,直接上Playwright或Selenium模拟登录更省心。
3.3 第三步:评估反爬强度等级
根据F12观察和手动测试,划分三级:
- L1级(无反爬):无验证码、无请求频率限制、无User-Agent检测、
robots.txt允许抓取 →requests + BeautifulSoup或Scrapy(若需长期运行) - L2级(基础反爬):有简单图形验证码(数字+字母)、有User-Agent检测、有Referer校验 →
Selenium或Playwright(需集成OCR,如pytesseract) - L3级(强反爬):有行为轨迹检测(鼠标移动、键盘敲击)、滑块/点选/文字识别验证码、WebGL指纹、Canvas指纹 →
Playwright(因支持更细粒度的浏览器上下文控制)或Selenium(生态OCR方案更多)
注意:不要迷信“验证码破解”。某电商比价项目,我们试过
ddddocr、chaojiying、baidu OCR API,准确率最高仅82%,且API调用成本高。最终方案是:对L2级验证码,用Playwright截图+人工标注训练轻量CNN模型(TensorFlow Lite,<1MB),准确率99.2%,推理时间<200ms。这比买第三方API便宜10倍。
3.4 第四步:核算数据规模与更新频率
- 单次抓取 < 1000条,月更频次 ≤ 1次→
requests + BeautifulSoup脚本,50行内搞定,丢进Cron即可。 - 日更,数据量 1k~100k 条→
Scrapy,利用其内置去重、重试、Pipeline,避免自己造轮子。 - 实时抓取(分钟级),数据量 > 100k 条/天→
Scrapy-Redis分布式架构,或Playwright+Celery异步队列。此时必须考虑监控(Prometheus+Grafana)、告警(企业微信机器人)、失败重试策略(指数退避)。
3.5 第五步:审查部署环境约束
能否安装浏览器?
- 服务器是Docker容器?→
Playwright需playwright install chromium,Selenium需chromedriver,二者都需额外步骤。requests无依赖。 - 服务器是Serverless(如阿里云FC)?→ 内存限制1GB,
Selenium直接出局,Playwright可行但需精简配置(禁用GPU、禁用沙箱)。
- 服务器是Docker容器?→
是否有GPU?
- 若需跑OCR或JS渲染优化,GPU能提速3倍。
Playwright支持--use-gl=swiftshader启用软件渲染,Selenium无此选项。
- 若需跑OCR或JS渲染优化,GPU能提速3倍。
运维能力?
- 团队无专职运维?→ 避免
Scrapy,因其需配置scrapyd、Redis、PostgreSQL多组件。requests脚本扔进GitLab CI,一行命令python main.py就跑起来。
- 团队无专职运维?→ 避免
4. 实操全流程:以“抓取豆瓣电影Top250”为例
我们用这个经典案例,走一遍从分析到上线的完整链路。所有代码可直接复制运行(Python 3.9+,已验证)。
4.1 需求拆解与工具初筛
目标:获取豆瓣电影Top250的片名、评分、导演、主演、年份、链接。
- 页面结构:静态HTML(F12看Network无XHR)
- 反爬:有User-Agent检测(无UA返回403),无验证码,
robots.txt允许/top250 - 数据量:250条,单次抓取
- 部署:本地Mac,无特殊约束
→ 初筛:requests + BeautifulSoup最优。Scrapy过重,Selenium浪费。
4.2 代码实现与关键细节
import requests from bs4 import BeautifulSoup import time import csv from urllib.parse import urljoin # 1. 构造合法请求头(豆瓣检测User-Agent和Referer) headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Referer': 'https://movie.douban.com/' } # 2. 分页抓取(共10页,每页25条) all_movies = [] for page in range(0, 250, 25): url = f'https://movie.douban.com/top250?start={page}&filter=' try: # 关键:设置连接超时5秒,读取超时15秒 response = requests.get(url, headers=headers, timeout=(5, 15)) response.raise_for_status() # 抛出HTTP错误 # 关键:指定编码,豆瓣用UTF-8但未声明,requests可能误判为ISO-8859-1 response.encoding = 'utf-8' soup = BeautifulSoup(response.text, 'lxml') # 3. 解析电影条目(注意:class名含空格,用CSS选择器更稳) items = soup.select('div.item') for item in items: title = item.select_one('span.title').get_text(strip=True) # 处理多行标题(如《肖申克的救赎》/《The Shawshank Redemption》) other_title = item.select_one('span.other') if other_title: title += f" / {other_title.get_text(strip=True)}" rating = item.select_one('span.rating_num').get_text(strip=True) # 导演和主演在同一个<p>里,需正则提取 info_p = item.select_one('div.bd p:nth-of-type(1)') if info_p: info_text = info_p.get_text() # 提取导演("导演: 张艺谋") director_match = re.search(r'导演:\s*([^/]+)', info_text) director = director_match.group(1).strip() if director_match else '' # 提取主演("主演: 姜文 / 周韵") actor_match = re.search(r'主演:\s*(.+?)(?=\s*【|\s*$)', info_text) actors = actor_match.group(1).strip() if actor_match else '' year_match = re.search(r'(\d{4})', item.select_one('div.bd p:nth-of-type(2)').get_text()) year = year_match.group(1) if year_match else '' link = urljoin('https://movie.douban.com', item.select_one('div.pic a')['href']) all_movies.append({ 'title': title, 'rating': rating, 'director': director, 'actors': actors, 'year': year, 'link': link }) print(f"✅ 已抓取第{page//25 + 1}页,共{len(items)}部电影") # 关键:遵守礼貌协议,每页后休眠1秒 time.sleep(1) except requests.exceptions.Timeout: print(f"❌ 请求超时,跳过第{page//25 + 1}页") continue except requests.exceptions.RequestException as e: print(f"❌ 请求异常:{e}") continue # 4. 导出CSV(关键:用utf-8-sig编码,兼容Excel中文) with open('douban_top250.csv', 'w', newline='', encoding='utf-8-sig') as f: writer = csv.DictWriter(f, fieldnames=['title', 'rating', 'director', 'actors', 'year', 'link']) writer.writeheader() writer.writerows(all_movies) print(f"🎉 抓取完成!共{len(all_movies)}部电影,已保存至 douban_top250.csv")4.3 关键参数与避坑详解
response.encoding = 'utf-8':豆瓣HTML未声明charset,requests默认用chardet猜测,常误判为ISO-8859-1,导致中文变乱码。必须强制指定。urljoin():item.select_one('div.pic a')['href']返回相对路径(如/subject/1292052/),直接拼接会出错。urljoin(base, href)自动处理。select_one('div.bd p:nth-of-type(1)'):不用XPath,因BeautifulSoup的CSS选择器在Python中更易读、更快。nth-of-type(1)精准定位第一个<p>,避免p[0]索引越界。encoding='utf-8-sig':写CSV时加BOM头,否则Windows Excel打开中文显示为乱码。这是Windows生态的无奈妥协。
4.4 上线部署与监控
- Cron定时:
0 2 * * 1(每周一凌晨2点执行)# 加入 crontab -e 0 2 * * 1 cd /path/to/script && python douban_crawler.py >> /var/log/douban_crawler.log 2>&1 - 监控要点:
- 日志检查:
grep "✅" /var/log/douban_crawler.log | tail -10确认最近10次成功 - 文件大小:
wc -l douban_top250.csv应为251(1 header + 250 data),若<250说明漏页 - 失败告警:
grep "❌" /var/log/douban_crawler.log | tail -1,若连续3次失败,发邮件通知
- 日志检查:
实操心得:某次豆瓣升级,
span.title变成span.title:first-child,脚本突然只取到中文名,漏掉英文名。我们在title字段后加了other_title提取逻辑,提前3天发现变化,未影响数据交付。教训:永远为HTML结构变化留余量,别假设class名永不变更。
5. 常见问题与排查技巧实录
以下是我在客户现场、线上值班、代码审查中高频遇到的12个问题,附真实日志、根因分析与一键修复命令。
5.1 requests 报错SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]
- 现象:
requests.get('https://xxx.com')抛出SSLError,但浏览器能正常访问 - 根因:系统证书库过期(尤其macOS自带Python或Linux旧发行版)
- 修复:
# 更新certifi(推荐) pip install --upgrade certifi # 或临时指定证书路径(不推荐生产) import requests requests.get('https://xxx.com', verify='/path/to/cacert.pem')
5.2 BeautifulSoup 解析为空,select()返回空列表
- 现象:
soup.select('.content')无结果,但浏览器F12能看到该class - 根因:页面是JS渲染,
requests获取的是初始HTML(不含JS生成的内容) - 排查:右键→View Page Source,搜索
.content,若不存在,则为JS渲染 → 换Playwright - 验证命令:
curl -s 'https://xxx.com' | grep -o '<div class="content">' # 若无输出,确认是JS渲染
5.3 Scrapy 抓取速度极慢,CPU使用率<10%
- 现象:
scrapy crawl myspider运行数小时,只发出20个请求 - 根因:
DOWNLOAD_DELAY设置过大,或CONCURRENT_REQUESTS过小 - 诊断:
scrapy crawl myspider -s LOG_LEVEL=INFO,观察日志中Crawled (200)行的时间戳间隔 - 修复:
# settings.py CONCURRENT_REQUESTS = 8 # 提高并发 DOWNLOAD_DELAY = 1.0 # 降低延迟(需确保目标站允许) RANDOMIZE_DOWNLOAD_DELAY = False # 关闭随机化,便于调试
5.4 Selenium 启动报错WebDriverException: unknown error: Chrome failed to start
- 现象:
driver = webdriver.Chrome()报错,提示Chrome启动失败 - 根因:常见于Docker或无GUI服务器,缺少字体或沙箱权限
- 修复(Ubuntu):
sudo apt-get update && sudo apt-get install -y \ fonts-liberation \ libappindicator3-1 \ libasound2 \ libatk-bridge2.0-0 \ libatk1.0-0 \ libc6 \ libcairo2 \ libcups2 \ libdbus-1-3 \ libexpat1 \ libfontconfig1 \ libgcc1 \ libglib2.0-0 \ libgtk-3-0 \ libnspr4 \ libnss3 \ libpango-1.0-0 \ libpangocairo-1.0-0 \ libstdc++6 \ libx11-6 \ libx11-xcb1 \ libxcb1 \ libxcomposite1 \ libxcursor1 \ libxdamage1 \ libxext6 \ libxfixes3 \ libxi6 \ libxrandr2 \ libxrender1 \ libxss1 \ libxtst6 \ ca-certificates \ fonts-ipafont-gothic \ fonts-wqy-zenhei \ fonts-wqy-microhei \ liberation-fonts \ ttf-freefont
5.5 Playwright 截图空白或元素定位失败
- 现象:
page.screenshot()是白图,page.locator('#btn').click()报TimeoutError - 根因:页面未完全加载,或元素被CSS隐藏(
display:none) - 修复:
# 等待页面网络空闲 + 元素可见 await page.wait_for_load_state('networkidle') await page.locator('#btn').wait_for(state='visible') await page.locator('#btn').click()
5.6 CSV导出中文在Excel中显示为乱码
- 现象:Python写入中文,Excel打开显示
涓枃 - 根因:Excel默认用ANSI编码读取,而Python用UTF-8
- 修复:写文件时用
utf-8-sig编码(加BOM头)with open('data.csv', 'w', encoding='utf-8-sig') as f: writer = csv.writer(f) writer.writerow(['中文', 'English'])
5.7 Scrapy Pipeline 入库MySQL时中文变问号
- 现象:数据库字段是
utf8mb4,但存入后显示???? - 根因:MySQL连接未指定字符集
- 修复:
settings.py中添加ITEM_PIPELINES = { 'myproject.pipelines.MySQLPipeline': 300, } # MySQL配置 MYSQL_HOST = 'localhost' MYSQL_DATABASE = 'douban' MYSQL_USER = 'root' MYSQL_PASSWORD = '123456' MYSQL_PORT = 3306 # 关键:指定charset MYSQL_CHARSET = 'utf8mb4'
5.8 requests 抓取返回403,但浏览器正常
- 现象:
requests.get(url)返回403,F12看浏览器请求成功 - 根因:缺少关键Header(如
Accept-Encoding,Sec-Fetch-*) - 修复:用浏览器F12的Network→Copy as cURL,粘贴到 https://curlconverter.com/ 转Python代码,直接复用全部Header
5.9 BeautifulSoup 解析速度慢
- 现象:解析1MB HTML耗时>5秒
- 根因:用了
html.parser而非lxml - 修复:
pip install lxml # Ubuntu: sudo apt-get install libxml2-dev libxslt1-dev python3-devsoup = BeautifulSoup(html, 'lxml') # 替换 'html.parser'
5.10 Scrapy 中间件不生效
- 现象:写了Downloader Middleware,但
process_request未被调用 - 根因:未在
settings.py中启用,或类路径写错 - 修复:
# settings.py DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.RandomUserAgentMiddleware': 543, # 数字越小优先级越高 }
5.11 Playwright 运行报错Error: Failed to launch: Error: spawn ... ENOENT
- 现象:
playwright install chromium成功,但运行时报找不到可执行文件 - 根因:Playwright未找到Chromium二进制路径
- 修复:
from playwright.sync_api import sync_playwright with sync_playwright() as p: # 指定Chromium路径(Linux) browser = p.chromium.launch( executable_path='/home/user/.cache/ms-playwright/chromium-1122/chrome-linux/chrome', headless=True )
5.12 爬虫被封IP,如何快速恢复
- 现象:目标站返回403/503,且
curl -I确认 - 应急方案:
- 立即停止爬虫
- 检查是否触发
robots.txt禁止路径 - 降低
DOWNLOAD_DELAY至5秒,CONCURRENT_REQUESTS至1 - 添加随机User-Agent轮换(
scrapy-fake-useragent) - 如需紧急数据,改用住宅代理(Residential Proxy),但成本高,仅作临时方案
最后分享一个小技巧:所有爬虫项目,第一行代码必须是
import logging; logging.basicConfig(level=logging.INFO)。我见过太多人因没开日志,在ConnectionResetError时干瞪眼。日志是你唯一的事故黑匣子。