当前位置: 首页 > news >正文

【代码】Python3|Scrapy框架初探(汽车之家大连市二手车车辆数据爬取、清洗与可视化)

本篇主要是整个项目的介绍,没提到太多琐碎的技术细节,以后有空的话会整理一下 Scrapy 和原生爬虫的差异,还有它坑人的一些地方,单发出来。

开源地址:https://github.com/shandianchengzi/car_home_spider

使用说明:切换到autohome_spider目录下,运行run.bat

文章目录

  • 汽车之家大连市二手车车辆数据爬取、清洗与可视化
    • 一、项目简介
    • 二、项目架构
      • 1)运行环境
      • 3)系统架构图
      • 4)数据库设计
    • 三、项目核心代码说明
      • 1)Scrapy框架数据爬取
      • 2)Pandas数据清洗与可视化
      • 3)Matplotlib数据可视化
    • 四、项目运行截图
      • 1) 爬虫结果截图
      • 2) 持久化存储结果截图
      • 3) 可视化分析图形截图
    • 五、总结
    • 六、参考资料

汽车之家大连市二手车车辆数据爬取、清洗与可视化

一、项目简介

本项目旨在通过网络爬虫技术,从“汽车之家”网站的二手车频道自动抓取各类汽车的详细信息,包括品牌、车型、价格、公里数、上牌时间等,然后利用Pandas库对数据进行清洗和可视化分析,为用户提供直观的数据展示和分析结果。通过本项目,用户可以了解到大连市二手车市场的价格分布、常购品牌等信息,为购车提供参考依据。

二、项目架构

1)运行环境

  1. 硬件系统:Intel Core i7, 16GB RAM, NVIDIA GeForce GTX 1050 Ti
  2. 操作系统:Windows 10, Version 20H2
  3. 软件版本:Python 3.8.5, SQLite 3.31.1, Visual Studio Code 1.57.1
  4. 运行时刻:2024年7月13日 23:00

3)系统架构图

在这里插入图片描述

4)数据库设计

数据存入csv文件,包含字段:品牌、上市年份、车型、表显里程(公里)、上牌时间(年)、价格(万)、原厂保修时间、所属城市、链接。

三、项目核心代码说明

1)Scrapy框架数据爬取

爬取之前,先分析网站信息。

  1. 确定网页:在网上汽车之家能找到两个网页是卖二手车的,一个在产品库1里、另一个在二手车严选2上。结果显示,2024年7月13日,产品库中的车源更多,有2714条;而二手车严选里只有1934条。因此,本项目选择产品库中的结果。

  2. 确定请求方式:打开开发者工具并刷新,然后搜索页面上的任意车辆的名称,检查返回的结果对应的请求。结果表明,请求方式为Get,请求的就是网站的链接,同时,没有传递任何Get参数。

  3. 确定传参模式:

    1. 筛选机制:注意到网页本身拥有排序功能,这样之后就不需要额外排序。它的排序选项不在参数中,在链接中,比较小众。比如a0_0msdgscncgpi1ltocsp2ex/
      对应默认排序,a0_0msdgscncgpi1lto2cspex/
      对应价格降序。

    2. 翻页机制:产品库的二手车页面中,页码也在链接中。比如a0_0msdgscncgpi1lto2csp1ex/对应第一页,a0_0msdgscncgpi1lto2csp2ex/对应第二页。

  4. 确定结果格式:由于他返回的就是网页,没有json之类的额外信息,所以爬取的结果就是网页上能看到的结果。分析页面内容,可知包含的信息为“品牌”、“上市年份”、“车型”、“实物图”、“表显里程”、“上牌时间”、“价格”、“原厂保修时间”、“所属城市”和详细信息的访问链接。观察到图片采用了懒加载技术,需要额外请求别的链接才能返回,加之数据分析时并不需要图片,因此干脆去掉实物图这一个信息。

  5. 额外注意事项:特别坑的一点是,页数超过100页时会自动重定向回到100页,而不是返回空,这样代码中加空判断就无法真正停止下来。这里得额外写一个100页的判断。而且也因为这个,最多返回结果数量2400条。考虑到总共也只有2714条,可以认为该数量是可以接受的,因此不更改筛选条件重新跑了。

分析好了这些内容之后,再开始用Scrapy写爬虫,代码如下:

  1. Spider中数据爬取解析:
class AutohomeSpider(scrapy.Spider):name = 'autohome_spider'allowed_domains = ['autohome.com.cn']base_url = 'https://car.autohome.com.cn/2sc/dalian/a0_0msdgscncgpi1lto2csp{}ex/'page = 1start_urls = ['https://car.autohome.com.cn/2sc/dalian/a0_0msdgscncgpi1lto2csp1ex/']def parse(self, response):xml = lxml.etree.HTML(response.text)piclist = xml.xpath('//div[@class="piclist"]/ul/li')if len(piclist) == 0 or self.page > 100: # max page 100returnfor car in piclist:try:l = ItemLoader(item=AutohomeItem())title = car.xpath('div[@class="title"]/a/text()')[0]title_href = car.xpath('div[@class="title"]/a/@href')[0]somethings = title.split(' ', 2)if len(somethings) != 3:with open('error.log', 'a') as f:f.write(title + '\n')continue# 获得icon_list里所有a标签的title属性并拼接非空的为字符串icon_list = car.xpath('div[@class="icon-list"]/a')city = car.xpath('div[@class="icon-list"]/span/span/text()')[0]icons_info = []for icon in icon_list:icon_info = icon.xpath('@title')if icon_info:icons_info.extend(icon_info)icons_info = ', '.join(icons_info)# 用ItemLoader加载数据l.add_value('brand', somethings[0])l.add_value('year', somethings[1])l.add_value('model', somethings[2])l.add_value('mileage', getNumberAndFloat(car.xpath('*/div[@class="detail-l"]/p[1]/text()')[0]))l.add_value('registration_time', getNumberAndFloat(car.xpath('*/div[@class="detail-l"]/p[2]/text()')[0]))l.add_value('price', car.xpath('*/div[@class="detail-r"]/span/text()'))l.add_value('warranty_time', icons_info)l.add_value('city', city)l.add_value('link', "https:" + title_href)yield l.load_item()except Exception as e:# skip no full information carpass# 下一页self.page += 1new_url = self.base_url.format(self.page)yield scrapy.Request(new_url, callback=self.parse)
  1. Pipeline中做数据存储:
class AutohomeSpiderPipeline:def open_spider(self, spider):self.file = open('autohome.csv', 'w', newline='', encoding='utf-8')self.writer = csv.DictWriter(self.file, fieldnames=['brand', 'year', 'model', 'mileage', 'registration_time', 'price', 'warranty_time', 'city', 'link'])# ['品牌', '上市年份', '车型', '表显里程(公里)', '上牌时间(年)', '价格(万)', '原厂保修时间', '所属城市', '链接']self.writer.writeheader()def close_spider(self, spider):self.file.close()def process_item(self, item, spider):# let item: {field: [value]} to {field: value}item = {k: v[0] for k, v in item.items()}self.writer.writerow(item)return item

2)Pandas数据清洗与可视化

数据清洗主要是将错误的数据修改正确或者删除,以便进一步分析。我在爬虫代码的解析过程中,对品牌的解析有误,有一些品牌的名称,本身就带空格,我用空格做分割,导致该列被解析到下一列中。代码如下:

# 数据清洗
df.drop_duplicates(inplace=True) # 去重
df.dropna(subset=['brand'], inplace=True) # 去掉品牌为空的数据
# 合并前三列的数据形成字符串,用正则重新解析,查找"xxxx款",该字符串前面的是brand,后面的是model,中间的是year
df['brand_model_year'] = df['brand'] + df['year'] + df['model'] # 辅助列
df['brand'] = df['brand_model_year'].str.extract(r'^(.*?)(\d{4}款)(.*)')[0]
df['year'] = df['brand_model_year'].str.extract(r'^(.*?)(\d{4}款)(.*)')[1]
df['model'] = df['brand_model_year'].str.extract(r'^(.*?)(\d{4}款)(.*)')[2]
df.drop(columns=['brand_model_year'], inplace=True)
df['year'] = df['year'].replace('款', '', regex=True)
# 如果原厂保修时间为空,填充为0
df['warranty_time'].fillna('0', inplace=True)
df.to_csv(result_path, index=False, encoding='gbk') # for windows excel

3)Matplotlib数据可视化

多角度可视化代码如下:

# 数据可视化
df.columns = ['品牌', '上市年份', '车型', '表显里程(公里)', '上牌时间(年)', '价格(万)', '原厂保修时间', '所属城市', '链接']
# 设置字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. 各种数据的占比统计,全画在一张图上
plt.figure(figsize=(20, 10))
# 1.1 价格分布(只做0~200万的)
plt.subplot(2, 2, 1)
sns.histplot(df['price'], bins=20, kde=True)
plt.xlim(0, 200)
plt.title('价格分布')
# 1.2 里程分布
plt.subplot(2, 2, 2)
sns.histplot(df['mileage'], bins=20, kde=True)
plt.title('里程分布')
# 1.3 品牌分布(前20,扇形图,不要x和y的label)
plt.subplot(2, 2, 3)
df['brand'].value_counts().head(20).plot.pie(autopct='%1.1f%%')
plt.ylabel('')
plt.title('品牌数量分布(前20)')
# 1.4 车型分布(前10,扇形图,不要x和y的label)
plt.subplot(2, 2, 4)
df['model'].value_counts().head(10).plot.pie(autopct='%1.1f%%')
plt.ylabel('')
plt.title('车型数量分布(前10)')
plt.savefig(os.path.join(imgs_dir, '各种数据的占比统计.png'))
# 2 时间分析
plt.figure(figsize=(20, 10))
# 2.1 上牌时间分布
plt.subplot(1, 2, 1)
sns.histplot(df['registration_time'], bins=20, kde=True)
plt.title('上牌时间分布')
# 2.2 上市年份分布
plt.subplot(1, 2, 2)
sns.histplot(df['year'], bins=20, kde=True)
plt.title('上市年份分布')
plt.savefig(os.path.join(imgs_dir, '时间分析.png'))
# 3. 保修存在性与其他数据的关系,标好图例
plt.figure(figsize=(20, 10))
# 3.1 保修存在占比(1表示存在,0表示不存在,扇形图)
plt.subplot(2, 2, 1)
df['warranty_time_exist'].value_counts().plot.pie(autopct='%1.1f%%')
plt.legend(['无保修', '有保修'])
plt.ylabel('')
plt.title('保修存在占比')
# 3.2 保修存在与价格的关系
plt.subplot(2, 2, 2)
sns.boxplot(x='warranty_time_exist', y='price', data=df)
plt.xticks([0, 1], ['无保修', '有保修'])
plt.title('保修存在与价格的关系')
# 3.3 保修存在与里程的关系
plt.subplot(2, 2, 3)
sns.boxplot(x='warranty_time_exist', y='mileage', data=df)
plt.xticks([0, 1], ['无保修', '有保修'])
plt.title('保修存在与里程的关系')
# 3.4 保修存在与上牌时间的关系
plt.subplot(2, 2, 4)
sns.boxplot(x='warranty_time_exist', y='registration_time', data=df)
plt.xticks([0, 1], ['无保修', '有保修'])
plt.title('保修存在与上牌时间的关系')
plt.savefig(os.path.join(imgs_dir, '保修是否存在与其他数据的关系.png'))

四、项目运行截图

1) 爬虫结果截图

在这里插入图片描述

2) 持久化存储结果截图

在这里插入图片描述

3) 可视化分析图形截图

价格、里程、品牌和车型数量分布可视化

在这里插入图片描述

上牌时间和上市时间分布

在这里插入图片描述

保修的存在性与价格、里程和上牌时间的关联

在这里插入图片描述

五、总结

通过本项目,我学习并掌握了网络爬虫的基本原理和方法,以及如何利用Python进行数据处理和可视化分析。在项目中,我使用Scrapy框架爬取了汽车之家网站的二手车信息,然后利用Pandas库对数据进行清洗和整理,最后使用Matplotlib库对数据进行可视化分析。通过这个项目,我不仅提高了自己的数据处理和分析能力,还为大连市二手车市场的价格分布、常购品牌等信息提供了直观的展示和分析结果,为购车提供了参考依据。

以上都是套话,下附真实的总结:
这次发现 scrapy 自带 pipeline 挺不错的,比我自己直接写一个强远了,而且报错日志什么的也很方便。不过这个网站反爬太少,header啥的根本不用加,这块我就还没学到。框架的坏处也有,很多东西一个 requests 改改参数能解决这个偏偏是类的函数,得诡异地设置一些东西去传递参数,还难写结束条件。

六、参考资料

  • Requests官方文档:https://docs.python-requests.org/en/master/

  • BeautifulSoup官方文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/

  • 通义千问AI问答:https://lxblog.com/qianwen/share?shareId=6f7c1cba-e39f-4e1e-8b59-b7477e346fa9

  • Scrapy笔记(5)- Item详解_scrapy
    item-CSDN博客:https://blog.csdn.net/sdulsj/article/details/52984619#SnippetTab

  • Python爬虫实战+数据分析+数据可视化(汽车之家)_基于大数据技术对汽车交易的可视化分析汽车之家-CSDN博客:https://blog.csdn.net/qq_45821420/article/details/115366180

  • python爬虫学习笔记-scrapy框架之start_url_scrapy的start
    url-CSDN博客:https://blog.csdn.net/weixin_42672765/article/details/85380212


  1. https://car.autohome.com.cn/2sc/dalian/a0_0msdgscncgpi1lto2csp1ex/ ↩︎

  2. https://www.che168.com/dalian/list/#pvareaid=100945 ↩︎

相关文章:

【代码】Python3|Scrapy框架初探(汽车之家大连市二手车车辆数据爬取、清洗与可视化)

本篇主要是整个项目的介绍,没提到太多琐碎的技术细节,以后有空的话会整理一下 Scrapy 和原生爬虫的差异,还有它坑人的一些地方,单发出来。 开源地址:https://github.com/shandianchengzi/car_home_spider 使用说明&a…...

C#中的new以及类

new关键字的用法 实例化对象:使用 new 关键字可以创建一个类的实例。例如: ​ MyClass obj new MyClass(); 指定构造函数:如果类有多个构造函数,可以使用 new 关键字指定使用哪一个构造函数来创建对象。例如: ​ MyC…...

Hbase简介和快速入门

一 Hbase简介 1 HBase定义 Apache HBase™ 是以hdfs为数据存储的,一种分布式、可扩展的NoSQL数据库。 2 HBase数据模型 HBase的设计理念依据Google的BigTable论文,论文中对于数据模型的首句介绍。Bigtable 是一个稀疏的、分布式的、持久的多维排序map…...

【AI落地应用实战】Amazon Bedrock +Amazon Step Functions实现链式提示(Prompt Chaining)

一、链式提示 Prompt Chaining架构 Prompt Chaining 是一种在生成式人工智能(如大型语言模型)中广泛使用的技术,它允许用户通过一系列精心设计的提示(Prompts)来引导模型生成更加精确、丰富且符合特定需求的内容。 P…...

vue Ref 和 Reactive 原理解析

文章目录 RefReactive Ref ref 的语义是指向一个值的引用,主要用于处理基本数据类型和单一值对象,即对值的引用进行包装和管理,而不是对对象的操作进行拦截,对于基础类型通过 getter 和 setter 实现拦截使用 Proxy 拦截对象的所有…...

【人工智能】Transformers之Pipeline(六):图像分类(image-classification)

目录 一、引言 二、图像分类(image-classification) 2.1 概述 2.2 技术原理 2.3 应用场景 2.4 pipeline参数 2.4.1 pipeline对象实例化参数 2.4.2 pipeline对象使用参数 2.4 pipeline实战 2.5 模型排名 三、总结 一、引言 pipeline&#x…...

编程语言漫谈之「初始化与赋值」——以C++和汇编语言为示例

编程语言漫谈之「初始化与赋值」——以C和汇编语言为示例 1. 赋值时汇编做了什么2. 在变量定义时做初始化, 与在使用时才进行初始化, 有区别吗? 1. 赋值时汇编做了什么 当我们在C中写下如下代码: int main() {int a 10;return 0; }这是一个简单的整数类型变量a的初始化赋值…...

windows使用ssh-agent管理私钥

主要有以下几个方面: 开启openssh 的 ssh-agent 服务 打开powershell 输入 Get-Service -Name ssh-agent 查看服务是否起来Start-Service ssh-agent 启动服务Stop-Service ssh-agent 关闭服务将私钥添加到ssh-agent 添加私钥 ssh-add ~/.ssh/id_rsa查询添加哪些私钥 ssh-add -…...

PostgreSQL 之 to_timestamp函数

to_timestamp 是 PostgreSQL 中的一个函数,用于将字符串或数字转换为时间戳。以下是关于 to_timestamp 的详细介绍: 引入版本 to_timestamp 函数在 PostgreSQL 7.3 版本中引入。 语法 to_timestamp 有两种主要的用法: 1.将字符串转换为时间戳 to_timestamp(text, text)第…...

USB3.0的等长要求到底是多少?

USB2.0与USB3.0接口的PCB布局布线要求PCB资源PCB联盟网 - Powered by Discuz! (pcbbar.com) 90欧姆阻抗,走差分线: 重点来了:...

力扣高频SQL 50题(基础版)第二十五题

文章目录 力扣高频SQL 50题(基础版)第二十五题619.只出现一次的最大数字题目说明实现过程准备数据实现方式结果截图 力扣高频SQL 50题(基础版)第二十五题 619.只出现一次的最大数字 题目说明 MyNumbers 表: ------…...

【C++题解】1581. 马里奥的银币1

问题:1581. 马里奥的银币1 类型:数组找数 题目描述: 马里奥有很多银币,有一天他得到了一张魔法卡,只要使用这张魔法卡,就可以使得他的银币里面的最大的银币金额变得更大。如果他最大的银币是偶数的金额&a…...

system和popen函数的异同点

system和popen函数的异同点 文章目录 system和popen函数的异同点1.什么是shell命令2.system 函数3.popen 函数4.总结 1.什么是shell命令 Shell 命令是在类 UNIX 操作系统(包括 UNIX、Linux 和 macOS 等)的 Shell 中执行的指令。Shell 是操作系统的命令行…...

Python小工具之httpstat网络分析

一、简介 Python httpstat是一个基于Python的命令行工具,用于测量HTTP请求的性能和状态信息。它能够向目标服务器发送HTTP请求,并显示详细的统计信息,包括DNS解析时间、建立连接时间、TLS/SSL握手时间、首字节时间、总时间等。这些信息对于排…...

挑战房市预测领头羊:KNN vs. 决策树 vs. 线性回归

挑战房市预测领头羊(KNN,决策树,线性回归) 1. 介绍1.1 K最近邻(KNN):与邻居的友谊1.1.1 KNN的基础1.1.2 KNN的运作机制1.1.3 KNN的优缺点 1.2 决策树:解码房价的逻辑树1.2.1 决策树的…...

Docker 基础知识

Docker 基础知识 什么是 Docker? Docker 是一个开源平台,用于开发、发布和运行应用程序。Docker 通过将应用程序及其依赖项打包到一个称为容器的可移植单元中来工作。 Docker 的核心组件是什么? Docker Engine:核心组件&#xff0…...

视频主题Qinmei 3.0视频站源码_WordPress影视视频主题/附详细安装教程

Qinmei 3.0主题主要是将 wordpress 改造成纯 api 的站点,以便实现前后端分离的技术栈,目前的进度已经大致完成,唯一的问题就是需要安装 JWT token 插件。 功能介绍: 支持豆瓣以及 bangumi 的一键获取信息, 豆瓣 api 目前使用的是…...

数字看板:跨行业需求下的创新与升级

在当今这个数据驱动的时代,数字看板作为信息展示与决策支持的重要工具,正逐步渗透到各行各业之中。从智慧城市到智能制造,从金融分析到医疗健康,数字看板以其直观、动态、高效的特点,成为了连接数据与决策者的桥梁。本…...

02、爬虫数据解析-Re解析

数据解析的目的是不拿到页面的全部内容,只拿到部分我们想要的内容内容。 Re解析就是正则解析,效率高准确性高。学习本节内容前需要学会基础的正则表达式。 一、正则匹配规则 1、常用元字符 . 匹配除换行符以外的字符 \w 匹配字母或数字或下划…...

掀桌子了!原来是咱们的大屏设计太酷,吓着前端开发老铁了

掀桌子了!原来是咱们的大屏设计太酷,吓着前端开发老铁了 艾斯视觉观点认为:在软件开发的世界里,有时候创意和设计的火花会擦得特别亮,以至于让技术实现的伙伴们感到既兴奋又紧张。这不,我们的设计团队刚刚…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

PHP 8.5 即将发布:管道操作符、强力调试

前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...