python用ssl模块可直接提取证书notafter字段,通过ssl.cert_time_to_seconds()转时间戳,结合time.time()计算剩余天数,并发检测需设超时与异常捕获。

用 ssl 模块直接连接并提取证书信息
Python 标准库的 ssl 模块就能完成基础检测,不需要额外装包。关键在于用 ssl.create_default_context() 建立连接后,调用 sock.getpeercert() 获取原始证书字典——它包含 notAfter 字段,格式是 'MMM DD HH:MM:SS YYYY GMT',比如 'Jan 15 12:34:56 2025 GMT'。
注意:必须用 socket.create_connection() 手动建 TCP 连接,再套上 ssl.wrap_socket() 或更推荐的 context.wrap_socket(),不能直接对域名用 urllib ——那层 HTTP 封装会屏蔽证书细节。
常见错误:ssl.SSLCertVerificationError 通常是因为目标站用了自签名证书或中间 CA 不在系统信任链里;这时加 context.check_hostname = False 和 context.verify_mode = ssl.CERT_NONE 可绕过验证(仅用于检测过期时间,不校验可信度)。
把 notAfter 字符串转成可比较的 datetime
notAfter 是固定格式但非 ISO 的字符串,别用 strptime('%Y-%m-%d ...') 硬写格式——容易因空格、缩写月份大小写失败。直接交给 ssl 模块的 ssl.cert_time_to_seconds() 函数最稳,它专为此设计,输入 notAfter 字符串,返回 Unix 时间戳整数。
实操建议:
- 先检查
cert_dict是否有'notAfter'键,某些异常证书可能缺失 - 用
ssl.cert_time_to_seconds(cert_dict['notAfter'])转时间戳,比手动解析少踩坑 - 对比时统一用
time.time()当前时间戳,避免时区换算错误
批量检测多个域名时怎么避免阻塞和超时
挨个同步连接太慢,尤其几十个域名时可能卡几分钟。用 concurrent.futures.ThreadPoolExecutor 并发是合理选择,线程数控制在 5–10 较稳妥——太多反而触发目标服务器限流或本地端口耗尽。
必须设超时:
- Socket 层超时:传给
socket.create_connection((host, 443), timeout=10) - SSL 握手超时:在
context.wrap_socket()后,sock.settimeout(10)再做sock.do_handshake()
错误类型要区分:socket.timeout、OSError(连不上)、ssl.SSLError(证书异常)都该捕获并记录,而不是让整个脚本崩掉。
输出结果时别只打印“过期/未过期”,要带具体天数和误差容忍
单纯判断布尔值意义不大。用户真正需要的是:还剩几天?是否在 7 天预警阈值内?
计算剩余天数时注意:
- 用
(expiry_timestamp - time.time()) / 86400得浮点天数,int()向下取整更符合“还剩 X 整天”的直觉 - 证书时间是 GMT,
time.time()是本地时区 timestamp,但两者都是 Unix 时间戳,差值天然无时区问题 - 建议加一个容错偏移,比如
if days_left 才标“已过期”,避免因系统时间误差误报
复杂点在于:有些 CDN(如 Cloudflare)返回的是他们自己的证书,不是源站的;如果目标是监控源站 SSL,得绕过 CDN 直连 IP,这就得先查 A 记录再连 IP + SNI 主机名——那是另一个层级的问题了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











