用Python写爬虫的常见陷阱与避坑指南

发布时间:2026/7/5 13:16:01

用Python写爬虫的常见陷阱与避坑指南 你写了一个爬虫兴冲冲地运行却只得到一堆空白页面或者被网站封了IP。这不是你的代码有问题而是你踩入了常见的陷阱。爬虫世界看似简单——只要requests.get加BeautifulSoup就能搞定但真实场景里藏着无数坑从请求头缺失到动态渲染从反爬策略到法律红线每一步都可能让你的爬虫“暴毙”。本文不讨论基础语法只专注那些真正让你熬夜debug的坑以及如何优雅避开。请求头伪装被一眼识破的“裸奔”很多新手爬虫的请求头就一个User-Agent甚至默认的python-requests/2.x都没改。你这是在告诉网站“快来封我我是一个机器人。”服务器通过User-Agent、Referer、Accept-Language等数十个字段来区分人与机器缺一个都可能触发反爬。避坑指南建一个请求头池随机切换。不仅要换UA还要带上Referer模仿从搜索引擎点击过来、Accept-Encoding支持gzip、Cookie如果登录态需要。使用fake_useragent库生成真实浏览器UA但别直接用random.choice(fake_useragent)因为某些库的生成列表陈旧且集中。更好的做法是手动收集20个主流浏览器UA存成列表轮换。另外某些网站会检查Sec-Fetch-相关头比如Sec-Fetch-Site: none对cross-site请求放行率不同用浏览器开发者工具抓一个真实请求逐字段复制。动态加载内容你看到的不是HTML用requests爬到的页面和浏览器看到的可能完全两码事。现代网站大量使用JavaScript渲染数据通过XHR或Fetch异步获取。你辛苦写解析器解析到的只是骨架核心数据躺在API里。避坑指南三步走。第一步打开浏览器开发者工具Network面板刷新页面筛选XHR/Fetch请求寻找返回JSON数据的接口。很多时候直接调API比渲染页面快10倍。第二步如果数据必须从渲染后DOM中拿比如某些图表库渲染考虑使用无头浏览器如Selenium或Playwright。千万别一上来就上Selenium它慢且容易被检测。Playwright支持更精细的浏览器指纹控制。第三步分析API的参数签名许多网站对参数做哈希或加时间戳校验如知乎的x-zse-96。你需要逆向前端JS逻辑或者用pyexecjs运行还原后的签名函数。频率控制与IP封锁莽撞的代价不加延时直接循环请求99%的网站会在几十个请求后给你返回403或验证码。更严重的是你的公网IP可能被永久拉入黑名单影响其他正常上网。避坑指南使用指数退避策略失败后休眠时间递增1秒、2秒、4秒、8秒...最大上限比如60秒。用time.sleep(random.uniform(1,3))随机化间隔防止规律性访问。如果必须大规模爬取购买高质量代理池不是免费透明代理检查代理的匿名级别透明代理会在X-Forwarded-For透露真实IP匿名代理隐藏但会添加特定头高匿代理完全不暴露。代理池要维护动态白名单连续返回503的代理迅速剔除。另外使用requests的Session复用连接别每次新建TCP减少连接建立导致的流量特征。编码与字符处理中文变成乱码requests自动猜测编码有时不靠谱尤其当网页声明charset与实际不符时。你拿到一段\u2019或½的乱码然后尝试各种decode浪费大量时间。避坑指南强制指定编码。response.content拿到原始字节用chardet检测实际编码再用.decode(detected_encoding)转换成字符串避免依赖response.encoding。对于HTML页面可以从meta标签中解析charset但很多网站meta不起作用比如某些用UTF-8却声明gb2312。保险做法是先用response.apparent_encoding获取最可能的编码若返回结果仍有乱码尝试常用的utf-8、gbk、gb2312、shift-jis等。对于JSON响应requests会自动处理但如果你自己从网页JavaScript变量中提取JSON字符串务必用json.loads前先repr()查看是否有非法转义。数据解析XPath/CSS选择器的脆弱性用BeautifulSoup的find_all(div, class_content)一次性解析过几天网站改版class名称变成content__new你的爬虫直接废掉。依赖页面结构的选择器极其脆弱尤其当网站采用前端框架动态生成类名时。避坑指南优先使用CSS选择器的属性值匹配比如a[href/detail/]通过URL模式定位比依赖class更稳定。对于经常变化的文本提取父容器后再用正则匹配特定模式如价格“¥\d.\d{2}”。建立数据校验与容错机制每个字段提取后检查是否为None若是则用默认值或告警日志。使用parser库如lxml比BeautifulSoup快很多但lxml对不规范的HTML容错性较差可以先尝试用html5lib解析再转成lxml树。对于表单数据不要用正则匹配所有选项先用浏览器提取典型内容编写容错分支。异常处理脚本因一个错误而崩溃网络波动、服务器返回500、连接超时、SSL证书错误……爬虫运行时间越长异常种类越多。最常见的错误是只捕获Exception并打印然后继续循环导致后续请求全部失败而不自知。避坑指南精细区分异常类型并制定恢复策略。比如ConnectionError重试3次Timeout立即换代理重试HTTPError中403直接休眠更久444连接断开重建session。使用tenacity或retrying库实现重试装饰器指定stop_max_attempt_number5, wait_exponential_multiplier2。同时记录详细的请求信息URL、时间、代理IP到日志文件方便事后排查。注意requests的timeout参数必须设置不设可能被网站拖死建立连接后不返回数据。设置(connect, read)两个超时值比如(3, 10)。验证码与滑动验证人类特有的门槛任何频率控制不完善的爬虫迟早会遇到验证码。从简单的图片识别到酷炫的滑动拼图甚至无感行为验证。很多爬虫死于验证码原因是太依赖自动打码服务或模拟浏览器忽略了行为真实性的模拟。避坑指南尽量绕开验证码。分析触发条件是否因为同一IP短时间内大量请求同一频道如果是降低频率、使用不同路径跳转、随机化点击间隔。对于滑块验证不要用固定像素平移需要模拟人类手拖动的随机加速度曲线开始慢、中间快、结尾微调。使用selenium的ActionChains或Playwright的mouse.move加上贝塞尔曲线轨迹。图片验证码可以接入第三方打码平台如超级鹰、图鉴但成本高且有延迟。终极方案是使用云服务商提供的指纹浏览器真人代理比如使用puppeteer-extra-plugin-stealth伪装全浏览器特征但维护成本高。编码与反爬升级对抗永无止境网站工程师也在进化。除了上述策略还有字体反爬将数字显示为自定义字体映射、CSS偏移文字用层叠覆盖打乱顺序、文本图片化直接截图、点击流分析监控鼠标轨迹与JS事件。你永远无法100%模拟真实用户因为浏览器也存在细微特征WebGL指纹、Canvas指纹、时区差异。避坑指南优先选择提供开放API或RSS的网站合法合规。对于必须要爬的动态反爬采用浏览器自动化开发者工具注入用Playwright打开页面在page.evaluate中修改window.navigator.webdriver标志位覆盖navigator.plugins个数删除navigator.languages中的常量。使用undetected-chromedriver专门绕过WebDriver检测。另外避免爬取高价值核心数据如实时行情、绝版资源这类网站反爬投入巨大一次突破可能很快被补上。数据存储与去重爬虫越写越大数据越来越乱爬取量上去后多线程/异步并发写入数据库出现重复、死锁、数据不一致。忘记设置唯一索引导致几十万条重复记录后期清洗成本远超爬取成本。避坑指南存储前必须去重。简单爬虫用set缓存URL指纹对URL做MD5但内存有限。大规模爬虫使用Redis或BloomFilterRedis的SADD操作原子性BloomFilter用pybloom_live库实现误判率设置0.1%。写入数据库时使用ON DUPLICATE KEY UPDATEMySQL或INSERT IGNORE避免先查后写。对于文件存储如CSV、JSONLines禁止追加写入的方式用批处理写入并在写入前检查该行是否已存在低效但保险。另外注意文件编码统一用UTF-8Windows默认编码可能写入乱码。法律法规与道德爬虫最大的陷阱不是技术你可能会踩到《网络安全法》《数据安全法》《个人信息保护法》的红线。即使技术再完美未经授权爬取个人隐私、商业机密、受版权保护的内容都可能面临法律诉讼甚至刑事责任。避坑指南爬取前先读robots.txt遵守Disallow规则是基本礼貌虽然它无法律强制力但法院会参考。不爬取需要登录才能访问的页面除非获得授权。不爬取个人邮箱、手机号、身份证等敏感信息。如果爬取公开数据用于学术研究或非商业用途注意控制爬取频次不要对服务器造成负担。存储数据时对个人标识做脱敏哈希处理。最后保留请求日志和响应数据万一被投诉可以证明你的爬虫行为合理合法。不要抱有侥幸心理——国内已有爬虫开发被判刑的案例如“爬虫抓取简历”案。异步与并发多线程不是万能药初学爬虫用threading或者multiprocessing跑结果发现目标网站限制了并行连接数或者GIL导致CPU密集型解析效率低。盲目使用多线程反而会触发反爬阈值造成大量连接超时。避坑指南对于I/O密集型网络请求使用asyncioaiohttp更轻量单线程事件循环处理数千个并发请求。但要注意控制并发数用asyncio.Semaphore限制同时进行的请求数量比如10个。对于CPU密集型解析如解析数千个HTML页面才考虑使用concurrent.futures.ProcessPoolExecutor利用多核加速。无论如何不要将请求和解析混在同一个线程/协程内阻塞等待可以用生产者-消费者模式一个协程负责请求放入队列另一个进程负责解析。另外使用queue.Queue时注意大小限制防止内存爆炸。调试与日志没有日志的爬虫是盲人很多人在开发时用print调试上线后发现出问题不知道哪一步失败。没有日志的爬虫就像在黑暗里开车撞了都不知道撞的啥。避坑指南使用logging模块替代print设置DEBUG级别打印请求详情INFO级别打印批处理进度WARNING级别打印重试次数ERROR级别打印不可恢复的错误。日志输出到文件并轮转RotatingFileHandler按大小或时间分割方便回溯。每个请求记录唯一ID如trace_id以便关联请求和响应。对于异常堆栈捕获后用logger.exception(msg)自动记录traceback。这样你就能在第二天看到日志里“2025-04-06 02:15:33, ERROR - [trace_abc123] 请求xxx超时3次后放弃”的痕迹定位问题只需一秒。最后的忠告保持谦逊与持续学习爬虫技术领域的变化比前端还快。今天有效的反爬绕过技巧明天可能就被补上。你永远不能依赖一个固定的“避坑清单”因为网站也在学习你的行为。好的爬虫开发者总是建立模块化架构请求层、解析层、存储层、监控层分离每一层都能单独升级。每次遇到新坑都把它写成测试用例集成到你的爬虫框架中。另外多阅读开源爬虫框架如Scrapy的源码学习别人如何设计重试、去重、中间件。别做“只写爬虫”的程序员要做理解HTTP协议、浏览器渲染、网络拓扑的工程师。真正的避坑指南不是列出所有陷阱而是教会你如何在每个未知陷阱面前冷静分析、理性应对。

相关新闻