
本文详解在使用beautiful soup解析网页表格时,因部分表格行缺失 `big chart 页面 为例,#section-chemicals 表能成功遍历,而 #section-plants 表却抛出 Attributeerror: ‘nonetype’ Object has no attribute ‘contents’——根本原因在于:该表首行是表头(
直接对 find() 结果做属性访问而不校验,是引发此类错误的典型模式。以下是推荐的三种稳健处理方式:
✅ 方案一:使用 css 伪类 :has()(推荐,简洁高效)
import requests from bs4 import beautifulsoup url = 'https://www.php.cn/link/013c0727c2f3b90ec8545f5062f75360' soup = BeautifulSoup(requests.get(url).content, 'html.parser') plants_table = soup.select_one('#section-PLANTS') # 只选取包含 标签的行,自动跳过表头/空行 for row in plants_table.select('tr:has(a)'): print(row.find('a').get_text(strip=True))
? tr:has(a) 是现代 BeautifulSoup(配合 lxml 或 html.parser)支持的 CSS 选择器,语义清晰、性能优秀,无需手动判断 None。
✅ 方案二:显式空值检查(兼容性最强)
for row in plants_table.find_all('tr'): link = row.find('a') if link: # 确保 link 不为 None print(link.get_text(strip=True))
✅ 方案三:使用 find_next() 或 select_one() 避免链式调用风险
for row in plants_table.find_all('tr'): link = row.select_one('a') # 返回 None 或 Tag,更安全 if link: print(link.get_text(strip=True))
⚠️ 注意事项
- 永远不要对 find() / select_one() 的返回值直接链式调用 .text 或 [‘href’],除非你 100% 确认该元素必然存在;
- 使用 .get_text(strip=True) 替代 .contents[0] 更鲁棒——它能合并嵌套文本节点并去除首尾空白;
- 若目标页面结构复杂(如含
/
),建议先用 soup.select(‘#section-PLANTS tbody tr’) 显式限定范围;
- 在生产环境中,务必添加异常处理与网络请求超时:
try: resp = requests.get(url, timeout=10) resp.raise_for_status() soup = BeautifulSoup(resp.content, 'html.parser') except (requests.RequestException, AttributeError) as e: print(f"解析失败: {e}")通过合理选用 CSS 选择器或前置空值校验,即可彻底规避 NoneType 错误,让表格数据提取既准确又健壮。
- 在生产环境中,务必添加异常处理与网络请求超时: