Python爬取网站时字典/列表值被统一覆盖为最新值的问题求助
解决Python爬取时字典/列表所有值被覆盖的问题
你碰到的这个问题,本质是可变对象的引用复用导致的。字典、列表这类可变类型,当你把它们添加到容器里时,存的不是具体的值,而是对象的内存引用。如果每次爬取都修改同一个对象,那容器里所有引用都会指向这个被反复修改的对象,最后自然全变成最新的内容。
先看错误示例(复现你的问题)
比如你可能写了这样的代码:
# 提前定义了一个全局的结果字典 result = {} def crawl(url): # 每次爬取都修改同一个result对象 result["url"] = url result["content"] = f"从{url}获取的内容" return result urls = ["https://site1.com", "https://site2.com", "https://site3.com"] final_dict = {} for url in urls: res = crawl(url) final_dict[url] = res print(final_dict)
运行后你会发现,final_dict里所有URL对应的内容都是最后一个网站的——因为所有值都指向同一个result字典对象。
解决办法1:每次爬取创建新对象
最直接的方式,就是在爬取函数内部每次都新建一个字典/列表,这样每次返回的都是独立的对象,互相不会干扰:
def crawl(url): # 每次调用函数都创建新的字典 result = {} result["url"] = url result["content"] = f"从{url}获取的内容" return result urls = ["https://site1.com", "https://site2.com", "https://site3.com"] final_dict = {} for url in urls: res = crawl(url) final_dict[url] = res print(final_dict)
解决办法2:返回对象的副本(如果必须复用对象)
如果因为某些场景需要在函数外复用基础对象,那返回的时候要返回对象的副本,而不是原对象的引用。浅拷贝用dict.copy(),如果有嵌套的可变结构(比如字典里套列表),就用copy.deepcopy():
import copy # 复用基础对象 base_result = {} def crawl(url): base_result["url"] = url base_result["content"] = f"从{url}获取的内容" # 返回深拷贝,避免引用复用 return copy.deepcopy(base_result) urls = ["https://site1.com", "https://site2.com", "https://site3.com"] final_dict = {} for url in urls: res = crawl(url) final_dict[url] = res print(final_dict)
列表场景的同理解决
如果是存入列表时出现同样问题,逻辑完全一致:
错误示例:
# 复用同一个列表 item = [] def crawl(url): item.clear() item.append(url) item.append(f"从{url}获取的内容") return item urls = ["https://site1.com", "https://site2.com"] final_list = [] for url in urls: final_list.append(crawl(url)) print(final_list) # 两个元素都是最后一个网站的内容
正确示例:
def crawl(url): # 每次新建列表 item = [] item.append(url) item.append(f"从{url}获取的内容") return item urls = ["https://site1.com", "https://site2.com"] final_list = [] for url in urls: final_list.append(crawl(url)) print(final_list)
总结一下:核心就是要保证添加到容器里的每个元素都是独立的对象,要么每次新建,要么拷贝副本,这样就不会出现所有值被最新结果覆盖的问题了。
内容的提问来源于stack exchange,提问作者harshvardhan
相关产品推荐
相关产品推荐

