Linux服务器运行undetected_chromedriver脚本10小时后出现Too many open files错误求助
兄弟,这个问题我之前帮不少开发者排查过,大概率是你的脚本长时间运行时没正确释放资源,导致文件句柄越积越多,最后触发了系统的文件描述符限制。咱们一步步来搞定它:
一、先确认系统的文件句柄限制
Linux系统默认的文件句柄软限制一般是1024,长时间跑爬虫这类创建大量资源的脚本很容易耗尽。你可以先查一下当前的限制:
- 查看当前会话的软限制:
ulimit -n - 查看系统硬限制:
ulimit -Hn
如果数值偏低,先临时调高应急:ulimit -n 4096,但这只是临时生效,重启会话就会失效。要永久生效的话,编辑/etc/security/limits.conf文件,添加两行(替换成你的用户名):
your_username soft nofile 4096 your_username hard nofile 8192
修改后需要重启系统或者重新登录会话才会生效。不过这只是兜底,核心还是要解决代码里的资源泄漏问题。
二、排查代码里的资源泄漏点
1. Chrome/Chromedriver实例没正确关闭
undetected_chromedriver每次启动都会创建完整的Chrome进程,如果用完后只调用driver.close()(这只会关闭当前标签页),而没调用driver.quit(),整个浏览器进程会一直留在后台,占用大量文件句柄和内存。时间一长,句柄肯定会爆。
一定要确保每次用完浏览器都调用driver.quit(),哪怕出错也要保证执行。推荐用try-finally或者上下文管理器来做:
from undetected_chromedriver import Chrome def run_scrape_task(): driver = None try: driver = Chrome() # 这里写你的爬取逻辑 finally: if driver is not None: driver.quit() # 必须调用quit,彻底杀掉进程释放资源
或者更简洁的上下文管理器写法,自动帮你处理关闭:
with Chrome() as driver: # 你的爬取逻辑
这样哪怕中间代码抛出异常,也会自动执行quit()释放资源。
2. 日志Handler重复创建导致句柄泄漏
看你贴的代码,日志初始化的逻辑如果被重复执行(比如在循环里或者函数里反复调用),会重复添加FileHandler,导致同一个日志文件被打开多次,积累大量文件句柄。
解决办法是确保日志初始化只执行一次,或者检查Logger是否已有Handler再添加:
logger = logging.getLogger('ParserLogger') # 只有当Logger没有Handler时才初始化,避免重复添加 if not logger.handlers: logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[ logging.FileHandler("my_parser.log"), logging.StreamHandler() ] )
3. 其他潜在的泄漏点
比如你写的get_random_chrome_user_agent函数,里面用到的UserAgent库如果内部有缓存文件没正确关闭,或者你自己在函数里打开了文件/网络连接没释放,也可能占句柄。可以检查这个函数的完整实现,确保所有资源都能正确关闭。
三、定位具体泄漏点的工具
如果还是找不到问题,可以用Linux的工具来排查:
- 先用
ps aux | grep python找到你的脚本进程PID,然后用lsof -p <你的PID>查看这个进程打开的所有文件句柄,看看哪些类型的文件/连接数量异常多(比如大量Chrome相关的socket、临时文件,或者重复的日志文件句柄)。 - 用
watch -n 1 lsof -p <PID> | wc -l可以实时监控句柄数量的增长,对应你的代码逻辑就能快速定位到哪个步骤在消耗句柄。
先从代码层面的资源释放入手,再配合系统限制调整,应该就能解决这个问题啦!
内容来源于stack exchange

