分享一个基于python的食品销售数据采集与可视化分析系统爬虫项目(源码、调试、LW、开题、PPT)

💕💕作者:计算机源码社
💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流!

1、选题背景

  随着互联网的发展,电子商务平台已成为消费者购买零食的重要渠道之一。尤其是在国内像京东这样的电商平台聚集了大量的零食销售数据,这些数据对于市场分析、商业决策以及消费者行为研究具有重要意义。然而,面对如此庞大的数据量,手动获取和分析这些数据效率低下且容易出错。因此,开发一套基于Python的零食销售数据采集与可视化分析系统,可以有效地解决数据采集和分析的困难,使企业能够更准确地把握市场趋势。

2、研究目的和意义

  基于python的零食销售数据采集与可视化分析系统旨在通过Scrapy爬虫技术从京东平台自动化采集零食销售数据,并将这些数据经过清洗和处理后,存储在MySQL数据库中。随后,利用Django框架搭建一个Web平台,通过Echarts实现数据的可视化展示。用户可以在平台上查看零食类别、价格、产地、店铺等信息的统计分析结果,从而更好地了解市场动态,支持管理层做出科学决策。系统还将具备用户登录、零食信息管理及用户信息管理等功能,提供全方位的数据管理与分析支持。

  该系统不仅能够大幅提升零食销售数据的采集和分析效率,还能通过可视化手段,使数据的展示更加直观,帮助用户更容易地理解复杂的数据关系。对于企业而言,系统的应用能够减少人工分析的时间和成本,提高市场响应速度,并为零售商、生产商等提供有力的数据支持,从而优化供应链管理和营销策略。通过对销售数据的深入挖掘与分析,企业还能够预测未来的市场趋势和消费者需求,进一步提升竞争力。

3、系统研究内容

本系统的开发主要分为四个核心部分:数据采集、数据处理与存储、数据可视化展示以及系统功能开发。

在数据采集部分,系统采用Scrapy爬虫技术从京东平台自动化抓取与零食相关的销售数据,包括零食类别、价格、产地、店铺等详细信息。数据采集后,通过Python进行数据处理和清洗,以确保数据的准确性和一致性。清洗后的数据将被存储在MySQL数据库中,以便后续的数据分析与管理。

在数据可视化展示部分,系统利用Echarts框架,将存储在MySQL中的数据进行可视化分析和展示,系统会在大屏幕上直观地展示零食类别分布、价格区间、产地来源、店铺销售情况等多维度的数据统计分析结果。这些可视化图表不仅帮助用户快速掌握市场信息,还为企业的决策提供了重要的依据。

在系统功能开发方面,基于Python和Django框架,系统搭建了一个功能齐全的Web平台。用户可以通过该平台进行登录,管理和维护零食信息,并进行个人信息管理和用户管理等操作。系统具备友好的用户界面,支持零食数据的增删改查操作,确保数据的实时性和准确性。通过这些功能模块的有机结合,系统不仅实现了零食销售数据的全面采集和展示,还为用户提供了便捷的管理工具。

4、系统页面设计

微信截图_20240823173110.png
微信截图_20240823173138.png
微信截图_20240823173158.png
微信截图_20240823173217.png

5、参考文献

[1]冯辉,时明晶,盛建娜.数字化时代食品企业管理模式探讨[J].今日财富,2024,(19):83-85.
[2]陈正伟.数据管理与隐私计算平台的设计案例分析[J].集成电路应用,2024,41(06):220-221.DOI:10.19339/j.issn.1674-2583.2024.06.099.
[3]刘静.大数据分析在食品安全风险评估中的应用[J].食品安全导刊,2024,(12):153-156.DOI:10.16043/j.cnki.cfs.2024.12.040.
[4]何月华.食品检验中的大数据分析与质量控制[J].中国食品工业,2024,(05):65-67.
[5]金鹏,叶莉敏,孟文.大数据技术在食品安全监管中的应用分析[J].食品安全导刊,2024,(01):7-9.DOI:10.16043/j.cnki.cfs.2024.01.004.
[6]卢素珍,彭雯婧,熊铮,等.数据分析平台提升食品安全抽检效能探索[J].质量探索,2023,20(03):79-83.
[7]杨清茹.大数据技术在食品安全监管中的应用分析[J].中国食品工业,2023,(12):73-75+78.
[8]包吉.供应链实践、大数据分析对食品零售业供应链绩效的影响研究[D].吉林大学,2023. DOI:10.27162/d.cnki.gjlin.2023.005717.
[9]尚敬轩,袁田,李碧玉,等.基于C/S-B/S结构的食品水质安全快速检测信息系统设计与应用[C]//中国医学装备协会.中国医学装备大会暨2023医学装备展览会会议论文汇编.桂林联勤保障中心药品仪器监督检验站;,2023:11. DOI:10.26914/c.cnkihy.2023.018263.
[10]贾艳艳.基于数据驱动的食品安全预警体系分析与应用[J].中国食品工业,2022,(19):87-89.
[11]魏海昱,林伟鸿,贺超波.基于Scrapy的食品安全舆情数据爬取与分析[J].现代计算机,2022,28(14):49-54+95.
[12]沙勇忠,陆莉.公共安全数据协同治理的逻辑框架与网络形式——以兰州市食品安全领域为例[J].信息资源管理学报,2022,12(03):7-20.DOI:10.13365/j.jirm.2022.03.007.
[13]朱菲,陈祖满,周静峰.基于信息化数据分析的《食品专业英语》线上线下混合式“金课”的建设[J].食品与发酵科技,2022,58(02):162-166.
[14]刘然,程曼.基于数据挖掘的校园食品安全事件分析[J].电脑与电信,2022,(04):65-68.DOI:10.15966/j.cnki.dnydx.2022.04.021.
[15]赵有东,申笑颜.防控生态中食品领域大数据的应用分析[J].中国信息化,2022,(01):88-89.
[16]赵先德,唐方方.区块链赋能供应链[M].中国人民大学出版社:202201.202.
[17]腾克,王震.数据挖掘在进口食品质量安全检测中的运用分析[J].当代化工研究,2021,(20):47-48.
[18]王庆春,基于食品安全突发事件应急处理的数据关系构建与关联分析方法研究.北京市,国家市场监督管理总局信息中心,2021-09-28.
[19]沈力.大数据背景下计算机技术在食品安全管理中的运用分析[J].食品安全导刊,2021,(24):184-185.DOI:10.16043/j.cnki.cfs.2021.24.099.
[20]李丹.关于利用大数据建立食品行业的危害控制措施指导的探讨[J].食品安全质量检测学报,2021,12(12):5054-5058.DOI:10.19812/j.cnki.jfsq11-5956/ts.2021.12.050.

6、核心代码

# # -*- coding: utf-8 -*-

# 数据爬取文件

import scrapy
import pymysql
import pymssql
from ..items import JianfeiItem
import time
from datetime import datetime,timedelta
import datetime as formattime
import re
import random
import platform
import json
import os
import urllib
from urllib.parse import urlparse
import requests
import emoji
import numpy as np
import pandas as pd
from sqlalchemy import create_engine
from selenium.webdriver import ChromeOptions, ActionChains
from scrapy.http import TextResponse
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
# 减肥
class JianfeiSpider(scrapy.Spider):
    name = 'jianfeiSpider'
    spiderUrl = 'https://search.jd.com/Search?keyword=%E5%87%8F%E8%82%A5&wq=%E5%87%8F%E8%82%A5&pvid=4ac391e8e75a42a7b69a0d9ac6efffc7&isList=0&page={}&s=56&click=0&log_id=1705715346068.8561'
    start_urls = spiderUrl.split(";")
    protocol = ''
    hostname = ''
    realtime = False

    headers = {
        "Cookie":"输入你自己的cookie"
    }

    def __init__(self,realtime=False,*args, **kwargs):
        super().__init__(*args, **kwargs)
        self.realtime = realtime=='true'

    def start_requests(self):

        plat = platform.system().lower()
        if not self.realtime and (plat == 'linux' or plat == 'windows'):
            connect = self.db_connect()
            cursor = connect.cursor()
            if self.table_exists(cursor, 'z6e9n865_jianfei') == 1:
                cursor.close()
                connect.close()
                self.temp_data()
                return
        pageNum = 1 + 1

        for url in self.start_urls:
            if '{}' in url:
                for page in range(1, pageNum):

                    next_link = url.format(page)
                    yield scrapy.Request(
                        url=next_link,
                        headers=self.headers,
                        callback=self.parse
                    )
            else:
                yield scrapy.Request(
                    url=url,
                    headers=self.headers,
                    callback=self.parse
                )

    # 列表解析
    def parse(self, response):
        _url = urlparse(self.spiderUrl)
        self.protocol = _url.scheme
        self.hostname = _url.netloc
        plat = platform.system().lower()
        if not self.realtime and (plat == 'linux' or plat == 'windows'):
            connect = self.db_connect()
            cursor = connect.cursor()
            if self.table_exists(cursor, 'z6e9n865_jianfei') == 1:
                cursor.close()
                connect.close()
                self.temp_data()
                return
        list = response.css('div.gl-i-wrap')
        for item in list:
            fields = JianfeiItem()

            fields["title"] = ' '.join(item.xpath('''.//div[@class='p-name p-name-type-2']/a/em//text()''').extract())
            try:
                fields["picture"] = str("https:"+ item.xpath('''.//div[@class='p-img']/a/img/@data-lazy-img''').extract()[0].strip())

            except:
                pass
            if '(.*?)' in '''div.p-price i::text''':
                try:
                    fields["price"] = float( re.findall(r'''div.p-price i::text''', item.extract(), re.DOTALL)[0].strip())
                except:
                    pass
            else:
                try:
                    fields["price"] = float( self.remove_html(item.css('div.p-price i::text').extract_first()))
                except:
                    pass
            if '(.*?)' in '''span.J_im_icon>a::text''':
                try:
                    fields["dianpu"] = str( re.findall(r'''span.J_im_icon>a::text''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["dianpu"] = str( self.remove_html(item.css('''span.J_im_icon>a::text''').extract_first()))

                except:
                    pass
            if '(.*?)' in '''div.p-img a::attr(href)''':
                try:
                    fields["laiyuan"] = str("https:"+ re.findall(r'''div.p-img a::attr(href)''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["laiyuan"] = str("https:"+ self.remove_html(item.css('''div.p-img a::attr(href)''').extract_first()))

                except:
                    pass
            detailUrlRule = item.css('div.p-img a::attr(href)').extract_first()
            if self.protocol in detailUrlRule or detailUrlRule.startswith('http'):
                pass
            elif detailUrlRule.startswith('//'):
                detailUrlRule = self.protocol + ':' + detailUrlRule
            elif detailUrlRule.startswith('/'):
                detailUrlRule = self.protocol + '://' + self.hostname + detailUrlRule
            else:
                detailUrlRule = self.protocol + '://' + self.hostname + '/' + detailUrlRule
            yield scrapy.Request(url=detailUrlRule, meta={'fields': fields}, headers=self.headers, callback=self.detail_parse, dont_filter=True)

    # 详情解析
    def detail_parse(self, response):
        fields = response.meta['fields']
        try:
            if '(.*?)' in '''div#choose-attr-1 div.dd div::attr(data-value)''':
                fields["category"] = str( re.findall(r'''div#choose-attr-1 div.dd div::attr(data-value)''', response.text, re.S)[0].strip())

            else:
                if 'category' != 'xiangqing' and 'category' != 'detail' and 'category' != 'pinglun' and 'category' != 'zuofa':
                    fields["category"] = str( self.remove_html(response.css('''div#choose-attr-1 div.dd div::attr(data-value)''').extract_first()))

                else:
                    try:
                        fields["category"] = str( emoji.demojize(response.css('''div#choose-attr-1 div.dd div::attr(data-value)''').extract_first()))

                    except:
                        pass
        except:
            pass
        try:
            fields["pianhao"] = str( response.xpath('''//li[starts-with(text(), "商品编号")]/text()''').extract()[0].strip().replace("商品编号:", ""))

        except:
            pass
        try:
            fields["maozhong"] = str( response.xpath('''//li[starts-with(text(), "商品毛重")]/text()''').extract()[0].strip().replace("商品毛重:", ""))

        except:
            pass
        try:
            fields["chandi"] = str( response.xpath('''//li[starts-with(text(), "商品产地")]/text()''').extract()[0].strip().replace("商品产地:", ""))

        except:
            pass
        try:
            fields["chengfen"] = str( response.xpath('''//li[starts-with(text(), "主要成分")]/text()''').extract()[0].strip().replace("主要成分:", ""))

        except:
            pass
        try:
            if '(.*?)' in '''//li[starts-with(text(), "类别")]/text()''':
                fields["leibie"] = str( re.findall(r'''//li[starts-with(text(), "类别")]/text()''', response.text, re.S)[0].strip().replace("类别:", ""))

            else:
                fields["leibie"] = ','.join(response.xpath('''//li[starts-with(text(), "类别")]/text()''').extract()).replace("类别:", "")
        except:
            pass
        return fields

    # 数据清洗
    def pandas_filter(self):
        engine = create_engine('mysql+pymysql://root:123456@localhost/spiderz6e9n865?charset=UTF8MB4')
        df = pd.read_sql('select * from jianfei limit 50', con = engine)

        # 重复数据过滤
        df.duplicated()
        df.drop_duplicates()

        #空数据过滤
        df.isnull()
        df.dropna()

        # 填充空数据
        df.fillna(value = '暂无')

        # 异常值过滤

        # 滤出 大于800 和 小于 100 的
        a = np.random.randint(0, 1000, size = 200)
        cond = (a<=800) & (a>=100)
        a[cond]

        # 过滤正态分布的异常值
        b = np.random.randn(100000)
        # 3σ过滤异常值,σ即是标准差
        cond = np.abs(b) > 3 * 1
        b[cond]

        # 正态分布数据
        df2 = pd.DataFrame(data = np.random.randn(10000,3))
        # 3σ过滤异常值,σ即是标准差
        cond = (df2 > 3*df2.std()).any(axis = 1)
        # 不满⾜条件的⾏索引
        index = df2[cond].index
        # 根据⾏索引,进⾏数据删除
        df2.drop(labels=index,axis = 0)

    # 去除多余html标签
    def remove_html(self, html):
        if html == None:
            return ''
        pattern = re.compile(r'<[^>]+>', re.S)
        return pattern.sub('', html).strip()

    # 数据库连接
    def db_connect(self):
        type = self.settings.get('TYPE', 'mysql')
        host = self.settings.get('HOST', 'localhost')
        port = int(self.settings.get('PORT', 3306))
        user = self.settings.get('USER', 'root')
        password = self.settings.get('PASSWORD', '123456')

        try:
            database = self.databaseName
        except:
            database = self.settings.get('DATABASE', '')

        if type == 'mysql':
            connect = pymysql.connect(host=host, port=port, db=database, user=user, passwd=password, charset='utf8')
        else:
            connect = pymssql.connect(host=host, user=user, password=password, database=database)
        return connect

    # 断表是否存在
    def table_exists(self, cursor, table_name):
        cursor.execute("show tables;")
        tables = [cursor.fetchall()]
        table_list = re.findall('(\'.*?\')',str(tables))
        table_list = [re.sub("'",'',each) for each in table_list]

        if table_name in table_list:
            return 1
        else:
            return 0

    # 数据缓存源
    def temp_data(self):

        connect = self.db_connect()
        cursor = connect.cursor()
        sql = '''
            insert into `jianfei`(
                id
                ,title
                ,picture
                ,price
                ,dianpu
                ,category
                ,pianhao
                ,maozhong
                ,chandi
                ,chengfen
                ,leibie
                ,laiyuan
            )
            select
                id
                ,title
                ,picture
                ,price
                ,dianpu
                ,category
                ,pianhao
                ,maozhong
                ,chandi
                ,chengfen
                ,leibie
                ,laiyuan
            from `z6e9n865_jianfei`
            where(not exists (select
                id
                ,title
                ,picture
                ,price
                ,dianpu
                ,category
                ,pianhao
                ,maozhong
                ,chandi
                ,chengfen
                ,leibie
                ,laiyuan
            from `jianfei` where
                `jianfei`.id=`z6e9n865_jianfei`.id
            ))
            order by rand()
            limit 50;
        '''

        cursor.execute(sql)
        connect.commit()
        connect.close()

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容