简介
运用Python爬虫技术对汽车网站进行汽车价格、品牌和销量等数据进行爬取,对爬取到的数据进行分析和加工,再利用可视化库对数据信息进行可视化分析,并以图标的形式直观地展示,为选择汽车的用户提供一个参考
架构
技术
- 前端 html css js juery bootstrap echarts
- 后端 flask
- 爬虫 selenium,bs4
- 数据库 mysql
系统展示
数据采集页面
排行页面
数据分析页面
实现过程
- 数据采集
销量榜页面查看
由此可见能采集到 车名,品牌,车型,价格,销量以及排名
开发者信息
使用selenium 抓取网页,用bs4定位元素就可以取到相关信息
点击销量趋势,可以看到这个款车型每个地区销量
使用request 获取该信息
模拟浏览器
取到全国销量
取到销量排行信息
- 数据库设计
配置文件config.py
class BaseConfig(object):
"""所有配置类的基类"""
SECRET_KEY = "LOVE"
DEBUG = True
TESTING = False
VISIT_TIME = 0 # 网站访问次数
# 数据库配置
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:自己的MySql密码@localhost/personalwebsite"
SQLALCHEMY_TRACK_MODIFICATIONS = False # 是否追踪数据库的修改
class ProductionConfig(BaseConfig):
"""生产环境下的配置类"""
DEBUG = False
class DevelopmentConfig(BaseConfig):
"""开发模式下的配置类"""
DEBUG = True
TESTING = True
- 网页设计
- 注册页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" type="text/css" href="../static/css/login.css"/>
<script src="../static/js/register.js" type="text/javascript"></script>
</head>
<body>
<div class="login-box">
<h2>注册</h2>
<form action="/register" method="post">
<div class="login-field">
<span style="color: aqua(图片); size: 12px">账号</span>
<input type="text" name="count" required=""/>
</div>
<div class="login-field">
<spqn style="color: aqua; size: 12px">密码</spqn>
<input type="password" name="password" required=""/>
</div>
<div class="login-field">
<spqn style="color: aqua; size: 12px">确认密码</spqn>
<input type="password" name="repassword" required=""/>
</div>
<input type="submit" value="提交" id="myloginlabel">
<p style="color: #101113">已有账号?<a href="./login" style="color: rgba(22,180,166,0.58)" onclick="topggleForm();">登录</a></p>
</form>
</div>
</body>
</html>
# 如果请求为post
if request.method == 'POST':
count = request.form.get('count')
password = request.form.get('password')
repassword = request.form.get('repassword')
print(count, password)
#检查信息完整
if len(count)==0 or len(password)==0 or len(repassword)==0:
msg = '信息不能为空'
print(msg)
return render_template('register.html',err="信息不能为空!")
#检查用户是否存在
if User.query.filter_by(name=count).first() is not None:
msg = '用户已存在'
print(msg)
return render_template('register.html',err="用户已存在!")
if password == repassword:
user = User(count, password)
#user.set_password(password)
db.session.add(user)
db.session.commit()
return render_template('login.html', )
else:
msg = '两次密码不一致'
print(msg)
return render_template('register.html',err="两次密码不一致!")
- 登录页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
<link rel="stylesheet" type="text/css" href="../static/css/login.css"/>
<script src="../static/js/register.js" type="text/javascript"></script>
</head>
<body>
<div class="login-box">
<h2>入口</h2>
<form action="/login" method="post">
<div class="login-field">
<span style="color: aqua; size: 12px">账号</span>
<input type="text" name="count" required=""/>
</div>
<div class="login-field">
<spqn style="color: aqua; size: 12px">密码</spqn>
<input type="password" name="password" required=""/>
</div>
<input type="submit" value="点击进入" id="myloginlabel">
<p style="color: #101113">没有账号?<a href="./register" style="color: rgba(22,180,166,0.58)" onclick="topggleForm();">注册</a></p>
</form>
</div>
</body>
</html>
# 如果请求为post
if request.method == 'POST':
count = request.form.get('name')
password = request.form.get('password')
print(count, password)
# 检查信息完整
if len(count) == 0 or len(password) == 0 :
msg = '信息不能为空'
print(msg)
return render_template('login.html', err="信息不能为空!")
user = User.query.filter_by(name=count).first()
#print(user)
if not user:
msg = '用户不存在'
return render_template('login.html',err=msg)
elif password != user.password:
msg = '密码错误!'
return render_template('login.html',err=msg)
else:
print("登录成功")
return render_template('index.html')
- 数据分析
读取数据
# 执行查询并将结果转换为DataFrame
data = pd.read_sql_query('SELECT * FROM dongchecar', engine)
数据清洗
#删除暂无报价
data=data[data["cardprice"]!='暂无报价']
data.reset_index(inplace=True)
#价格拆分
data["lowprice"]=data["cardprice"].apply(lambda x:x.split("-")[0] )
data["lowprice"]=data["lowprice"].apply(lambda x:x.replace("万","") )
data["lowprice"]=data["lowprice"].astype("float")
# 定义大品牌的列表
big_brands = ['奥迪', '通用', '日产', '本田', '奇瑞汽车', '现代', '吉利', '大众', '保时捷', '奔驰', '宝马', '小鹏', '捷豹', '极氪', '特斯拉', '理想', '腾势', '蔚来', '赛力斯', '起亚', '路虎', '长城', '长安汽车', '零跑',"沃尔沃","领克","丰田","红旗","英菲尼迪","北京","福特","马自达"]
# 将 'brand' 列中包含大品牌的行标记为 True
#data['is_big_brand'] = data['cardbrand'].str.contains('|'.join(big_brands))
# 创建新列 'big_brand',将品牌直接写成大品牌
data['big_brand'] = data['cardbrand'].apply(lambda x: next((b for b in big_brands if b in x), x))
#统计品牌数量
brand=data["big_brand"].value_counts().reset_index()
汽车品牌数量TOP分布图
汽车数量TOP 20
xiaoliang=data[data["type"]==1]
xiaoliang=xiaoliang.head(30)
#柱状图
bar = (
Bar(init_opts=opts.InitOpts(width="900px", height="400px",))
.add_xaxis(xiaoliang["carname"].tolist())
.add_yaxis("销售数量", xiaoliang["carsales"].tolist(), label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
title_opts=opts.TitleOpts(title="2023年汽车数量TOP 30"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
)
# .render("guiyang_wind_count_bar_chart.html")
)
bar.render_notebook()
2023年新能源汽车续航排行
xuhang=data[data["type"]==2]
xuhang=xuhang.head(30)
#排序
xuhang.sort_values(by=["carxuhang"],inplace=True,ascending=True)
# 创建横向条形图
bar_chart = (
Bar(init_opts=opts.InitOpts(width="900px", height="600px",))
.add_yaxis("续航里程",xuhang["carxuhang"].tolist())
.add_xaxis( xuhang["carname"].tolist())
.reversal_axis() # 设置为水平显示
.set_global_opts(
title_opts=opts.TitleOpts(title="2023年新能源汽车续航排行"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
)
)
# 渲染成 HTML 文件
bar_chart.render_notebook()
2023年汽车降价排行
查看单个车型全国销量:
# 提取城市和销量的列表
cities = city_lst
sales = sales_lst
# 创建 Geo 图
geo_chart = (
Geo()
.add_schema(maptype="china")
.add(dict1["data"]["title"], [list(z) for z in zip(cities, sales)])
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
visualmap_opts=opts.VisualMapOpts(max_=max(sales), min_=min(sales)),
title_opts=opts.TitleOpts(title=dict1["data"]["title"] + "汽车销量分布图"),
)
)
问题记录:
HTML Img标签 src为网络地址(https)无法显示图片问题解决
解决方案: 只需要在<head>标签内添加
<meta name="referrer" content="no-referrer">
就可以了
以上就是项目部分内容,欢迎批评指正,感兴趣的朋友可关注联系我谢谢!
评论·0