爬取DataFrame与Excel转换DataFrame按名称匹配时ValueError问题的解决方案咨询
解决DataFrame匹配时的ValueError问题及实现商品价格监控逻辑
你遇到的ValueError完全是因为直接对布尔Series做真值判断导致的——df1["Item Name"].str.contains(x)返回的是一个包含True/False的Series,而if语句需要的是单个布尔值,Python没法确定你要判断这个Series里的所有元素还是任意元素,所以抛出了这个模糊性错误。
针对你的需求(匹配相同商品名称并执行价格分析),用Pandas的merge关联两个DataFrame是更高效且符合Pandas idiomatic的方式,比循环遍历要简洁得多,也能避免这类错误。下面是重构后的代码和思路:
核心思路
- 用
merge将新爬取的df和历史Excel的df1按Item Name做内连接,直接得到所有名称匹配的商品行对。 - 针对每一对匹配的行,处理不同的价格可用场景(原价/折扣价是否为"Not Available"),计算价格差异。
- 更新
df1中的价格(如果新价格更便宜),同时收集价格下降的记录到cheap_cheap。 - 处理
df中未在df1出现的商品(可选,根据你的需求决定是否添加到历史数据)。
修改后的代码
import pandas as pd import asyncio # 假设pricecompare是你已经定义好的价格比较函数,比如返回新价格减旧价格的数值 def pricecompare(new_price, old_price): # 这里需要把字符串价格转成数值,比如去掉货币符号、逗号等 new = float(new_price.replace('$', '').replace(',', '')) old = float(old_price.replace('$', '').replace(',', '')) return new - old def pricemonitor(category): global cheap_cheap # 执行爬取,得到新的df(这里假设searching函数返回爬取后的DataFrame) df = asyncio.run(searching(category)) # 读取历史Excel数据 df1 = pd.read_excel(f"C:\\Users\\N\\PycharmProjects\\pythonProject\\Scrapped results\\{category}.xlsx") # 初始化价格下降记录DataFrame if 'cheap_cheap' not in globals(): cheap_cheap = pd.DataFrame(columns=["Item Name", "New Price", "Old Price", "Amount difference"]) # 1. 关联两个DataFrame,找到名称匹配的商品 merged = pd.merge(df, df1, on="Item Name", suffixes=('_new', '_old'), how='inner') # 2. 遍历匹配的行,处理价格比较和更新 for idx, row in merged.iterrows(): item_name = row["Item Name"] # 定义各价格变量 new_item_price = row["Item Price_new"] new_disc_price = row["Discounted Price_new"] old_item_price = row["Item Price_old"] old_disc_price = row["Discounted Price_old"] cheaper = None new_price = None old_price = None # 场景1:原价和折扣价都可用 if (new_item_price != "Not Available" and new_disc_price != "Not Available" and old_item_price != "Not Available" and old_disc_price != "Not Available"): cheaper = pricecompare(new_disc_price, old_disc_price) new_price = new_disc_price old_price = old_disc_price # 场景2:只有原价可用 elif new_item_price != "Not Available" and old_item_price != "Not Available": cheaper = pricecompare(new_item_price, old_item_price) new_price = new_item_price old_price = old_item_price # 场景3:只有折扣价可用 elif new_disc_price != "Not Available" and old_disc_price != "Not Available": cheaper = pricecompare(new_disc_price, old_disc_price) new_price = new_disc_price old_price = old_disc_price else: # 无可用价格,跳过 continue # 如果新价格更便宜(cheaper为负,因为new - old < 0) if cheaper < 0: # 记录价格变化 cheap_row = pd.DataFrame({ "Item Name": [item_name], "New Price": [new_price], "Old Price": [old_price], "Amount difference": [cheaper] }) cheap_cheap = pd.concat([cheap_cheap, cheap_row], ignore_index=True) # 更新df1中的对应价格 if new_price == new_disc_price: df1.loc[df1["Item Name"] == item_name, "Discounted Price"] = new_disc_price else: df1.loc[df1["Item Name"] == item_name, "Item Price"] = new_item_price # 可选:把df中未在df1出现的商品添加到df1中(如果需要扩充历史数据) new_items = df[~df["Item Name"].isin(df1["Item Name"])] df1 = pd.concat([df1, new_items], ignore_index=True) # 保存更新后的df1回Excel df1.to_excel(f"C:\\Users\\N\\PycharmProjects\\pythonProject\\Scrapped results\\{category}.xlsx", index=False)
关键改进点
- 避免循环遍历单个值:用
merge直接关联匹配的商品,比你原来的循环更高效,尤其是数据量大的时候。 - 修复变量名冲突:原来的函数参数
x和循环变量x重名,现在改成category避免混淆。 - 明确价格场景处理:把不同的价格可用情况拆分成清晰的条件分支,逻辑更易读。
- 正确更新df1:用
df1.loc[df1["Item Name"] == item_name, ...]精准定位要更新的行,避免批量赋值错误。 - 初始化全局变量:添加了
cheap_cheap的初始化逻辑,防止第一次运行时变量未定义。
另外,还要注意pricecompare函数需要正确处理字符串格式的价格(比如去掉货币符号、千位分隔符),如果你的价格格式不同,需要调整这个函数的逻辑。
内容的提问来源于stack exchange,提问作者NZH
相关产品推荐
相关产品推荐

