Python爬取TrueCar数据存MySQL时出现list索引越界及写入异常
问题根因与修复方案
一、list index out of range 报错触发原因
- 你在遍历提取车型、价格、里程元素时,硬编码了循环20次的逻辑,但实际通过选择器匹配到的页面元素数量不足20个。触发该问题的常见场景:
- 请求未携带正常浏览器请求头,被truecar反爬策略拦截,返回的页面为验证拦截页,没有实际车辆内容,匹配到的元素列表为空
- 页面的元素类名、测试属性值发生调整,原有选择器无法完整匹配所有车辆卡片,抓到的元素数量达不到20个
- 一旦循环索引超过实际抓取到的列表长度,就会直接触发索引越界错误。
二、数据库写入失败的核心原因
原有实现完全不符合mysql.connector的参数传参规则,自然无法正常写入:
- SQL拼接逻辑错误:原本只需要3个字段的占位符,却把三个独立列表生成的占位符组强行拼接到单条VALUES子句中,最终生成的SQL语法完全错误
- 传参逻辑错误:
cursor.execute()仅支持传入对应单条记录的参数元组,根本不支持拆分三个列表分别传入参数的写法 - 你要将每辆车作为独立行存入表,完全不需要复杂的占位符拼接,直接使用批量插入方法即可实现需求。
三、修正后的可运行实现
import mysql.connector from bs4 import BeautifulSoup import requests # 携带正常浏览器请求头,避免被反爬拦截 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" } # 接收输入并拼接请求链接 requested_car_name = input() my_request = requests.get( 'https://www.truecar.com/used-cars-for-sale/listings/' + requested_car_name + '/location-holtsville-ny/?sort[]=best_match', headers=headers ) my_soup = BeautifulSoup(my_request.text, 'html.parser') # 提取全量匹配元素后直接截取前20条,取消硬编码循环逻辑 car_model_elems = my_soup.find_all('span', attrs={'class': 'vehicle-header-make-model text-truncate'})[:20] price_elems = my_soup.find_all('div', attrs={'data-test': 'vehicleCardPricingBlockPrice'})[:20] distance_elems = my_soup.find_all('div', attrs={'data-test': 'vehicleMileage'})[:20] # 增加基础异常判断,避免空列表操作 if not all([car_model_elems, price_elems, distance_elems]): print("页面元素匹配失败,请检查选择器有效性或反爬拦截情况") exit() # 按行组装数据:每一个元组对应一辆车的三个字段值 insert_data = [] for model, price, dist in zip(car_model_elems, price_elems, distance_elems): insert_data.append( (model.text.strip(), price.text.strip(), dist.text.strip()) ) # 原有数据库连接配置保持不变 mydb = mysql.connector.connect( host="xxxxx", user="xxxxxx", password="xxxxxx", port='xxxxxx', database='xxxxxx' ) my_cursor = mydb.cursor(buffered=True) # 使用批量插入方法写入多行,SQL保持单条3字段的标准结构 insert_sql = "INSERT INTO car_name (car_model, price, distance) VALUES (%s, %s, %s)" my_cursor.executemany(insert_sql, insert_data) mydb.commit() print(f"成功插入 {my_cursor.rowcount} 条记录") mydb.close()
注意:不同类别的页面元素抓取数量可能存在细微差异,直接用
zip()按最短列表长度对齐匹配,就不会再出现索引越界问题,也能保证三个字段的取值和对应车辆一一匹配,不会错位。
内容的提问来源于stack exchange,提问作者Xus
相关产品推荐
相关产品推荐

