如何用BeautifulSoup多页爬取数据?解决数组长度不一致报错
排查爬取多页数据时「All arrays must be of the same length」错误
这个错误的核心是你用来构建DataFrame的各个列表(如tahun、harga_list、distance等)长度不一致,Pandas要求所有列的行数必须完全匹配。下面是代码里的具体问题和修复方案:
一、代码中的关键问题
1. 空URL与User-Agent导致请求无效
代码里url = f""和headers = {"User-Agent": }都是空值,直接导致请求失败,返回空页面后无法获取数据,部分列表会是空的,和其他正常列表长度不匹配。
2. 硬索引操作引发异常与长度差异
- 直接取
containers[0]:如果页面找不到class为grid的div,会触发索引越界;即使找到,若容器下的judul、harga、specs数量不一致(比如某条数据缺价格或规格),也会导致对应列表长度不同。 k.split('|')[1]到[5]的硬索引:如果某条规格文本分割后不足6个元素,会触发索引越界,同时跳过该元素的添加,导致distance、transmit等列表长度小于judul_list。
3. 标题分割的硬编码容错性差
用a.split()[0]、[1]、[2]直接分割标题,遇到格式不符合预期的标题(比如字段不足3个)会触发索引错误,生成的tahun、merek、series列表会出现缺失值或长度异常。
4. 未处理请求失败场景
没有检查请求状态码,若某页请求失败(如404、500),继续解析空页面会导致对应列表无法添加数据,长度不匹配。
二、修复后的代码示例
import requests from bs4 import BeautifulSoup import pandas as pd def replaced(text): return text.replace('\n\n\n\n\n','').strip() total_page = 3 current_page = 1 judul_list = [] harga_list = [] distance = [] transmit = [] location = [] sp = [] rec_seller = [] # 补全实际的分页URL模板和User-Agent BASE_URL = "这里填你的分页URL模板,比如https://example.com/page={}" HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } while current_page <= total_page: url = BASE_URL.format(current_page) page_request = requests.get(url, headers=HEADERS) # 检查请求是否成功 if page_request.status_code != 200: print(f"第{current_page}页请求失败,状态码:{page_request.status_code}") current_page +=1 continue soup = BeautifulSoup(page_request.content, "html.parser") containers = soup.find_all('div', {'class' : 'grid'}) # 检查是否找到目标容器 if not containers: print(f"第{current_page}页未找到目标容器") current_page +=1 continue container = containers[0] # 提取标题 judul = container.findAll('h2', {'class' : 'listing__title epsilon flush'}) judul_list += [replaced(i.text) for i in judul] # 提取价格并对齐长度 harga = container.findAll('div', {'class' : 'listing__price delta weight--bold'}) harga_texts = [replaced(j.text) for j in harga] if len(harga_texts) < len(judul): harga_texts += [None]*(len(judul)-len(harga_texts)) harga_list += harga_texts # 提取规格并安全分割 specs = container.findAll('div', {'class' : 'listing__specs soft-quarter--ends soft-half--sides milli'}) specs_list = [replaced(k.text) for k in specs] # 对齐规格列表与标题列表长度 if len(specs_list) < len(judul): specs_list += [""]*(len(judul)-len(specs_list)) for k in specs_list: parts = [p.strip() for p in k.split('|') if p.strip()] # 按位置取值,不足则填None distance.append(parts[1] if len(parts)>=2 else None) transmit.append(parts[2] if len(parts)>=3 else None) location.append(parts[3] if len(parts)>=4 else None) sp.append(parts[4] if len(parts)>=5 else None) rec_seller.append(parts[5] if len(parts)>=6 else None) current_page += 1 # 安全分割标题字段 tahun = [] merek = [] series = [] for a in judul_list: parts = a.split() tahun.append(parts[0].strip('|') if len(parts)>=1 else None) merek.append(parts[1].strip('|') if len(parts)>=2 else None) series.append(parts[2].strip('|') if len(parts)>=3 else None) # 统一所有列表长度到最短值 min_length = min( len(tahun), len(merek), len(series), len(harga_list), len(distance), len(transmit), len(location), len(sp), len(rec_seller) ) # 截断所有列表到相同长度 tahun = tahun[:min_length] merek = merek[:min_length] series = series[:min_length] harga_list = harga_list[:min_length] distance = distance[:min_length] transmit = transmit[:min_length] location = location[:min_length] sp = sp[:min_length] rec_seller = rec_seller[:min_length] # 创建DataFrame data = { 'Tahun': tahun, 'Merek': merek, 'Series': series, 'Harga': harga_list, 'Distance': distance, 'Transmit': transmit, 'Location': location, 'SP': sp, 'Rec_Seller': rec_seller } df = pd.DataFrame(data) print(df)
三、关键修复点说明
- 补全URL模板和User-Agent,确保请求有效;
- 增加请求状态和容器存在性检查,避免无效解析;
- 对价格、规格列表做长度对齐,不足时补
None; - 规格分割时用长度判断避免索引越界;
- 标题分割改为循环处理,增加容错;
- 最后统一所有列表长度到最小值,确保DataFrame能正常创建。
内容的提问来源于stack exchange,提问作者abbym
相关产品推荐
相关产品推荐

