新能源汽车可视化大屏数据展示系列之五数据

举报
tea_year 发表于 2024/12/18 11:58:13 2024/12/18
【摘要】 任务目标:       1.在mysql创建数据表       2.爬取数据到csv       3.清洗数据到mysql创建模型,生产表到数据库1 创建myApp应用在原有Django项目carShow的控制台,执行指令:python manage.py startapp myapp创建一个应用:python manage.py startapp myApp 是一个常用的命令,用于在Dja...

任务目标:

       1.在mysql创建数据表

       2.爬取数据到csv

       3.清洗数据到mysql

创建模型,生产表到数据库

1 创建myApp应用

在原有Django项目carShow的控制台,执行指令:python manage.py startapp myapp

创建一个应用:

python manage.py startapp myApp 是一个常用的命令,用于在Django项目中创建一个新的应用(app)。这个命令会在项目目录下创建一个名为 myapp 的文件夹,并在其中生成一些基础文件,这些文件是Django应用的标准结构。

以下是这个命令会创建的文件和目录结构:

myApp/
    migrations/
    __init__.py
    __init__.py
    admin.py
    apps.py
    models.py
    tests.py
    views.py
    management/
    commands/
    __init__.py
    ...

__init__.py:一个空文件,告诉Python这个目录是一个Python包。

admin.py:用于定义Django admin界面的定制。

apps.py:定义了一个配置类,用于配置Django应用。

models.py:定义数据库模型。

tests.py:用于编写测试用例。

views.py:定义视图函数和类。

management/commands/:用于存放自定义Django命令

2 增加模型层设置

在刚才创建的项目下面,找到models.py文件,增加模型类的编写:

from django.db import models

# Create your models here.
class CarInfo(models.Model):
    id=models.AutoField('id',primary_key=True)
    brand=models.CharField('品牌',max_length=250,default='')
    carName=models.CharField('车名',max_length=250,default='')
    carImg=models.CharField('图片链接',max_length=250,default='')
    saleVolume=models.CharField('销量',max_length=250,default='')
    price=models.CharField('价格',max_length=250,default='')
    manufacturer=models.CharField('厂商',max_length=250,default='')
    rank=models.CharField('排名',max_length=250,default='')
    carModel=models.CharField('车型',max_length=250,default='')
    energyType=models.CharField('能源类型',max_length=250,default='')
    marketTime=models.CharField('上市时间',max_length=250,default='')
    insure=models.CharField('保修时间',max_length=250,default='')
    createTime=models.DateField('创建时间',auto_now_add=True)
    class Meta:
        db_table='carInfo'

这段代码定义了一个名为 CarInfo 的 Django 模型,用于表示汽车信息。以下是对每个字段和相关配置的解释:

  1. id:
    • 类型:AutoField
    • 说明:这是一个自动递增的主键字段,用于唯一标识每一条记录。
    • 参数:primary_key=True 表示这是主键。
  1. brand:
    • 类型:CharField
    • 说明:表示汽车品牌。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. carName:
    • 类型:CharField
    • 说明:表示汽车名称。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. carImg:
    • 类型:CharField
    • 说明:表示图片链接(注意这里可能是一个错误,通常应该是销量)。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. price:
    • 类型:CharField
    • 说明:表示汽车价格(注意这里可能是一个错误,通常应该是价格)。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. manufacturer:
    • 类型:CharField
    • 说明:表示汽车厂商。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. rank:
    • 类型:CharField
    • 说明:表示汽车排名(注意这里可能是一个错误,通常应该是价格)。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. carModel:
    • 类型:CharField
    • 说明:表示汽车车型。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. energyType:
    • 类型:CharField
    • 说明:表示汽车能源类型(如汽油、电动等)。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. marketTime:
    • 类型:CharField
    • 说明:表示汽车上市时间。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. insure:
    • 类型:CharField
    • 说明:表示汽车保修时间/或里程数量。
    • 参数:max_length=250 表示最大长度为250个字符,default='' 表示默认值为空字符串。
  1. createTime:
    • 类型:DateField
    • 说明:表示记录创建的时间。
    • 参数:auto_now_add=True 表示在创建记录时自动设置为当前日期和时间。
  1. Meta:
    • db_table='carInfo':指定数据库中对应的表名为 carInfo

注意事项

  • saleVolume, price, rank 这些字段的名称可能与实际含义不符,建议检查并更正。例如,saleVolume 应该改为 salesVolumeprice 应该改为 pricerank 应该改为 ranking
  • 如果需要存储数值数据(如价格、销量),应使用适当的字段类型,如 DecimalFieldIntegerField

》》》多学一招

在 Django 中,Meta 类是一个特殊的内部类,用于定义模型的元数据。这些元数据可以影响模型的行为和数据库表的映射方式。

在例子中:

class Meta:
    db_table = 'carInfo'

这个 Meta 类中的 db_table 属性指定了该模型对应的数据库表的名称。默认情况下,Django 会根据模型的名称自动生成数据库表名,通常是 appname_modelname 的形式。然而,通过设置 db_table 属性,你可以自定义数据库表的名称。

具体来说,这段代码告诉 Django,当你对这个模型进行数据库操作时,应该使用名为 carInfo 的数据库表,而不是默认生成的表名。这在以下几种情况下特别有用:

  1. 已有数据库:如果你正在使用一个已经存在的数据库,并且表名与 Django 默认生成的名字不同,你可以通过这种方式来匹配现有的表。
  2. 命名规范:你可能希望使用特定的命名规范来使数据库表名更具可读性或符合某些业务需求。
  3. 避免冲突:在某些情况下,默认生成的表名可能会与其他表名产生冲突,通过自定义表名可以避免这种情况。模仿上述代码,编写User的模型类:
class User(models.Model):
    id=models.AutoField('id',primary_key=True)
    username=models.CharField('用户名',max_length=250,default='')
    password=models.CharField('密码',max_length=250,default='')
    class Meta:
        db_table='user'

3 在mysql生成数据表

为了在mysql中生成相应的表,需要在settings.py添加“myApp":

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'myapp',  
]

在terminal下执行指令:python manage.py makemigrations

python manage.py makemigrations 是 Django 框架中的一个命令,用于创建数据库迁移文件。这些迁移文件记录了模型(models)的更改,以便在数据库中应用这些更改。

以下是这个命令的具体作用和步骤:

  1. 检测模型变化: makemigrations 会检查你的 Django 项目中的模型定义(位于 models.py 文件中),并与当前数据库结构进行比较。
  2. 生成迁移文件: 如果检测到模型的变化(例如新增字段、删除字段、修改字段类型等),Django 会自动生成相应的迁移文件。这些文件通常位于每个应用的 migrations 目录下,文件名以数字开头,表示迁移的顺序。
  3. 记录迁移操作: 迁移文件包含了具体的数据库操作指令,如 CREATE TABLE, ALTER TABLE, DROP TABLE 等。这些指令描述了如何将数据库从旧状态更新到新状态。


在terminal下执行指令:python manage.py migrate

使用navicat查看carData数据库下的表:

数据爬取和清洗

分析排行的url变化:

#前10条
https://www.dongchedi.com/motor/pc/car/rank_data?aid=1839&app_name=auto_web_pc&city_name=%E5%8C%97%E4%BA%AC&count=10&offset=0&month=&new_energy_type=&rank_data_type=11&brand_id=&price=&manufacturer=&series_type=&nation=0

#前11-20条
https://www.dongchedi.com/motor/pc/car/rank_data?aid=1839&app_name=auto_web_pc&city_name=%E5%8C%97%E4%BA%AC&count=10&offset=10&month=&new_energy_type=&rank_data_type=11&brand_id=&price=&manufacturer=&series_type=&nation=0


接下来回到spiderMain项目目录,在spider.py文件下,过滤数据到csv文件。增加的代码是try 块,及下面的代码部分。

    def main(self):
        #定义变量count

        count=self.get_page()
        print(count)
        params={'offset':int(count)}

        # print("数据从{}开始爬取".format(int(count)+1))

        #pageJson=requests.get(self.spiderUrl, headers=self.headers).json()
        pageJson=requests.get(self.spiderUrl, headers=self.headers,params=params).json()
        pageJson=pageJson["data"]["list"]
        # print(pageJson)
        try:
            # 循环遍历
            for index, car in enumerate(pageJson):
                carData = []
                print('正在爬取第%d' % (index + 1) + '数据')
                # 品牌名 print(car['brand_name'])
                carData.append(car['brand_name'])
                # 车名  print(car['series_name'])
                carData.append(car['series_name'])
                # 打印图片链接print(car['image'])
                carData.append(car['image'])
                # 销量
                carData.append(car['count'])
                # 价格,需要拼接最低价格和最高价格;
                price = []
                price.append(car['min_price'])
                price.append(car['max_price'])
                carData.append(price)
                #厂商  print(car["sub_brand_name"])
                carData.append(car["sub_brand_name"])

                # 排名 https://www.dongchedi.com/auto/params-carIds-x-5952
                # print(car['rank'])
                carData.append(car['rank'])
                # 5952,变成活的数据
                carNumber = car['series_id']

                infoHTML = requests.get('https://www.dongchedi.com/auto/params-carIds-x-%s' % carNumber,
                                        headers=self.headers)
                # print(infoHTML.text)
                infoHTMLPath = etree.HTML(infoHTML.text)
                # carModel
                carModel = infoHTMLPath.xpath('//div[@data-row-anchor="jb"]/div[2]/div/text()')[0]
                carData.append(carModel)

                # 新能源汽车类型 fuel_form
                energyType = infoHTMLPath.xpath('//div[@data-row-anchor="fuel_form"]/div[2]/div/text()')[0]
                carData.append(energyType)
                # maketTime
                marketTime = infoHTMLPath.xpath("//div[@data-row-anchor='market_time']/div[2]/div/text()")[0]
                carData.append(marketTime)

                # 保修期限 insure
                #        infoHTMLpath.xpath("//div[@data-row-anchor='period']/div[2]/div/text()")[0]
                insure = infoHTMLPath.xpath('//div[@data-row-anchor="period"]/div[2]/div/text()')[0]
                carData.append(insure)

                print(carData)
                self.save_to_save(carData)

                # 等待存入csv文件之后,再去掉break
                # break
        except:
            pass
        #之前的设置页面和调用 
        self.setPage(int(count)+10)
        self.main()

经过运行发现一直从1-10,下次再从1-10,出现bug的原因在于

https://www.dongchedi.com/motor/pc/car/rank_data?aid=1839&app_name=auto_web_pc&city_name=%E5%8C%97%E4%BA%AC&count=10&offset=0&month=&new_energy_type=&rank_data_type=11&brand_id=&price=&manufacturer=&series_type=&nation=0

#将offset=0给去除掉
https://www.dongchedi.com/motor/pc/car/rank_data?aid=1839&app_name=auto_web_pc&city_name=%E5%8C%97%E4%BA%AC&count=10&month=&new_energy_type=&rank_data_type=11&brand_id=&price=&manufacturer=&series_type=&nation=0
  1. params={'offset':int(count)}部分
    • 这里定义了一个名为params的字典(Python 中的一种数据结构)。字典中的键值对表示请求参数的名称和对应的值。
    • 在这个例子中,字典只有一个键值对,键是'offset',值是将变量count转换为整数类型后的结果。这个offset参数通常用于分页获取数据等场景中,比如在网页接口里,它可以指定从哪一条数据开始获取,实现数据的分批获取功能。例如,如果count的值是 10,那么params字典传递给请求时就表示从第 11 条数据开始获取(一般是基于 0 索引的话,第 11 条数据对应的索引就是 10)。
  2. pageJson=requests.get(self.spiderUrl, headers=self.headers,params=params).json()部分
    • 这行代码与上面被注释掉的代码类似,但多了params=params这个参数传递。它同样是使用requests库的get方法向self.spiderUrl发送 HTTP GET 请求,并且带上了之前定义的headers(请求头信息)以及params(请求参数)。
    • 通过带上params参数,将之前定义的包含offset参数的字典传递给服务器端,服务器端可以根据这个参数来决定返回什么样的数据(例如按照指定的起始位置返回分页数据等)。
    • 最后同样调用.json()方法,将服务器返回的响应内容(假设为 JSON 格式)解析成 Python 中合适的数据结构,并将解析后的结果赋值给变量pageJson,以便后续代码对获取到的数据进行进一步的处理,比如提取其中感兴趣的数据项、进行数据存储等操作。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。