BeautifulSoup中Try/Except异常处理失效及自定义函数返回值全为None的问题排查
解决BeautifulSoup遍历中的异常处理与参数传递问题
咱们一步步来拆解你的问题,先搞清楚为什么前两次的尝试都没达到预期效果,再给出可行的解决方案。
第一个问题:为什么iferr函数没捕获异常?
你最初的iferr(x)函数逻辑有个致命问题:异常在传入函数之前就已经触发了。比如你写的iferr(dp[0].find('a', rel='nofollow')['href']),Python会先执行dp[0].find('a', rel='nofollow')['href']这个表达式,如果找不到元素或者没有href属性,直接就抛出异常了,根本没机会进入iferr的try块。所以这个函数完全起不到捕获异常的作用。
第二个问题:为什么fndwoerr返回全是None?
你后来写的函数里犯了两个参数传递的错误:
- 你把
find的标签名写成了固定字符串'x',而不是传入的变量x,相当于每次都在找<x>标签,肯定找不到; - 你把关键字参数名(比如
class_、rel)当成字符串y传递,而不是作为find的关键字参数传入。d.find('x', y='z')实际是在调用find时传了一个名为y的参数,这和BeautifulSoup需要的class_、rel完全不沾边,自然也找不到元素。
正确的解决方案
我们需要把可能抛出异常的操作放在try块内部执行,同时正确传递find的关键字参数。这里有两种简洁的实现方式:
方式一:通用异常处理函数
写一个能接收任意可调用操作的安全执行函数,把可能出错的逻辑包装成lambda传入:
def safe_execute(func, default=None): try: return func() except (Exception, TypeError, AttributeError): return default
然后在列表推导式里这样用:
articles = [[ safe_execute(lambda: dp[0].find('span', class_='citation')), safe_execute(lambda: dp[0].find('div', class_='abstract')), safe_execute(lambda: dp[0].find('a', rel='nofollow')['href']) ] for dp in data]
这样每个可能出错的表达式都在lambda内部执行,异常会被safe_execute捕获,返回默认的None。
方式二:针对BeautifulSoup的专用查找函数
如果你的场景只需要处理find操作,可以写一个更贴合需求的函数,直接处理标签名、关键字参数和属性获取:
def safe_find(elem, tag, default=None, attr=None, **kwargs): try: # 执行find操作,关键字参数直接传递给find result = elem.find(tag, **kwargs) # 如果需要获取属性,且找到元素的话返回属性值,否则返回default if attr is not None and result is not None: return result.get(attr, default) # 不需要属性的话直接返回find结果(找不到就是None) return result except (Exception, TypeError, AttributeError): return default
调用时更简洁直观:
articles = [[ safe_find(dp[0], 'span', class_='citation'), safe_find(dp[0], 'div', class_='abstract'), safe_find(dp[0], 'a', rel='nofollow', attr='href') ] for dp in data]
关键知识点总结
- 异常捕获时机:必须把可能抛出异常的代码放在
try块内部执行,不能先执行再传入函数; - 关键字参数传递:用
**kwargs可以把函数接收的关键字参数原样传递给另一个函数(比如BeautifulSoup的find),避免把参数名当成字符串传递的错误; - 默认值处理:明确指定异常时的返回值(比如
None),让结果更可控。
内容的提问来源于stack exchange,提问作者Tomikuz
相关产品推荐
相关产品推荐

