Python大数据实战(一):Scrapy爬取二手车数据+GBDT价格预测完整项目
2026/6/23 4:17:52 网站建设 项目流程

Python大数据实战(一):Scrapy爬取二手车数据+GBDT价格预测完整项目


文章目录

  • Python大数据实战(一):Scrapy爬取二手车数据+GBDT价格预测完整项目
  • 前言
  • 一、项目概述
    • 1.1 项目架构总览
    • 1.2 学习目标
    • 1.3 数据来源
    • 1.4 项目目标
  • 二、Scrapy 爬虫:数据采集
    • 2.1 创建爬虫项目
    • 2.2 定义数据模型(Item)
    • 2.3 编写爬虫逻辑(Spider)
    • 2.4 启动爬虫
  • 三、Pandas 数据分析与特征工程
    • 3.1 标签数据预处理
    • 3.2 标签 One-Hot 编码
    • 3.3 价格分析:哪些品牌最贵?
    • 3.4 销量分析:哪些品牌最畅销?
    • 3.5 价格分布分析(以"大众"为例)
    • 3.6 品牌 One-Hot 编码
  • 四、GBDT 建模与评估
    • 4.0 GBDT 算法原理(一图看懂)
    • 4.1 数据准备
    • 4.2 模型训练
    • 4.3 模型评估
    • 4.4 特征重要性分析
  • 五、常见错误与解决方案
    • 错误 1:Scrapy 爬取被反爬拦截
    • 错误 2:中文显示乱码
    • 错误 3:One-Hot 编码后特征爆炸
  • 六、总结

前言

“这辆二手车值多少钱?”——这是每个买车人和卖车人都想知道答案的问题。

对于数据从业者来说,二手车价格预测是一个经典的"爬虫 + 数据分析 + 机器学习"综合实战项目。它不像鸢尾花分类那样简单,也不像推荐系统那样复杂,刚好卡在"能学到东西又不至于劝退"的甜点区。

本文带你从零开始,用 Scrapy 爬取人人车真实数据,用 Pandas 做数据清洗和特征工程,最后用 GBDT(梯度提升决策树)建立价格预测模型。全程代码可运行,适合有 Python 基础、想入门大数据项目的同学。


一、项目概述

1.1 项目架构总览

人人车网站 → Scrapy爬虫 → 原始数据CSV → Pandas清洗 → 标签拆分+OneHot → 品牌编码+标签编码 → Matplotlib可视化分析 → GBDT回归模型 → 价格预测评估

1.2 学习目标

阶段技能工具/库
数据采集Scrapy 爬虫框架Scrapy
数据处理数据清洗、标签编码、One-HotPandas、NumPy
数据分析价格分布、品牌销量、概率密度Matplotlib、Seaborn、SciPy
机器学习回归预测、模型评估Scikit-learn(GBDT)

1.3 数据来源

爬取人人车网站(https://www.renrenche.com/)的二手车信息,包含:

  • 品牌(brand):大众、丰田、本田、宝马……
  • 价格(price):二手车挂牌价格
  • 标签(tag):如"准新车"“急售”"0过户"等

1.4 项目目标

通过已有数据建立回归模型,对二手车价格进行预测,最终用 MSE、MAE、RMSE、R² 四个指标评估模型效果。


二、Scrapy 爬虫:数据采集

2.1 创建爬虫项目

# 创建 Scrapy 项目scrapy startproject ershouche# 进入项目目录,创建爬虫文件cdershouche scrapy genspider car www.renrenche.com

执行后项目结构如下:

ershouche/ ├── ershouche/ │ ├── spiders/ │ │ └── car.py # 爬虫逻辑 │ ├── items.py # 数据模型 │ ├── pipelines.py # 数据处理管道 │ └── settings.py # 项目配置 └── scrapy.cfg

2.2 定义数据模型(Item)

# items.pyimportscrapyclassErshoucheItem(scrapy.Item):"""二手车数据模型"""brand=scrapy.Field()# 品牌,如"大众"price=scrapy.Field()# 价格,如"8.5万"tag=scrapy.Field()# 标签,如"准新车_急售"

2.3 编写爬虫逻辑(Spider)

# spiders/car.pyimportscrapyfromershouche.itemsimportErshoucheItemclassCarSpider(scrapy.Spider):name='car'allowed_domains=['renrenche.com']start_urls=['https://www.renrenche.com/xa/ershouche/']defparse(self,response):"""解析当前页的二手车列表"""# 获取当前页所有二手车列表项car_list=response.xpath("//ul[@class='row-fluid list-row js-car-list']/li")forliincar_list:item=ErshoucheItem()# 提取品牌brand=li.xpath(".//a[@class='brand']/text()").extract_first()item['brand']=brand.strip()ifbrandelse''# 提取价格price=li.xpath(".//div[@class='price']/text()").extract_first()item['price']=price.strip()ifpriceelse''# 提取标签(多个标签用下划线连接)tag_list=li.xpath(".//div[@class='tag']/span/text()").extract()item['tag']='_'.join([t.strip()fortintag_list])yielditem# 翻页处理next_url=response.xpath('//ul[@class="pagination js-pagination"]/li[last()]/a/@href').extract_first()# 如果不是最后一页,继续爬取ifnext_urlandnext_url!="javascript:void(0);":next_url=response.urljoin(next_url)yieldscrapy.Request(next_url,callback=self.parse)

2.4 启动爬虫

# 在项目根目录执行scrapy crawl car-ocars.csv# 输出为 CSV 文件

⚠️ 注意事项:爬取前请确认目标网站的 robots.txt 协议,合理设置下载延迟(DOWNLOAD_DELAY = 2),避免对目标服务器造成压力。


三、Pandas 数据分析与特征工程

3.1 标签数据预处理

爬取到的tag字段包含多个标签(如"准新车_急售_0过户"),需要拆分为独立的特征列。

importpandasaspdimportnumpyasnp# 读取数据dataset=pd.read_csv('cars.csv')# 过滤掉标签为空的数据(数据量很少,不影响整体)dataset=dataset[dataset["tag"].notna()]# 收集所有唯一标签tag_list=[]dataset["tag"].apply(lambdax:tag_list.extend(x.split("_")))tag_list=list(set(tag_list))# 去重print(f"共有{len(tag_list)}种标签:{tag_list[:10]}")

3.2 标签 One-Hot 编码

将标签转换为 0/1 特征矩阵:

# 创建标签特征 DataFrame,初始值全为 0tag_df=pd.DataFrame(columns=tag_list)df=pd.concat([dataset,tag_df],sort=False)df[tag_list]=df[tag_list].fillna(0)defset_tag_status(series):"""将当前行的标签设置为 1"""tags=series["tag"].split("_")fortintags:iftintag_list:series[t]=1returnseries# 对每一行应用标签编码df[tag_list]=df[["tag",*tag_list]].apply(lambdax:set_tag_status(x),axis=1).drop("tag",axis=1)df=df.drop("tag",axis=1)# 删除原始 tag 列print(f"特征矩阵形状:{df.shape}")

3.3 价格分析:哪些品牌最贵?

importmatplotlib.pyplotaspltimportseabornassns# 设置中文字体(避免乱码)plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False# 平均价格最高的前 10 个品牌num_top=df.groupby("brand")["price"].mean().sort_values(ascending=False)[:10]# 绘制条形图fig=plt.figure(figsize=(15,10))sns.barplot(x=num_top.index,y=num_top.values)plt.title("二手车平均价格 Top 10 品牌")plt.xticks(rotation=90)plt.ylabel("平均价格(万元)")plt.tight_layout()plt.show()

3.4 销量分析:哪些品牌最畅销?

# 销量最多的前 10 个品牌amount_top=df["brand"].value_counts().sort_values(ascending=False)[:10]# 条形图fig=plt.figure(figsize=(12,8))sns.barplot(x=amount_top.index,y=amount_top.values)plt.title("二手车销量 Top 10 品牌")plt.xticks(rotation=90)plt.ylabel("数量(辆)")plt.tight_layout()plt.show()# 饼图:各品牌占比fig=plt.figure(figsize=(10,10))plt.pie(amount_top.values,labels=amount_top.index,autopct="%1.2f%%")plt.title("各大品牌车系数量占有比重前 10 位")plt.show()

3.5 价格分布分析(以"大众"为例)

fromscipy.statsimportnorm# 筛选大众品牌数据df_dazhong=df[df["brand"]=="大众"]dazhong_mean=df_dazhong["price"].mean()# 均值dazhong_std=df_dazhong["price"].std()# 标准差# 绘制直方图 + 概率密度曲线num_bins=20n,bins,patches=plt.hist(df_dazhong["price"],num_bins,facecolor="green",density=True,alpha=0.5)# 叠加正态分布概率密度曲线y=norm.pdf(bins,dazhong_mean,dazhong_std)plt.plot(bins,y,"r--",linewidth=2,label="正态分布拟合")plt.xlabel("价格(万元)")plt.ylabel("概率密度")plt.title(f"大众二手车价格分布(均值={dazhong_mean:.2f}万,标准差={dazhong_std:.2f}万)")plt.legend()plt.show()

3.6 品牌 One-Hot 编码

# 对品牌进行 One-Hot 编码one_hot_df=pd.get_dummies(df["brand"])df=df.drop("brand",axis=1)# 删除原始 brand 列# 合并 One-Hot 列df=pd.merge(df,one_hot_df,left_index=True,right_index=True)print(f"One-Hot 编码后特征数:{df.shape[1]}")

四、GBDT 建模与评估

4.0 GBDT 算法原理(一图看懂)

GBDT(Gradient Boosting Decision Tree)的核心思想是串行训练多棵决策树,每棵树都在修正前面所有树的残差

第1棵树: 预测 → 残差1 = 真实值 - 预测值1 第2棵树: 拟合残差1 → 残差2 = 残差1 - 预测值2 第3棵树: 拟合残差2 → 残差3 = 残差2 - 预测值3 ... 最终预测 = 树1预测 + 树2预测 + 树3预测 + ...
对比维度随机森林GBDT
训练方式并行(Bagging)串行(Boosting)
每棵树关系独立依赖前序树
偏差较低更低
方差较低较高(需控制学习率)
适用场景通用追求高精度

4.1 数据准备

fromsklearn.model_selectionimporttrain_test_splitfromsklearn.ensembleimportGradientBoostingRegressorfromsklearn.metricsimportmean_squared_error,mean_absolute_error,r2_score# 分离特征和标签X=df[df.columns.difference(["price"])].values# 样本特征Y=df["price"].values# 目标变量(价格)# 划分训练集和测试集(7:3)X_train,X_test,Y_train,Y_test=train_test_split(X,Y,test_size=0.3,random_state=666)print(f"训练集:{X_train.shape[0]}条, 测试集:{X_test.shape[0]}条")

4.2 模型训练

# 创建 GBDT 回归模型gbdt=GradientBoostingRegressor(n_estimators=70,# 70 棵决策树learning_rate=0.1,# 学习率max_depth=5,# 树的最大深度random_state=666)# 训练模型gbdt.fit(X_train,Y_train)# 预测pred=gbdt.predict(X_test)

4.3 模型评估

# 四大评估指标mse=mean_squared_error(Y_test,pred)mae=mean_absolute_error(Y_test,pred)rmse=np.sqrt(mse)r2=r2_score(Y_test,pred)print("="*40)print("GBDT 二手车价格预测模型评估")print("="*40)print(f"MSE (均方误差):{mse:.2f}")print(f"MAE (平均绝对误差):{mae:.2f}万元")print(f"RMSE (均方根误差):{rmse:.2f}万元")print(f"R² (决定系数):{r2:.4f}")print("="*40)# 解读ifr2>0.8:print("✅ 模型效果优秀,可以用于实际预测")elifr2>0.6:print("⚠️ 模型效果一般,建议调参优化")else:print("❌ 模型效果较差,需要更多特征或数据")

4.4 特征重要性分析

# 查看哪些特征对价格预测影响最大feature_importance=pd.DataFrame({'feature':df.columns.difference(["price"]),'importance':gbdt.feature_importances_}).sort_values('importance',ascending=False)print("Top 10 重要特征:")print(feature_importance.head(10))

五、常见错误与解决方案

错误 1:Scrapy 爬取被反爬拦截

# ❌ 错误:直接高频请求,被网站封 IPscrapy crawl car# 无任何反爬措施# ✅ 正确:配置下载延迟和 User-Agent# settings.pyDOWNLOAD_DELAY=2# 每次请求间隔 2 秒RANDOMIZE_DOWNLOAD_DELAY=True# 随机延迟DEFAULT_REQUEST_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',}

错误 2:中文显示乱码

# ❌ 错误:matplotlib 默认不支持中文plt.title("二手车价格分布")# 显示为方框# ✅ 正确:设置中文字体plt.rcParams['font.sans-serif']=['SimHei','DejaVu Sans']plt.rcParams['axes.unicode_minus']=False# 解决负号显示问题

错误 3:One-Hot 编码后特征爆炸

# ❌ 问题:品牌有 100+ 种,One-Hot 后特征数暴增# 解决方案:只保留出现频率最高的 Top N 品牌top_brands=df["brand"].value_counts().head(20).index.tolist()df["brand"]=df["brand"].apply(lambdax:xifxintop_brandselse"其他")# 然后再做 One-Hot,特征数从 100+ 降到 21

六、总结

本文完成了一个完整的"爬虫 → 数据分析 → 机器学习"项目实战:

  1. Scrapy 爬虫:从人人车采集真实二手车数据,含翻页处理
  2. Pandas 数据处理:标签拆分、One-Hot 编码、品牌编码
  3. 数据可视化:价格 Top 10、销量占比饼图、价格概率密度分布
  4. GBDT 建模:70 棵决策树的梯度提升回归,四大指标评估

核心收获:一个完整的数据项目不是"调个包就完事了",数据采集和特征工程往往占 80% 的工作量。爬虫写得好不好、特征做得细不细,直接决定模型效果的上限。

下一篇我们将实战工资分类预测项目,用逻辑回归和随机森林预测你的薪资属于哪个区间——敬请期待!


参考链接:

  • Scrapy 官方文档
  • Scikit-learn GBDT 文档
  • Pandas 数据处理指南
  • Matplotlib 中文显示方案

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询