爬取Flipkart手机数据转换为Pandas DataFrame时遭遇ValueError(值长度与索引不匹配)的问题求助
解决Flipkart爬虫字段长度不匹配的问题
问题诊断
你遇到的ValueError本质是不同字段的抓取结果数量不一致:名称只抓了主列表的24个产品,但价格等字段把页面底部额外推荐的5个产品也抓进来了,导致总长度不匹配。
为什么会这样?因为你当前的代码是在整个页面的产品列表容器里批量提取所有名称、所有价格,而不是绑定每个产品的独立数据。底部的额外推荐产品可能和主列表的产品使用了不同的名称class,但价格class是一样的,所以价格列表多了额外的条目,而名称列表没有,最终导致Pandas创建DataFrame时长度不匹配。
解决方案:按单个产品容器抓取数据
正确的做法是先定位每个产品的独立卡片容器,然后在每个容器内单独提取该产品的所有字段。这样每个产品的所有字段要么都能抓到,要么统一用默认值填充,保证所有列表的长度完全一致。
修正后的代码
import requests from bs4 import BeautifulSoup import pandas as pd # 初始化存储列表,每个元素是一个产品的字典 products_data = [] lst = ['samsung', 'redmi', 'realme', 'vivo', 'moto'] # 修正拼写错误:motto → moto n_pages = 0 for page in range(1, 15): n_pages += 1 # 修正URL中的品牌变量:循环取单个品牌,而非整个列表 url = f"https://www.flipkart.com/search?q={lst[page%5]}+mobiles&sid=tyy%2C4io&as=on&as-show=on&otracker=AS_QueryStore_OrganicAutoSuggest_1_2_na_na_ps&otracker1=AS_QueryStore_OrganicAutoSuggest_1_2_na_na_ps&as-pos=1&as-type=RECENT&suggestionId=samsung+mobiles%7CMobiles&requestId=346f99ae-2791-4d89-b63a-2e4af06e0a63&page={page}" res = requests.get(url) soup = BeautifulSoup(res.content, 'html.parser') # 定位每个独立的产品卡片容器(核心改进点) product_cards = soup.find_all("div", class_="_1AtVbE col-12-12") for card in product_cards: # 跳过广告或非产品卡片 if card.find("div", class_="_1xHGtK _373qXS"): continue # 提取单个产品的所有字段,找不到则用None填充 product_name = card.find("div", class_="_4rR01T").text if card.find("div", class_="_4rR01T") else None price = card.find("div", class_="_30jeq3").text if card.find("div", class_="_30jeq3") else None actual_price = card.find("div", class_="_3I9_wc").text if card.find("div", class_="_3I9_wc") else None features = card.find("ul", class_="_1xgFaf").text if card.find("ul", class_="_1xgFaf") else None discount = card.find("span", class_="_3Ay6Sb").text if card.find("span", class_="_3Ay6Sb") else None rating_count = card.find("span", class_="_2_R_DZ").text if card.find("span", class_="_2_R_DZ") else None stars = card.find("div", class_="_3LWZlK").text if card.find("div", class_="_3LWZlK") else None # 将单个产品数据添加到列表 products_data.append({ 'product': product_name, 'price': price, 'actual_price': actual_price, 'features': features, 'discount': discount, 'rating': rating_count, 'stars': stars }) # 直接从字典列表创建DataFrame,无需担心长度匹配 df = pd.DataFrame(products_data) print(df.head())
关键改进点
- 按产品卡片遍历:不再全局提取所有名称/价格,而是针对每个产品卡片单独提取,保证每个产品的字段一一对应。
- 处理缺失字段:用
if ... else None处理可能缺失的字段(比如有些产品没有折扣或评分),避免列表长度不一致。 - 跳过广告卡片:页面中可能存在广告卡片,通过判断特定class跳过,避免抓取无效数据。
- 修正URL变量:原来的URL中
{lst}是整个列表,改为循环品牌列表中的单个品牌(同时修正了motto为moto的拼写错误)。 - 用字典列表存储数据:更直观,且Pandas可以直接从字典列表创建DataFrame,自动处理所有字段的长度匹配。
为什么原来的代码会出错?
原来的代码中,mobile_data = soup.find_all("div", class_="_1YokD2")是抓取整个产品列表的容器,然后在这个容器内用find_all提取所有名称、所有价格,这会把页面底部额外推荐的产品(可能属于不同的列表)的价格也抓进来,但这些推荐产品的名称可能使用了不同的class,所以名称列表没有这些条目,最终导致价格列表长度 > 名称列表长度,触发Pandas的长度匹配错误。
内容的提问来源于stack exchange,提问作者sumeet kumar
相关产品推荐
相关产品推荐

