Scrapy+BeautifulSoup爬虫报d3赋值前引用UnboundLocalError求解
报错原因
触发UnboundLocalError: local variable 'd3' referenced before assignment的根本原因是:你把d3、d1这类变量的赋值逻辑全放在了try块里,当页面不存在对应字段、try块代码抛出异常时,except分支只写了pass直接跳过赋值,后续yield读取变量时,该变量从未被声明创建,自然会报未赋值错误。
除此之外你的代码还有两个会导致数据异常的问题:
- 每遍历到一个
div.line_list_K块就执行一次yield,会把单条律师详情拆成多条缺字段的无效数据 - 列表页提取的详情页地址是相对路径,直接发起请求可能出现域名拼接失败的问题
修复方法
- 解析字段前先给所有要输出的字段设置默认空值,就算对应字段不存在,变量也已经被定义,不会触发未赋值错误
- 调整yield逻辑,等整个页面所有字段解析完成后,只返回一条完整数据
- 用
response.urljoin()把提取到的相对路径补全为绝对地址,避免请求出错
修复后可运行代码
import scrapy from scrapy.http import Request from scrapy.crawler import CrawlerProcess from bs4 import BeautifulSoup class TestSpider(scrapy.Spider): name = 'test' start_urls = ['https://rejestradwokatow.pl/adwokat/list/strona/1/sta/2,3,9'] custom_settings = { 'CONCURRENT_REQUESTS_PER_DOMAIN': 1, 'DOWNLOAD_DELAY': 1, 'USER_AGENT': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' } def parse(self, response): soup = BeautifulSoup(response.text, 'html.parser') tra = soup.find_all('td', class_='icon_link') for links in tra: for link in links.find_all('a', href=True): # 补全相对链接为绝对地址 comp = response.urljoin(link['href']) yield Request(comp, callback=self.parse_book) def parse_book(self, response): soup = BeautifulSoup(response.text, 'html.parser') # 提前初始化所有字段默认值,从根源避免未赋值错误 data = { 'status': '', 'd1': '', 'd3': '', 'd4': '', 'd5': '' } details = soup.find_all('div', class_='line_list_K') for detail in details: try: data['status'] = detail.find('span', string='Status:').findNext('div').get_text(strip=True) except AttributeError: pass try: data['d1'] = detail.find('span', string='Data wpisu w aktualnej izbie na listę adwokatów:').findNext('div').get_text(strip=True) except AttributeError: pass try: data['d3'] = detail.find('span', string='Ostatnie miejsce wpisu:').findNext('div').get_text(strip=True) except AttributeError: pass try: data['d4'] = detail.find('span', string='Stary nr wpisu:').findNext('div').get_text(strip=True) except AttributeError: pass try: data['d5'] = detail.find('span', string='Zastępca:').findNext('div').get_text(strip=True) except AttributeError: pass # 所有字段解析完成后只返回一条完整数据 yield data if __name__ == "__main__": process = CrawlerProcess() process.crawl(TestSpider) process.start()
优化提示
- 把裸
except:替换为except AttributeError:,只捕获标签不存在导致的属性错误,不会吞掉其他代码逻辑错误,方便后续排查问题 - 调用
get_text()时加上strip=True参数,自动去除文本前后的换行、多余空格,不需要后续单独清洗 - Scrapy自带的CSS/XPath选择器性能远高于BeautifulSoup,后续可以直接用内置选择器解析,减少依赖。
内容的提问来源于stack exchange,提问作者Amen Aziz
相关产品推荐
相关产品推荐

