for循环更新字典仅保留最后一次爬取数据的问题排查
问题根本原因
两个核心逻辑错误导致最终输出仅保留最后一页数据:
- 字典key唯一性触发覆盖:所有待爬页面结构完全一致,从表格中提取的字段名(即字典键/key)完全相同。Python原生字典的key具有全局唯一性,当你在循环中反复调用
final_dict.update()传入同key的键值对时,新传入的值会直接替换掉该key对应的旧值,循环执行完后自然只会保留最后一个页面的所有字段值。 - DataFrame构造逻辑不符合需求:你最后使用
pd.DataFrame([final_dict])构造表格时,是把整个字典作为单行数据传入,就算不存在key覆盖问题,最终也只会生成1行数据,完全无法承载多页的多行数据。
额外隐患:外层循环遍历页面列表时使用i作为循环变量,内层遍历标签、数据节点时也复用i作为循环变量,属于变量名污染,后续新增逻辑时很容易引发非预期的变量覆盖错误。
修复方案
不要用单个字典存储所有页面的数据,改用列表逐页存储结果:每爬完一个页面,就把当前页两个表格合并后的字典作为独立元素追加到结果列表中,最后直接把整个列表传入pd.DataFrame()即可,列表中的每个字典会自动对应DataFrame的一行,从根源上避免同key覆盖的问题。
修正后的可运行代码:
import requests from bs4 import BeautifulSoup import pandas as pd pages = ['https://example.com/page1.html', 'https://example.com/page2.html'] # 初始化列表存储每一页的结果,替代原来的单个字典 result_list = [] for url in pages: r = requests.get(url) soup = BeautifulSoup(r.content, 'html.parser') # 解析第一个表格 first_table = soup.select_one("table:nth-of-type(1)") # 提取标签文本 label_filter = [] labels = first_table.find_all('td', class_='label') for label in labels: label_filter.extend(label.find_all('span', class_='txt')) label_filter_txt = [item.text for item in label_filter] # 提取对应数据文本 label_data = [] datapoints = first_table.find_all('td', class_='data') for point in datapoints: label_data.extend(point.find_all('span', class_='txt')) label_data_txt = [item.text for item in label_data] first_table_dict = dict(zip(label_filter_txt, label_data_txt)) # 解析第二个表格 second_table = soup.select_one("table:nth-of-type(2)") # 提取标签文本 label_filter = [] labels = second_table.find_all('td', class_='label') for label in labels: label_filter.extend(label.find_all('span', class_='txt')) label_filter_txt = [item.text for item in label_filter] # 提取对应数据文本 label_data = [] datapoints = second_table.find_all('td', class_='data') for point in datapoints: label_data.extend(point.find_all('span', class_='txt')) label_data_txt = [item.text for item in label_data] second_table_dict = dict(zip(label_filter_txt, label_data_txt)) # 合并当前页两个表格的数据,追加到结果列表 page_dict = {} page_dict.update(first_table_dict) page_dict.update(second_table_dict) result_list.append(page_dict) # 直接传入结果列表构造DataFrame,每个元素对应一行数据 df = pd.DataFrame(result_list)
如果你有特殊需求必须把所有数据存在同一个字典而非按行存储,只需要给每个页面的字段key加上唯一标识即可,比如将key调整为
{page_index}_{field_name}格式,保证不同页面的key不重复就不会触发覆盖。但从生成结构化二维表格的需求来看,用列表逐行存储是最简洁、性能最优的方案。
内容的提问来源于stack exchange,提问作者interferemadly
相关产品推荐
相关产品推荐

