requests.get()默认不抛出404异常,需手动检查status_code或调用raise_for_status();并发需限流、设超时、重试机制;URL须规范化去重;HTML解析应覆盖a/link/img/script等标签及canonical链接。

requests.get() 默认不抛出 404 异常,得手动检查 response.status_code
很多人以为 requests.get() 遇到 404 就会报错中断,实际它默认把 404 当作正常响应返回——response.status_code 是 404,但不会 raise requests.exceptions.HTTPError。不显式判断,死链就悄无声息混进结果里。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 每次调用后立刻检查
response.status_code是否在[200, 299]范围内,别依赖异常机制 - 想让 400+ 状态码自动抛异常,得显式调用
response.raise_for_status(),但它会把 404、500 全拦住,不利于分类统计 - 对重定向(如 301/302)要明确策略:是否跟随?是否算“有效链接”?
requests.get(url, allow_redirects=True)是默认行为,但最终状态码才是判定依据
并发太多触发目标站反爬或连接被拒,ThreadPoolExecutor 得限流
全站遍历动辄成千上万 URL,一股脑丢进 ThreadPoolExecutor(max_workers=50),大概率遭遇 ConnectionRefusedError、TimeoutError 或目标站返回 429/503。不是代码写错了,是发得太猛。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 从保守值起步:
max_workers=5或10,再根据实际响应时间逐步上调 - 加固定延迟没用,关键在控制并发请求数;用
concurrent.futures.as_completed()配合计数器比单纯设max_workers更稳 - 务必设置超时:
requests.get(url, timeout=(3, 7))—— 第一个数字是连接超时,第二个是读取超时,避免单个慢请求拖垮整批任务 - 遇到
requests.exceptions.ConnectionError或TimeoutError,别直接当死链,先记下来重试 1 次(带 jitter 延迟),再判为失效
URL 去重和规范化必须做,否则 https://a.com/ 和 https://a.com/index.html 被当成两个链接
爬取过程中,同一页面可能通过不同路径被多次发现:带尾部斜杠 / 不带、含查询参数 / 无参、大小写混用、协议混用(http vs https)。不做归一化,统计和去重全乱套。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
urllib.parse.urlparse()解析,统一转小写、移除默认端口(80/443)、标准化路径(os.path.normpath()处理../)、剥离空查询参数 - 不要简单用
set()存原始 URL 字符串——https://example.com和https://example.com/在字符串层面不同,但语义等价 - 对内部链接,先补全为绝对 URL(用
urllib.parse.urljoin(base_url, relative)),再规范化,否则相对路径无法比对
解析 HTML 提取链接时,BeautifulSoup 别漏掉 <link rel="canonical"> 和 <script> 里的 URL
只扫 a[href] 和 img[src] 远远不够。SEO 相关的 <link rel="canonical">、资源预加载的 <link rel="preload">、甚至某些前端框架动态拼接的 URL(藏在 <script> 的字符串里),都可能是有效入口或死链高发区。
实操建议:
立即学习“Python免费学习笔记(深入)”;
-
BeautifulSoup(html, "lxml")比"html.parser"更准,尤其对不规范标签;但别用"html5lib",太慢且没必要 - 基础提取至少覆盖:
soup.find_all("a", href=True)、soup.find_all("link", href=True)、soup.find_all("img", src=True)、soup.find_all("script", src=True) - 对
<script>内容,别硬正则匹配 URL——先用script.string取文本,再用re.findall(r'https?://[^\s"\']+', text)粗筛,仅用于辅助发现,不作为主链接源 - 跳过
javascript:void(0)、#、mailto:、tel:这类非 HTTP 协议链接,避免无效请求
真正难的不是发请求,是搞清哪些 URL 值得测、哪些该跳过、哪些返回 404 是预期行为(比如旧版 API 下线),还有怎么让失败不中断整个流程——这些细节堆起来,才决定一次检测靠不靠谱。










