沈阳网站开发集团网站做的漂浮为什么不动

张小明 2026/1/12 13:15:30
沈阳网站开发集团,网站做的漂浮为什么不动,wordpress主题自媒体一号,大学网站策划方案前言 在爬虫开发过程中#xff0c;异常是不可避免的 —— 网络波动导致的请求超时、目标网站结构变更引发的解析错误、服务器返回的非预期状态码等#xff0c;都可能导致爬虫程序崩溃或数据采集不完整。异常处理能力是衡量爬虫稳定性的核心指标#xff0c;也是保障爬虫持续…前言在爬虫开发过程中异常是不可避免的 —— 网络波动导致的请求超时、目标网站结构变更引发的解析错误、服务器返回的非预期状态码等都可能导致爬虫程序崩溃或数据采集不完整。异常处理能力是衡量爬虫稳定性的核心指标也是保障爬虫持续运行的关键。本文将从爬虫常见异常类型入手系统讲解超时、请求报错、解析报错等核心异常的处理策略并结合实战代码实现高容错性的爬虫架构帮助开发者打造 “稳、准、全” 的爬虫程序。摘要本文以「豆瓣图书 Top250」https://book.douban.com/top250为爬取目标聚焦爬虫开发中的核心异常场景请求超时、连接错误、状态码异常、解析失败、文件写入错误等详细讲解异常捕获、重试机制、降级处理等解决方案。通过实战代码演示如何使用 Python 异常处理语法try-except结合自定义重试逻辑实现对各类异常的全链路管控并给出异常日志记录、数据兜底等进阶优化方案最终提升爬虫程序的鲁棒性和可用性。一、爬虫常见异常类型梳理爬虫的异常贯穿 “请求 - 解析 - 存储” 全流程核心异常类型及成因如下表所示异常阶段异常类型具体场景典型报错信息请求阶段超时异常Timeout网络延迟、服务器响应慢、目标网站限流requests.exceptions.Timeout: Connection timed out请求阶段连接异常ConnectionError网络中断、域名解析失败、服务器宕机requests.exceptions.ConnectionError: Failed to establish a connection请求阶段状态码异常服务器返回 4xx/5xx 错误如 403 禁止访问、500 服务器内部错误requests.exceptions.HTTPError: 403 Client Error解析阶段解析异常AttributeError/KeyError网页结构变更、目标标签 / 字段不存在AttributeError: NoneType object has no attribute text存储阶段写入异常IOError/PermissionError磁盘空间不足、文件权限不够、路径不存在PermissionError: [Errno 13] Permission denied通用阶段通用请求异常上述请求异常的父类覆盖所有请求问题requests.exceptions.RequestException二、异常处理核心原则在设计爬虫异常处理逻辑时需遵循以下核心原则确保处理策略科学、有效精准捕获避免使用except Exception捕获所有异常应按异常类型细分捕获便于定位问题分级处理不同异常采取不同策略如超时异常重试、404 异常直接跳过、权限异常终止程序重试可控重试机制需设置最大重试次数和休眠时间避免无限重试导致程序卡死日志记录捕获异常时记录关键信息时间、URL、异常类型、错误详情便于事后排查数据兜底解析失败时保留原始数据或返回默认值避免单条数据异常导致整批数据丢失优雅降级核心功能异常时程序应降级运行而非直接崩溃如存储失败时先缓存数据。三、实战代码实现高容错爬虫开发3.1 完整代码python运行import requests from bs4 import BeautifulSoup import csv import time import logging from fake_useragent import UserAgent from typing import Optional, List, Dict # 日志配置 # 配置日志记录异常信息到文件控制台 logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(crawler_error.log, encodingutf-8), # 异常日志写入文件 logging.StreamHandler() # 控制台输出 ] ) logger logging.getLogger(__name__) # 配置项 # 目标URL豆瓣图书Top250 BASE_URL https://book.douban.com/top250 # CSV存储路径 CSV_PATH douban_book_top250.csv # 请求配置 HEADERS { User-Agent: UserAgent().random, Accept-Language: zh-CN,zh;q0.9, Accept-Encoding: gzip, deflate, Connection: keep-alive } # 异常重试配置 MAX_RETRY 3 # 最大重试次数 RETRY_DELAY 2 # 重试休眠时间秒 # 超时配置 REQUEST_TIMEOUT 10 # 请求超时时间秒 # 异常处理装饰器 def retry_on_exception(max_retry: int MAX_RETRY, delay: int RETRY_DELAY): 异常重试装饰器捕获指定异常并自动重试 :param max_retry: 最大重试次数 :param delay: 重试间隔秒 def decorator(func): def wrapper(*args, **kwargs): retry_count 0 while retry_count max_retry: try: return func(*args, **kwargs) except (requests.exceptions.Timeout, requests.exceptions.ConnectionError) as e: # 超时/连接异常重试 retry_count 1 logger.warning(f【重试】{func.__name__} 执行失败{retry_count}/{max_retry}异常{str(e)[:100]}) time.sleep(delay) except requests.exceptions.HTTPError as e: # 状态码异常记录日志并跳过4xx/5xx一般不重试 logger.error(f【状态码异常】{func.__name__} 执行失败URL{args[0]}异常{e}) return None except Exception as e: # 其他未知异常记录日志并终止 logger.critical(f【致命异常】{func.__name__} 执行失败异常{e}终止重试, exc_infoTrue) return None logger.error(f【重试耗尽】{func.__name__} 执行失败已重试{max_retry}次URL{args[0]}) return None return wrapper return decorator # 核心爬虫函数 retry_on_exception(max_retry3, delay2) def fetch_page(url: str) - Optional[str]: 获取网页内容带异常重试 :param url: 目标URL :return: 网页HTML文本失败返回None response requests.get( urlurl, headersHEADERS, timeoutREQUEST_TIMEOUT, allow_redirectsTrue ) # 校验状态码2xx为成功否则抛出HTTPError response.raise_for_status() # 自动识别编码避免乱码 response.encoding response.apparent_encoding return response.text def parse_book_data(html: str) - List[Dict]: 解析图书数据带解析异常处理 :param html: 网页HTML文本 :return: 图书数据列表解析失败返回空列表 book_list [] if not html: logger.warning(【解析异常】HTML文本为空) return book_list try: soup BeautifulSoup(html, html.parser) # 定位图书条目 book_items soup.find_all(tr, class_item) for item in book_items: # 数据提取所有可能报错的步骤都做容错处理 book_info { 排名: item.find(td, class_rating_num).previous_sibling.text.strip() or 未知, 书名: item.find(a).get(title) or 未知, 评分: item.find(span, class_rating_nums).text.strip() or 0.0, 评论数: item.find(span, class_pl).text.strip().replace((, ).replace(), ).replace(人评价, ) or 0, 作者/出版社: item.find(p, class_pl).text.strip() or 未知 } book_list.append(book_info) except AttributeError as e: # 解析异常标签不存在 logger.error(f【解析异常】标签定位失败异常{e}, exc_infoTrue) except Exception as e: # 其他解析异常 logger.error(f【解析异常】未知解析错误异常{e}, exc_infoTrue) return book_list def save_to_csv(data: List[Dict], file_path: str) - bool: 保存数据到CSV带写入异常处理 :param data: 图书数据列表 :param file_path: CSV文件路径 :return: 成功返回True失败返回False if not data: logger.warning(【存储异常】无数据可写入CSV) return False # 定义CSV表头 headers [排名, 书名, 评分, 评论数, 作者/出版社] try: # 打开文件设置newline避免空行utf-8-sig解决中文乱码 with open(file_path, a, newline, encodingutf-8-sig) as f: # a模式文件不存在则创建存在则追加 writer csv.DictWriter(f, fieldnamesheaders) # 若文件为空先写入表头 if f.tell() 0: writer.writeheader() # 写入数据 writer.writerows(data) logger.info(f【存储成功】{len(data)}条数据写入CSV{file_path}) return True except PermissionError as e: logger.error(f【存储异常】文件权限不足路径{file_path}异常{e}) except FileNotFoundError as e: logger.error(f【存储异常】文件路径不存在路径{file_path}异常{e}) except IOError as e: logger.error(f【存储异常】磁盘IO错误路径{file_path}异常{e}) except Exception as e: logger.error(f【存储异常】未知写入错误异常{e}, exc_infoTrue) return False def crawl_douban_book_top250() - None: 爬取豆瓣图书Top250主函数全流程异常管控 page 0 total_crawled 0 # 累计爬取数据条数 logger.info(【爬虫启动】开始爬取豆瓣图书Top250) while True: # 构造分页URL每页25条 page_url f{BASE_URL}?start{page * 25} logger.info(f【爬取页面】第{page 1}页URL{page_url}) # 1. 获取页面内容 html fetch_page(page_url) if not html: logger.warning(f【页面获取失败】第{page 1}页终止爬取) break # 2. 解析页面数据 book_data parse_book_data(html) if not book_data: # 解析不到数据可能是最后一页终止爬取 logger.info(f【解析完成】第{page 1}页无数据判定为最后一页) break # 3. 保存数据到CSV if save_to_csv(book_data, CSV_PATH): total_crawled len(book_data) # 4. 控制爬取频率 time.sleep(1) page 1 # 终止条件爬取超过250条Top250共10页 if page 10: break logger.info(f【爬虫结束】爬取完成累计获取{total_crawled}条图书数据) # 程序入口 if __name__ __main__: try: crawl_douban_book_top250() except KeyboardInterrupt: # 手动终止程序CtrlC logger.info(【爬虫终止】用户手动终止程序) except Exception as e: # 全局异常捕获 logger.critical(f【爬虫崩溃】全局未捕获异常{e}, exc_infoTrue)3.2 核心异常处理逻辑解析1异常重试装饰器retry_on_exception核心作用将重试逻辑封装为装饰器实现代码复用避免重复编写重试代码异常分级处理超时 / 连接异常Timeout/ConnectionError自动重试最多 3 次每次重试前休眠 2 秒状态码异常HTTPError记录日志并跳过4xx/5xx 错误重试意义不大未知异常Exception记录详细日志含堆栈信息并终止重试避免无限循环日志记录每次重试和失败都记录关键信息函数名、重试次数、URL、异常详情便于排查。2请求阶段异常处理fetch_page 函数超时控制设置timeout10避免请求长时间阻塞状态码校验通过response.raise_for_status()触发 4xx/5xx 状态码的 HTTPError 异常编码处理使用response.apparent_encoding自动识别编码避免乱码导致的后续解析异常装饰器复用通过retry_on_exception直接复用重试逻辑代码简洁高效。3解析阶段异常处理parse_book_data 函数容错提取所有字段提取都通过or 未知设置默认值避免字段为空导致程序崩溃精准捕获单独捕获AttributeError标签不存在其他解析异常统一捕获日志记录记录异常的同时通过exc_infoTrue输出堆栈信息便于定位具体报错行优雅降级解析失败时返回空列表主程序判定为 “最后一页”避免程序中断。4存储阶段异常处理save_to_csv 函数细分存储异常分别捕获权限异常PermissionError、路径异常FileNotFoundError、IO 异常IOError针对性记录错误原因文件模式优化使用a模式追加 读取避免覆盖已有数据且通过f.tell() 0判断文件是否为空确保表头只写一次返回值标识通过布尔值返回存储结果主程序可根据结果统计有效数据条数数据兜底无数据时仅记录警告不终止程序。5全局异常处理程序入口捕获在if __name__ __main__中捕获KeyboardInterrupt手动终止和全局Exception避免程序直接崩溃日志完整记录全局异常记录堆栈信息便于事后复盘问题根源。3.3 代码运行结果1控制台输出示例plaintext2025-12-17 10:00:00,123 - INFO - 【爬虫启动】开始爬取豆瓣图书Top250 2025-12-17 10:00:00,124 - INFO - 【爬取页面】第1页URLhttps://book.douban.com/top250?start0 2025-12-17 10:00:02,345 - INFO - 【存储成功】25条数据写入CSVdouban_book_top250.csv 2025-12-17 10:00:03,456 - INFO - 【爬取页面】第2页URLhttps://book.douban.com/top250?start25 2025-12-17 10:00:05,678 - WARNING - 【重试】fetch_page 执行失败1/3异常requests.exceptions.Timeout: Connection timed out after 10 seconds 2025-12-17 10:00:09,789 - INFO - 【存储成功】25条数据写入CSVdouban_book_top250.csv ... 2025-12-17 10:00:50,123 - INFO - 【爬虫结束】爬取完成累计获取250条图书数据2日志文件crawler_error.log示例plaintext2025-12-17 10:00:05,678 - WARNING - 【重试】fetch_page 执行失败1/3异常requests.exceptions.Timeout: Connection timed out after 10 seconds 2025-12-17 10:00:10,123 - ERROR - 【解析异常】标签定位失败异常NoneType object has no attribute text Traceback (most recent call last): File douban_book_crawler.py, line 112, in parse_book_data 排名: item.find(td, class_rating_num).previous_sibling.text.strip() or 未知, AttributeError: NoneType object has no attribute text 2025-12-17 10:00:20,456 - INFO - 【解析完成】第10页无数据判定为最后一页3CSV 文件输出示例排名书名评分评论数作者 / 出版社1红楼梦9.6189321[清] 曹雪芹 著 / 人民文学出版社 / 1996-122百年孤独9.3256789[哥伦比亚] 加西亚・马尔克斯 著 / 范晔 译 / 南海出版公司 / 2011-63活着9.3321567余华 著 / 作家出版社 / 2012-8四、进阶异常处理优化方案4.1 异常分类与处理策略对照表针对不同异常类型可采用更精细化的处理策略如下表所示异常类型优先级处理策略适用场景超时异常Timeout高重试3-5 次 递增休眠2s→4s→6s网络不稳定、服务器响应慢连接异常ConnectionError高重试3 次 切换代理 IP单 IP 被限流、域名解析波动403/429 状态码中休眠5-10 分钟 切换代理 IP被网站反爬识别404 状态码低直接跳过页面不存在无重试意义500/503 状态码中重试5 次 延长休眠服务器临时故障解析异常AttributeError中记录原始 HTML 跳过该条数据单条数据标签异常不影响整体存储权限异常PermissionError高切换存储路径 告警通知核心存储功能异常4.2 异常告警机制实现当捕获到严重异常如存储失败、大量请求失败时可添加邮件 / 钉钉告警及时通知开发者python运行import smtplib from email.mime.text import MIMEText from email.header import Header def send_error_alert(error_msg: str): 发送异常告警邮件 :param error_msg: 异常信息 # 配置邮件信息 smtp_server smtp.163.com smtp_port 25 sender your_email163.com password your_email_password receiver developerxxx.com # 构造邮件内容 message MIMEText(f爬虫异常告警\n{error_msg}, plain, utf-8) message[From] Header(豆瓣图书爬虫, utf-8) message[To] Header(开发者, utf-8) message[Subject] Header(【紧急】豆瓣图书爬虫异常, utf-8) try: smtp_obj smtplib.SMTP(smtp_server, smtp_port) smtp_obj.login(sender, password) smtp_obj.sendmail(sender, receiver, message.as_string()) smtp_obj.quit() logger.info(【告警成功】异常邮件已发送) except smtplib.SMTPException as e: logger.error(f【告警失败】邮件发送失败异常{e}) # 调用示例在存储异常处添加告警 except PermissionError as e: error_msg f存储权限异常路径{file_path}异常{e} logger.error(error_msg) send_error_alert(error_msg)4.3 原始数据缓存机制解析失败时缓存原始 HTML便于事后分析页面结构变更python运行import os from datetime import datetime def cache_failed_html(html: str, page_num: int): 缓存解析失败的HTML页面 :param html: HTML文本 :param page_num: 页码 # 创建缓存目录 cache_dir failed_html_cache if not os.path.exists(cache_dir): os.makedirs(cache_dir) # 构造缓存文件名时间页码 cache_file f{cache_dir}/page_{page_num}_{datetime.now().strftime(%Y%m%d_%H%M%S)}.html try: with open(cache_file, w, encodingutf-8) as f: f.write(html) logger.info(f【缓存成功】解析失败的HTML已缓存至{cache_file}) except Exception as e: logger.error(f【缓存失败】HTML缓存失败异常{e}) # 调用示例在解析异常处添加缓存 except AttributeError as e: logger.error(f【解析异常】标签定位失败异常{e}, exc_infoTrue) cache_failed_html(html, page 1)五、常见异常排查思路5.1 超时异常排查网络层面检查本地网络是否稳定使用ping命令测试目标网站连通性目标网站层面访问目标 URL 查看是否响应缓慢确认是否为网站服务器问题爬虫层面降低爬取频率增加超时时间或切换代理 IP 测试代码层面检查是否存在死锁、资源占用过高导致的请求阻塞。5.2 解析异常排查页面结构验证将缓存的 HTML 保存为文件打开后检查目标标签是否存在反爬验证确认是否被网站返回 “假页面”如登录验证页导致标签结构变更解析规则优化使用更通用的解析规则如通过 XPath 替代类名定位提升兼容性数据兜底对关键字段设置默认值避免单字段异常导致整页解析失败。5.3 存储异常排查权限检查使用ls -lLinux或右键属性Windows检查文件 / 目录权限路径验证确认存储路径是否存在避免拼写错误磁盘空间检查磁盘剩余空间避免空间不足导致写入失败文件占用确认 CSV 文件是否被其他程序如 Excel打开导致写入锁定。六、总结与最佳实践6.1 核心总结本文通过豆瓣图书 Top250 爬取案例完整实现了爬虫全流程的异常处理核心要点包括异常分层捕获按 “请求 - 解析 - 存储” 阶段细分异常精准定位问题重试策略差异化不同异常采取不同重试逻辑避免无效重试日志完整记录记录异常时间、URL、堆栈信息便于事后排查优雅降级处理单条数据 / 单页异常不影响整体爬虫运行全局兜底机制捕获全局异常避免程序直接崩溃。6.2 异常处理最佳实践避免过度捕获不使用except Exception捕获所有异常应细分异常类型保留程序崩溃的 “预警信号”重试次数可控设置最大重试次数避免无限重试导致程序卡死日志分级输出使用logging模块的不同级别INFO/WARNING/ERROR/CRITICAL区分日志重要性代码解耦将异常处理逻辑封装为装饰器 / 函数提升代码复用性事后复盘定期分析异常日志优化爬虫规则如调整解析策略、增加代理池资源释放在异常捕获后释放占用的资源如文件句柄、网络连接避免资源泄漏。异常处理是爬虫开发的 “护城河”一套完善的异常处理机制能大幅提升爬虫的稳定性和可用性。开发者在编写爬虫时应将异常处理作为核心模块设计而非 “事后补充”才能在复杂的网络环境中保障数据采集的完整性和可靠性。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

网站建设人员架构有什么平台可以销售产品

EmotiVoice语音合成情感冲突规避机制:避免怪异混合情绪 在虚拟偶像直播中,一句本应温柔鼓励的话语却因音调突兀上扬而听起来像讽刺;在有声读物里,角色“含泪微笑”的描写被合成为一种令人不适的抽泣式笑声——这些看似微小的技术瑕…

张小明 2026/1/9 15:49:26 网站建设

安庆网站建设全国文明城市创建工作

准备 使用 CachyOS Live USB 启动进入桌面/终端连接到网络打开终端开始操作1.确认分区(找出根分区和 EFI 分区) 执行查看硬盘与分区文件系统: lsblk -f根据 lsblk 结果,确认你真正的 Linux 系统分区(示例)&…

张小明 2026/1/8 0:31:17 网站建设

html5网站建设中模板跑腿小程序源码

深入理解Shell的字符串输入输出操作 在Shell编程中,字符串的输入输出操作是非常基础且重要的部分。本文将详细介绍 print 和 read 这两个命令,它们赋予了Shell类似于传统编程语言的输入输出能力。 1. print 命令 print 命令用于将其参数打印到标准输出。相较于 ec…

张小明 2025/12/29 8:52:00 网站建设

公司网站建设方案模板下载wordpress本地时间

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个交互式JMeter入门教程项目,包含:1) 分步视频指导;2) 可运行的示例测试计划(测试一个简单的REST API)&#xff1b…

张小明 2026/1/3 12:02:46 网站建设