你的爬虫,需要一个“黑匣子”
想象一下这个场景:你精心编写的爬虫脚本,在本地跑得风生水起,感觉分分钟就能把整个互联网的数据都搬回家。于是你自信满满地把它扔到服务器上,设置好定时任务,安心睡觉。第二天一早,你满怀期待地打开电脑,却发现——数据量为零,脚本不知道在哪个深夜已经悄然崩溃,没留下任何线索。
此时的你,是不是很想穿越回过去,给那个只用 print(“跑到第XX页了…”) 的自己一个大嘴巴子?
“print流派”的三大致命伤:
- 信息转瞬即逝:控制台输出关掉就没了,服务器上你上哪儿看去?
- 泥沙俱下,真假难辨:有用的错误信息和没用的调试信息混在一起,找bug如同大海捞针。
- 性能与灵活性双输:上线后你得一处处去删print语句,万一漏了几个,还会影响程序性能。
而Python标准库里的 logging 模块,就是来解决这些痛点的。它就像飞机上的“黑匣子”,无论程序是平稳飞行还是意外坠毁,它都能忠实地记录下一切关键信息,让你事后可以精准复盘。
第一幕:开箱即用,5分钟上手logging
别怕,logging没那么复杂。咱们先来看看最简单、最“傻瓜式”的用法。
import logging
# 最最最基础的用法
logging.warning(“这是一条警告信息!”)
logging.error(“这是一条错误信息!”)
# 试着运行一下,你会看到:
# WARNING:root:这是一条警告信息!
# ERROR:root:这是一条错误信息!
发现了没?我们没有做任何配置,它就直接工作了。但为什么 logging.info(“这是一条普通信息”) 没有输出呢?
这就引出了logging的核心概念——日志级别。
第二幕:理解日志的“音量旋钮”:级别(Level)
logging模块设定了5个标准级别,按严重性从低到高排列:
- DEBUG:最唠叨的模式,记录一切细节,用于开发阶段调试。
- INFO:正常运行时需要记录的信息,比如“成功连接到数据库”。
- WARNING:表示一些不期望的事情发生了,但程序还在正常运行,比如“磁盘空间不足”。
- ERROR:由于一个更严重的问题,某些功能已经没法正常使用了。
- CRITICAL:最高级别,程序可能要挂了!
默认的“音量旋钮”拧在了 WARNING 位置。 所以,比WARNING级别“轻”的DEBUG和INFO信息,默认就被静音了。
你可以通过一行代码来调整这个“旋钮”:
import logging
logging.basicConfig(level=logging.DEBUG) # 把旋钮拧到最低,让所有信息都“响”起来
logging.debug(“这是最琐碎的调试信息”)
logging.info(“这是一条普通信息”)
logging.warning(“警告!”)
现在,所有级别的信息都会打印出来了。是不是感觉控制力强多了?
第三幕:打造你的专属日志:格式化和输出
默认的输出 WARNING:root:消息 有点丑,而且信息量不够(比如没有时间)。这时候,就该 basicConfig 方法大显身手了。
import logging
logging.basicConfig(
level=logging.INFO,
format=‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’,
datefmt=‘%Y-%m-%d %H:%M:%S’,
filename=‘my_spider.log’, # 日志输出到文件,而不是控制台
filemode=‘a’ # ‘a’是追加模式,‘w’是覆盖模式
)
logging.info(“程序启动啦!”)
# 此时控制台没东西了,但当前目录下会生成一个 my_spider.log 文件
# 里面的内容大概是:2023-10-27 14:35:01 - root - INFO - 程序启动啦!
参数解释:
format:这就是你的日志“美颜滤镜”。
-
% (asctime)s:人类可读的时间。% (name)s:logger的名字(后面高级篇会讲,默认是‘root’)。% (levelname)s:日志级别。% (message)s:你输出的消息。
filename:指定日志文件路径,有了它,日志就不再是“一次性”的了。filemode:和打开文件的模式一样,w会覆盖,a会追加。
到这一步,你已经能解决80%的日志需求了!但作为一个有追求的爬虫工程师,我们还得往深里探一探。
第四幕:高手进阶:Logger,Handler,Filter,Formatter
这才是logging模块的完全体!它采用了“组装式”设计,就像乐高。
- Logger(记录器):就是你代码里打日志的那个接口。你可以创建多个logger,比如一个叫
‘spider’专门记录爬虫逻辑,一个叫‘parser’专门记录解析逻辑。 - Handler(处理器):决定日志该去哪里。是控制台(
StreamHandler)?还是文件(FileHandler)?或者是通过网络发出去?你可以给一个logger添加多个handler。 - Filter(过滤器):提供更精细的规则来决定哪些日志能通过。
- Formatter(格式化器):和上面
basicConfig里的format一样,决定日志的最终输出样式。
为什么要这么复杂? 灵活性!比如,你可以让 spider logger 的 DEBUG 级别信息写入文件(便于深度调试),同时只让 ERROR 级别信息发送邮件到你的邮箱(便于报警)。
下面我们来看一个完整示例。
终幕:实战!给爬虫装上“黑匣子”
我们来写一个简单的爬虫,并给它配上工业级的日志系统。
import logging
import requests
from bs4 import BeautifulSoup
import time
# 1. 创建一个专属的logger
logger = logging.getLogger(‘my_awesome_spider’)
logger.setLevel(logging.DEBUG) # logger本身捕获的最低级别
# 2. 创建Handler(我们创建两个:一个给文件,一个给控制台)
# 文件Handler,记录所有DEBUG及以上级别的日志
file_handler = logging.FileHandler(‘spider.log’, mode=‘a’, encoding=‘utf-8’)
file_handler.setLevel(logging.DEBUG)
# 控制台Handler,只记录INFO及以上级别的日志
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 3. 创建Formatter,定义日志格式
formatter = logging.Formatter(
‘%(asctime)s - %(name)s - [%(levelname)s] - %(message)s’
)
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# 4. 将Handler添加到logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)
def crawl_page(url):
“”“爬取单个页面的函数”“”
logger.info(f“开始爬取: {url}”)
try:
response = requests.get(url, timeout=5)
response.raise_for_status() # 如果状态码不是200,会抛出HTTPError异常
# 假装这里有一些复杂的解析逻辑
soup = BeautifulSoup(response.text, ‘html.parser’)
title = soup.title.string if soup.title else ‘No Title’
logger.debug(f"页面标题获取成功: {title}") # 这种细节信息用DEBUG
logger.info(f“爬取成功: {url}”)
return response.text
except requests.exceptions.RequestException as e:
# 这里是爬虫最可能出错的地方!
logger.error(f“爬取失败 {url},错误: {e}”, exc_info=True) # exc_info=True会打印完整的异常栈
return None
def main():
logger.info(“= = = 爬虫程序启动 = = =”)
urls = [
‘https://httpbin.org/json’,
‘https://httpbin.org/status/404’, # 一个会返回404的URL
‘https://这是一个无效的网址.com/’,
]
for i, url in enumerate(urls, 1):
logger.info(f”正在处理第 {i} 个URL,共 {len(urls)} 个”)
result = crawl_page(url)
time.sleep(1) # 礼貌一点
logger.info(“= = = 爬虫程序结束 = = =”)
if __name__ == ‘__main__’:
main()
运行这个脚本,你会看到:
- 控制台:清晰地显示着INFO及以上的关键流程信息。
- spider.log 文件:记录了包括DEBUG信息在内的所有细节,特别是那个404错误和无效网址的 完整错误堆栈。
现在,让我们模拟一下“后悔药”的场景:
假如你的爬虫在深夜因为一个连接超时异常崩溃了。第二天,你不再需要去猜测发生了什么。只需打开 spider.log,搜索 “ERROR”,你就能立刻看到:
2023-10-27 14:40:23 - my_awesome_spider - [ERROR] - 爬取失败 https://这是一个无效的网址.com/,错误: ... (后面是详细的异常信息)
问题瞬间定位!这就是logging的力量。
总结
老铁,看到这里,你已经成功从“print游击队”毕业,加入了“logging正规军”。记住,一个成熟的程序员,不是在写日志,就是在去写日志的路上。
总结一下核心心法:
- 告别print:从项目一开始就使用logging。
- 善用级别:用DEBUG调试,用INFO记录流程,用WARNING和ERROR记录问题。
- 输出到文件:这是日志发挥作用的前提。
- 信息明确:日志信息要能让人看懂,必要时带上上下文(比如URL、ID等)。
- 面向“甩锅”编程:清晰详细的日志,在排查与第三方API交互的问题时,是你最强的“甩锅”(哦不,是举证)利器。
现在,就打开你的爬虫项目,把里面乱七八糟的print语句,换成优雅强大的logging吧!让你的代码从此拥有一个可靠的“黑匣子”。

被折叠的 条评论
为什么被折叠?



