调用lxml etree cleanup_namespaces返回None而非已清理XML树的问题
核心问题排查
为什么clean_root返回None
etree.cleanup_namespaces的API设计为原地修改传入的XML树对象,执行完成后没有返回值,默认返回None。- 你原本的
clean_root方法中,循环修改元素tag为本地名称的操作确实已经正常生效,但因为最后直接返回了etree.cleanup_namespaces()的执行结果(该结果为None),才导致整个方法的返回值是None,给你造成了“清理操作完全没生效”的错觉。 - 实际传入的
root对象在循环执行时,就已经被修改掉了标签上的命名空间URL前缀。
为什么不带self调用会触发NameError
- 类内部定义的实例方法,是绑定在类实例上的属性,不属于当前函数的局部、或全局可访问的函数作用域。
- 在实例方法内部直接写
clean_root(xxx),Python会依次在当前代码块的局部变量、全局变量中查找名为clean_root的可调用对象,找不到就会抛出NameError。这种情况和你写错方法名(比如将方法名误写为clean_tree)触发的错误逻辑完全一致,类实例内的方法必须通过self.方法名()的方式调用。
修正后的可运行代码
import requests from lxml import etree class scraper(): def __init__(self, BASE_URL, headers): self.BASE_URL = BASE_URL self.headers = headers self.URL = self.BASE_URL + '?delimiter=/' def clean_root(self, root): """用于清理每个XML元素标签前的URL前缀""" for elem in root.getiterator(): # 原地修改元素标签为无命名空间的本地名称 elem.tag = etree.QName(elem).localname # 原地清理冗余命名空间,无需接收返回值 etree.cleanup_namespaces(root) # 返回被原地修改完成的root对象 return root def get_root_folder_names(self): """获取根文件夹列表""" res = requests.get(self.URL, headers=self.headers) root = etree.XML(res.content) print(f"修改前的元素: {root}") cleaned_root = self.clean_root(root) print(f"清理后的元素: {cleaned_root}")
效果说明
- 修正后执行代码,打印的清理后元素标签会去掉
{http://s3.amazonaws.com/doc/2016-11-11/}的命名空间前缀,与预期输出一致。 - 因为所有修改都是原地生效的,即便不通过方法返回root对象,只要持有同一个XML对象的引用,后续的遍历、提取操作都能直接拿到清理后的内容,返回对象的写法只是更符合常规的函数调用习惯。
内容的提问来源于stack exchange,提问作者swiss_knight
相关产品推荐
相关产品推荐

