💗博主介绍:✌全网粉丝15W+,CSDN全栈领域优质创作者,博客之星、掘金/知乎/b站/华为云/阿里云等平台优质作者、专注于Java、小程序/APP、python、大数据等技术领域和毕业项目实战,以及程序定制化开发、文档编写、答疑辅导等。
👇🏻 精彩专栏 推荐订阅👇🏻
计算机毕业设计精品项目案例(持续更新)
🌟文末获取源码+数据库+文档🌟
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以和学长沟通,希望帮助更多的人

一.前言

旅游景点数据分析可视化平台是一个专门设计用于分析和增强地方旅游吸引力的智能平台。该系统对丰富的旅游资源进行深入挖掘和评估。且能够追踪游客流量、美食推荐、地区文化活动、酒店住宿率以及社交媒体上的旅游相关讨论,以全方位了解和优化游客体验。系统通过可视化工具将分析结果呈现给用户,包括热力图、趋势图和互动地图等形式,使得复杂的数据信息易于理解和操作。旅游景点数据分析可视化平台旨在推动区域旅游业的可持续发展,提升作为旅游目的地的竞争力。随着技术的不断进步,该系统将持续升级,为旅游业者和游客提供更加精准和便捷的服务。

基于Python的旅游景点数据分析可视化平台的数据存储主要通过MySQL数据库。用户在使用应用时产生的数据通过Python语言传递给数据库。通过此方式促进旅游景点数据分析可视化平台的信息化管理,提供一个内容丰富、功能多样、易于操作的平台。述了数据库的设计,系统的详细设计部分主要论述了几个主要模块的详细设计过程。


二.技术环境

开发语言:Python
python框架:django
软件版本:python3.7/python3.8
数据库:mysql 5.7或更高版本
数据库工具:Navicat11
爬虫框架:Scrapy
大数据框架:Hadoop
开发软件:PyCharm/vs code
前端框架:vue.js


三.功能设计

本课题主要就是设计并开发一个旅游景点数据分析可视化平台。运用当前Google提供的Django框架来实现对景点信息查询等功能。当然使用的数据库是mysql。系统主要包括系统首页、用户、旅游景点、周边住宿、周边美食、美食分类、系统管理、个人资料等功能的操作平台;
本管理系统的用例图根据角色权限进行分类,主要可分为管理员用例和用户用例。
(1)管理员用例图如下所示:
在这里插入图片描述

(2)用户用例图如下所示:
在这里插入图片描述

四.数据设计

概念模型的设计是为了抽象真实世界的信息,并对信息世界进行建模。它是数据库设计的强大工具。数据库概念模型设计可以通过E-R图描述现实世界的概念模型,
在系统中将对“用户、公告栏、旅游景点、系统简介、周边美食、收藏”等作为实体,它们的局部E-R图,如图所示:
在这里插入图片描述

五.部分效果展示

5.1前台用户功能实现效果

当人们打开系统的网址后,首先看到的就是首页界面。在这里,人们能够看到系统的导航条,通过导航条导航进入各功能展示页面进行操作。系统首页界面如图所示:
在这里插入图片描述

在注册流程中,用户在Vue前端填写必要信息(如用户名、密码等)并提交。前端将这些信息通过HTTP请求发送到Python后台。后台处理这些信息,检查用户名是否唯一,并将新用户数据存入MySQL数据库。完成后,后台向前端发送注册成功的确认,前端随后通知用户完成注册。这个过程实现了新用户的数据收集、验证和存储。注册页面如图所示:
在这里插入图片描述

旅游景点:在旅游景点页面的输入栏中输入标题和地点进行查询,可以查看到旅游景点的详细信息,并根据需要进行点赞、评论或收藏操作;旅游景点页面如图所示:
在这里插入图片描述

周边住宿:在周边住宿页面的输入栏中输入酒店名称、酒店类型、房间号、客房类型和状态进行查询,可以查看到酒店的详细信息,并根据需要进行点赞、评论或收藏操作;周边住宿页面如图所示:

在这里插入图片描述

周边美食:在周边美食页面的输入栏中输入美食名称和地址进行查询,可以查看到美食的详细信息,并根据需要进行点赞、评论或收藏操作;周边美食页面如图所示:
在这里插入图片描述

个人中心:在个人中心页面可以对修改密码、我的收藏进行详细操作;如图所示:
在这里插入图片描述

5.2后台管理员功能实现效果

在登录流程中,用户首先在Vue前端界面输入用户名和密码。这些信息通过HTTP请求发送到Python后台。后台接收请求,通过与MySQL数据库交互验证用户凭证。如果认证成功,后台会返回给前端,允许用户访问系统。这个过程涵盖了从用户输入到系统验证和响应的全过程。如图所示。
在这里插入图片描述

管理员进入主页面,主要功能包括对系统首页、用户、旅游景点、周边住宿、周边美食、美食分类、系统管理、个人资料等进行操作。

旅游景点功能实现是在Django后端部分,您需要创建一个新的应用,然后在该应用下创建一个模型(models.py)来定义旅游景点的数据结构,使用Django的ORM来处理与MySQL数据库的交互,包括旅游景点的增删改查等操作。接着,在views.py中编写视图逻辑来处理前端请求,使用Django的URL路由(urls.py)将请求映射到相应的视图函数。对于数据的验证和序列化,可以使用Django的表单或序列化器来实现。在前端Vue.js部分,将创建相应的Vue组件,在这些组件中使用axios或其他HTTP库与Django后端的API进行交互,实现旅游景点的查看、修改、查看评论和删除等功能。状态管理可以通过Vuex来维护,比如在store目录下定义旅游景点管理模块的状态、突变、动作和获取器。如图所示:
在这里插入图片描述

周边住宿功能实现是在Django后端部分,您需要创建一个新的应用,然后在该应用下创建一个模型(models.py)来定义周边住宿的数据结构,使用Django的ORM来处理与MySQL数据库的交互,包括周边住宿的增删改查等操作。接着,在views.py中编写视图逻辑来处理前端请求,使用Django的URL路由(urls.py)将请求映射到相应的视图函数。对于数据的验证和序列化,可以使用Django的表单或序列化器来实现。在前端Vue.js部分,将创建相应的Vue组件,在这些组件中使用axios或其他HTTP库与Django后端的API进行交互,实现周边住宿的查看、修改、查看评论和删除等功能。状态管理可以通过Vuex来维护,比如在store目录下定义周边住宿管理模块的状态、突变、动作和获取器。如图所示:

在这里插入图片描述

周边美食功能实现是在Django后端部分,您需要创建一个新的应用,然后在该应用下创建一个模型(models.py)来定义周边美食的数据结构,使用Django的ORM来处理与MySQL数据库的交互,包括周边美食的增删改查等操作。接着,在views.py中编写视图逻辑来处理前端请求,使用Django的URL路由(urls.py)将请求映射到相应的视图函数。对于数据的验证和序列化,可以使用Django的表单或序列化器来实现。在前端Vue.js部分,将创建相应的Vue组件,在这些组件中使用axios或其他HTTP库与Django后端的API进行交互,实现周边美食的查看、修改、查看评论和删除等功能。状态管理可以通过Vuex来维护,比如在store目录下定义周边美食管理模块的状态、突变、动作和获取器。如图所示:

在这里插入图片描述

5.3可视化大屏展示功能实现效果

管理员点击看板,跳转到看板界面,可以查看地点分布、浏览区间、体验数统计、旅游景点、年龄分布、性别比例等统计数据。看板界面如图所示:
在这里插入图片描述

六.部分功能代码


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

# 数据爬取文件

import scrapy
import pymysql
import pymssql
from ..items import LvyoujingdianItem
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 LvyoujingdianSpider(scrapy.Spider):
    name = 'lvyoujingdianSpider'
    spiderUrl = 'https://www.mafengwo.cn/gonglve/ziyouxing/list/list_page?mddid=12720&page={}'
    start_urls = spiderUrl.split(";")
    protocol = ''
    hostname = ''
    realtime = False


    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, '7y935m2h_lvyoujingdian') == 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,
                        callback=self.parse
                    )
            else:
                yield scrapy.Request(
                    url=url,
                    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, '7y935m2h_lvyoujingdian') == 1:
                cursor.close()
                connect.close()
                self.temp_data()
                return
        data = json.loads(response.body)
        html_text = data["html"]
        resp = response.replace(body=html_text)
        list = resp.css('div[class="item clearfix"]')
        for item in list:
            fields = LvyoujingdianItem()

            if '(.*?)' in '''div.detail h3::text''':
                try:
                    fields["biaoti"] = str( re.findall(r'''div.detail h3::text''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["biaoti"] = str( self.remove_html(item.css('div.detail h3::text').extract_first()))

                except:
                    pass
            if '(.*?)' in '''div.img img::attr(src)''':
                try:
                    fields["fengmian"] = str( re.findall(r'''div.img img::attr(src)''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["fengmian"] = str( self.remove_html(item.css('div.img img::attr(src)').extract_first()))

                except:
                    pass
            if '(.*?)' in '''span.location''':
                try:
                    fields["didian"] = str( re.findall(r'''span.location''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["didian"] = str( self.remove_html(item.css('span.location').extract_first()))

                except:
                    pass
            if '(.*?)' in '''span.view''':
                try:
                    fields["liulanshu"] = str( re.findall(r'''span.view''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["liulanshu"] = str( self.remove_html(item.css('span.view').extract_first()))

                except:
                    pass
            try:
                fields["laiyuan"] = 'https://www.mafengwo.cn'+ str(self.remove_html(item.css('a[class="_j_item"]::attr(href)').extract_first()))

            except:
                pass
                
            if '(.*?)' in '''<span>(.*?)人体验过</span></div>''':
                try:
                    fields["tiyanshu"] = str( re.findall(r'''<span>(.*?)人体验过</span></div>''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["tiyanshu"] = str( self.remove_html(item.css('<span>(.*?)人体验过</span></div>').extract_first()))

                except:
                    pass
            if '(.*?)' in '''div.detail ul li::text''':
                try:
                    fields["kandian1"] = str( re.findall(r'''div.detail ul li::text''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["kandian1"] = str( self.remove_html(item.css('div.detail ul li::text').extract_first()))

                except:
                    pass
            if '(.*?)' in '''div.detail ul li:nth-child(2)::text''':
                try:
                    fields["kandian2"] = str( re.findall(r'''div.detail ul li:nth-child(2)::text''', item.extract(), re.DOTALL)[0].strip())

                except:
                    pass
            else:
                try:
                    fields["kandian2"] = str( self.remove_html(item.css('div.detail ul li:nth-child(2)::text').extract_first()))

                except:
                    pass
            
            yield fields

    # 数据清洗
    def pandas_filter(self):
        engine = create_engine('mysql+pymysql://root:123456@localhost/spider7y935m2h?charset=UTF8MB4')
        df = pd.read_sql('select * from lvyoujingdian 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 `lvyoujingdian`(
                id
                ,biaoti
                ,fengmian
                ,didian
                ,liulanshu
                ,laiyuan
                ,tiyanshu
                ,kandian1
                ,kandian2
            )
            select
                id
                ,biaoti
                ,fengmian
                ,didian
                ,liulanshu
                ,laiyuan
                ,tiyanshu
                ,kandian1
                ,kandian2
            from `7y935m2h_lvyoujingdian`
            where(not exists (select
                id
                ,biaoti
                ,fengmian
                ,didian
                ,liulanshu
                ,laiyuan
                ,tiyanshu
                ,kandian1
                ,kandian2
            from `lvyoujingdian` where
                `lvyoujingdian`.id=`7y935m2h_lvyoujingdian`.id
            ))
        '''

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

源码及文档获取

文章下方名片联系我即可~
大家点赞、收藏、关注、评论啦 、查看👇🏻获取联系方式👇🏻
精彩专栏推荐订阅:在下方专栏👇🏻

最新计算机毕业设计选题篇-选题推荐
小程序毕业设计精品项目案例-200套
Java毕业设计精品项目案例-200套
Python毕业设计精品项目案例-200套
大数据毕业设计精品项目案例-200套
💟💟如果大家有任何疑虑,欢迎在下方位置详细交流。

Logo

更多推荐