Python爬虫程序运行中假死无响应且不抛异常,如何排查与解决?

null
Python爬虫程序运行中假死无响应且不抛异常,如何排查与解决?

22 回复

设置 timeout ?


遇到爬虫假死这事儿确实挺烦的,程序挂着不动也不报错。我一般按这个顺序来查:

1. 先看是不是网络请求卡住了 直接用requests的timeout参数,别让它无限等:

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()
retries = Retry(total=3, backoff_factor=0.5)
session.mount('http://', HTTPAdapter(max_retries=retries))
session.mount('https://', HTTPAdapter(max_retries=retries))

# 设置连接和读取超时
try:
    response = session.get('http://example.com', timeout=(3.05, 27))
except requests.exceptions.Timeout:
    print("请求超时了")
except requests.exceptions.RequestException as e:
    print(f"请求出错: {e}")

2. 检查是不是解析耗死了 特别是用BeautifulSoup处理大文件或复杂HTML时:

from bs4 import BeautifulSoup
import lxml  # 确保安装了lxml解析器

# 用lxml解析器,比html.parser快得多
soup = BeautifulSoup(html_content, 'lxml')

# 如果文档真的很大,考虑逐部分处理
# 或者用select代替find_all,效率更高

3. 线程/进程池可能卡住了 如果用concurrent.futures,记得设timeout:

from concurrent.futures import ThreadPoolExecutor, as_completed
import time

def fetch_url(url):
    # 你的爬取逻辑
    pass

urls = [...]  # URL列表
with ThreadPoolExecutor(max_workers=10) as executor:
    future_to_url = {executor.submit(fetch_url, url): url for url in urls}
    
    for future in as_completed(future_to_url.keys(), timeout=30):
        try:
            data = future.result(timeout=10)  # 每个任务单独超时
        except TimeoutError:
            print(f"任务超时: {future_to_url[future]}")
            future.cancel()  # 取消卡住的任务

4. 加个全局看门狗 设个总时间限制,超时就退出:

import signal
import time

class TimeoutException(Exception):
    pass

def timeout_handler(signum, frame):
    raise TimeoutException("程序运行超时")

# 设置2小时超时
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(7200)  # 7200秒=2小时

try:
    # 你的主爬虫逻辑
    main_spider()
except TimeoutException:
    print("程序执行超时,自动退出")
finally:
    signal.alarm(0)  # 取消定时器

5. 关键位置加日志 在可能卡住的地方记录状态:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def parse_page(html):
    logger.info("开始解析页面")
    # 解析逻辑...
    logger.info(f"解析完成,找到{len(items)}个条目")
    return items

6. 用异步试试 如果同步请求容易卡,考虑aiohttp:

import aiohttp
import asyncio

async def fetch(session, url):
    try:
        async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as response:
            return await response.text()
    except asyncio.TimeoutError:
        print(f"异步请求超时: {url}")
        return None

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks, return_exceptions=True)

快速排查步骤:

  1. 先加超时参数复现问题
  2. 在关键函数入口/出口加print或日志
  3. top或任务管理器看CPU/内存
  4. 逐步缩小范围,定位具体卡住的函数

最可能的就是网络请求没设超时,或者解析大文件时内存爆了。先从这里查起。

总结:核心是给所有可能阻塞的操作加上超时控制。

多 print, 看卡在哪了。。。

你代码也不发 让我们怎么猜。。。。

接楼上,我猜是爬虫累了

栈溢出

爬虫:爬了这么久,是该歇歇了。

多线程死锁?

服务器被你爬趴下了?

阻塞了, 链接池释放了吗,设置 timeout 了吗

可能虫子被小鸟吃了

开 ssh,我去看看

很大可能是请求阻塞了

爬虫:我休息一下不行?换你一直爬试试?

用 print 方法检查,那个地方卡了。每个函数下都放个 print.

1 楼说的对,很大可能没有设置 timeout。
另外可以加杀死进程的代码。在下一次启动任务时,先执行一下杀死进程。注意 2 个 crontab

爬虫:我有自己的想法了,我要看小电影,歇一会

只说自己爬虫程序卡死了,也不说自己具体使用的是什么技术。。也不贴代码,这让人怎么给你分析?

大多数原因都是阻塞在了某个链接上,如果你使用 python 的协程 处理不好的话很容易卡死的。

被一只早起的鸟,吃了

可以看一下,是不是卡在打 log 上了。我曾经碰到过,将所有 log 配置都去除,只有在抛异常的时候再打 log

当然是等它复活啊

记得 close connection

回到顶部