如何在BeautifulSoup的find方法中传入变量?及大XML搜索优化
问题解决:BeautifulSoup传变量及大XML文件优化
一、解决find函数传变量的问题
你之前的错误在于把属性和值拼成字符串传给find(),但find()的正确用法是通过关键字参数或attrs字典传递属性条件。
正确写法示例
假设你的CRD号码列表是firm_crd_list = ["5639055", "9999", ...],遍历查找的代码应该是:
# 方式1:使用关键字参数(对应XML属性名FirmCrdNb) for Firm_CRD in firm_crd_list: select_firm = soup.find(FirmCrdNb=Firm_CRD).parent # 处理提取到的Firm标签内容 # 方式2:使用attrs字典(更灵活,适合动态属性场景) for Firm_CRD in firm_crd_list: select_firm = soup.find(attrs={'FirmCrdNb': Firm_CRD}).parent # 处理提取到的Firm标签内容
之前的写法无效,是因为你传给find()的是一个字符串(比如'firmcrdnb="5639055"'),find()会把它当作标签名去查找,自然匹配不到结果。
二、优化大XML文件的搜索速度
SEC的XML文件体积较大,直接用BeautifulSoup加载整个文档会导致解析慢、内存占用高,甚至触发pydevd警告。可以通过以下方式优化:
1. 使用SoupStrainer只解析目标标签
SoupStrainer能让BeautifulSoup只解析你关心的标签,忽略无关内容,大幅降低解析时间和内存占用:
from bs4 import BeautifulSoup, SoupStrainer # 只解析<Info>标签(FirmCrdNb属性在该标签内) only_info_tags = SoupStrainer('Info') with open(Firm_Download_name, 'r') as f: # 仅生成包含目标标签的soup对象 soup = BeautifulSoup(f, 'lxml', parse_only=only_info_tags) # 遍历CRD列表查找 for Firm_CRD in firm_crd_list: info_tag = soup.find(attrs={'FirmCrdNb': Firm_CRD}) if info_tag: select_firm = info_tag.parent # 获取上级<Firm>标签 # 提取子标签数据
2. 改用lxml的iterparse流式解析
如果文件超大,流式解析是更高效的方案——无需加载整个文档到内存:
import lxml.etree as ET # 将CRD列表转为集合,提升查找效率 firm_crd_set = set(firm_crd_list) # 流式遍历XML,仅处理<Firm>标签 for event, elem in ET.iterparse(Firm_Download_name, events=('end',), tag='Firm'): info_elem = elem.find('Info') if info_elem is not None: firm_crd = info_elem.get('FirmCrdNb') # 匹配目标CRD时提取数据 if firm_crd in firm_crd_set: main_addr = elem.find('MainAddr') if main_addr: city = main_addr.get('City') state = main_addr.get('State') # 处理提取到的数据 # 清理已处理元素,释放内存 elem.clear() while elem.getprevious() is not None: del elem.getparent()[0]
3. 调试时避免查看整个soup对象
你遇到的pydevd warning是因为调试工具试图生成整个soup对象的字符串表示,而大文件的soup体积极大,导致耗时过长。调试时只查看单个标签或属性即可,不要直接展开整个soup对象。
内容的提问来源于stack exchange,提问作者Astaldaran
相关产品推荐
相关产品推荐

