基于Python+大数据的旅游景区推荐系统设计与实现

💗博主介绍:✌全网粉丝10W+,CSDN全栈领域优质创作者,博客之星、掘金/华为云/阿里云等平台优质作者。
👇🏻 精彩专栏 推荐订阅👇🏻
计算机毕业设计精品项目案例-200套
🌟文末获取源码+数据库+文档🌟
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以和学长沟通,希望帮助更多的人

一.前言


近些年来,随着科技的飞速发展,互联网的普及逐渐延伸到各行各业中,给人们生活带来了十分的便利,旅游景区推荐系统利用计算机网络实现信息化管理,使整个旅游景区推荐的发展和服务水平有显著提升。
本文拟采用PyCharm开发工具,Python语言、Django框架进行开发,后台使用MySQL数据库进行信息管理,设计开发的旅游景区推荐系统。通过调研和分析,系统拥有管理员和用户两个角色,主要具备注册登录、个人信息修改、用户、景点分类、景点信息、旅游景区等功能模块。将纸质管理有效实现为在线管理,极大提高工作效率。

二.技术环境

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

三.功能设计

系统用例图如图3-1、图3-2、图3-3、图3-4所示。



系统功能结构图是系统设计阶段,系统功能结构图只是这个阶段一个基础,整个系统的架构决定了系统的整体模式,是系统的根据。本系统的整个设计结构如图所示。

四.数据设计

概念模型的设计是为了抽象真实世界的信息,并对信息世界进行建模。它是数据库设计的强大工具。数据库概念模型设计可以通过E-R图描述现实世界的概念模型。系统的E-R图显示了系统中实体之间的链接。而且Mysql数据库是自我保护能力比较强的数据库,下图主要是对数据库实体的E-R图:

五.部分效果展示

系统前台功能实现效果

当游客打开系统的网址后,首先看到的就是首页界面。在这里,游客能够看到旅游景区推荐系统的导航条显示首页、景点信息、旅游景区、景点资讯、个人中心。系统首页界面如图所示:

在系统首页点击中间的注册/登录按钮,然后页面跳转到注册登录界面,后来输入信息完成后,单击注册或者登录操作,如图所示:

用户点击景点信息,在景点信息页面的搜索栏输入景点名称、景点分类、景点星级、景点地址,进行查询,然后可以查看景点名称、景点分类、景点星级、景点图片、景点地址、营业时间、咨询热线,还可以对景点信息进行收藏或者评论操作;如图所示:

景点资讯;在景点资讯页面查看标题、内容、发布时间等信息进行详细操作,如图所示:

在个人中心页面可以输入个人详细信息,进行信息更新操作,还可以对我的收藏进行详细操作,如图所示:

系统管理员功能实现效果

管理员登录,通过登录页面填写用户名和密码等信息,点击登录操作,如图所示。

管理员登录进入系统可以查看系统首页、个人中心、用户管理、景点分类管理、景点信息管理、旅游景区管理、系统管理等功能,进行详细操作,如图所示。

管理员点击用户管理;在用户管理页面输入用户名、姓名、性别、头像、年龄、手机等信息,进行查询,新增或删除用户信息等操作;如图所示。

管理员点击景点信息管理;在景点信息管理页面输入景点名称、景点分类、景点星级、景点图片、景点地址、营业时间、咨询热线等信息,进行查询、新增或删除景点信息等操作;如图所示。

管理员点击旅游景区管理;在旅游景区管理页面对标题、封面、位置、价格、点评、评论等信息,进行查询或删除旅游景区等操作;如图所示。

管理员点击系统管理;在系统管理页面对系统简介、轮播图管理、景点资讯等信息,进行查询系统信息等操作;如图所示。

数据可视化分析大屏展示实现效果

旅游景区推荐系统展示图,如图所示。

在性别统计页面用饼状图进行展示所示。

在用户年龄分布统计页面用条形图进行展示所示。

六.部分功能代码

# 数据爬取文件

import scrapy
import pymysql
import pymssql
from ..items import QingdaolvyouItem
import time
import re
import random
import platform
import json
import os
from urllib.parse import urlparse
import requests
import emoji

# 旅游票务
class QingdaolvyouSpider(scrapy.Spider):
    name = 'qingdaolvyouSpider'
    spiderUrl = 'https://piao.qunar.com/ticket/list.htm?keyword=%E9%9D%92%E5%B2%9B&region=%E9%9D%92%E5%B2%9B&from=mpshouye_hotcity&page={}'
    start_urls = spiderUrl.split(";")
    protocol = ''
    hostname = ''
    headers = {
        "cookie":"SECKEY_ABVK=vlhpRLsLQG31Po7dyp9LqZqIVWCqTw4N5fBZ1DsuytI%3D; BMAP_SECKEY=fYAVeumEoDJpvS6t9mUnIfl7ylS6g05LSr9A_ZA18UssrV2x9Nvb--l3q9TLiknfzexlawoBsTebfVGIHzfyqOYfo51s-Ty6bZN2gB7dr1ALnVPRdfYiZs3FsCl2tC0PoI6DkXokTEOHVASpbWqBKuvneDEGUXxubzmT6qyM8jikWfPePl74wseQQxqH3SH3; QN1=00008c0031984ca726d0ccdd; HN1=v1d5a05c0541e94af107a046147dde57e6; HN2=qungnknsnqczr; QN300=s%3Dbaidu; _i=DFiEuMlwNifDZ7e6ttNii8l8C0yw; QN269=3C0E7D80A48D11EDA4E6FA163E7C276C; fid=c122ef21-269d-44af-816b-a3af77b6e9a0; ctt_june=1654604625968##iK3wWsjmahPwawPwa%3DXNWK0GE2GIaRkTESWRa%3Da8aDkGES0REDPsXPWGWKj8iK3siK3saKj%2BWKPnWsj%2BaSjnVuPwaUvt; ctf_june=1654604625968##iK3wVRtnahPwawPwasWGa%3DasWK2naS2%3DaSETVPDmWSXNWSvmXSWGX%3DPOVRDniK3siK3saKj%2BWKPnWsjmaSj%3DWwPwaUvt; cs_june=a4e7c8acd60e0c8483c9c4af0f303f81fd7bf3054fa1059b680a62984007c656679c337a756eb8f3b21f18c3ca84c016ab0131ff331f4cb4e98fa22f3456d33eb17c80df7eee7c02a9c1a6a5b97c117961a58ae707d2d19d229b1e3a0abd1ac65a737ae180251ef5be23400b098dd8ca; qunar-assist={%22version%22:%2220211215173359.925%22%2C%22show%22:false%2C%22audio%22:false%2C%22speed%22:%22middle%22%2C%22zomm%22:1%2C%22cursor%22:false%2C%22pointer%22:false%2C%22bigtext%22:false%2C%22overead%22:false%2C%22readscreen%22:false%2C%22theme%22:%22default%22}; QN205=organic; QN277=organic; csrfToken=CHPGSBwmGivAQIY68e9qdAdiTV3ndNSv; QN57=16773851843530.3742666257450069; Hm_lvt_15577700f8ecddb1a927813c81166ade=1677385185; QN267=9396775017807b72f; _vi=kLcz4BXbLA-Z_dmzAME0UN9x6XaB-aiI3ZQP-imSw9FAo6neFHeLQ5sMT6sMGgFb5a8IfmLRa7vmEMF3xiAAC7OMS4j9DgEidNCIF7BZoBbk58pE_3MLJ42UlqZfLutL8q10pZv62VI2_1_qG1wdurlugFXSrwHiB_htc5SdZS6G; QN58=1677387675012%7C1677387675012%7C1; ariaDefaultTheme=undefined; Hm_lpvt_15577700f8ecddb1a927813c81166ade=1677387675; __qt=v1%7CVTJGc2RHVmtYMS9NUFFkYWJvb2FuMVkzNDhtbjNjU0lZQUhsdmlmeUlENW91YjBzZTdodm9FVGdOWTVFUzh6dnVJTFVtUDNVQjFMa1RRVy82NjZoTWRYY2NKcGIxMGlnZnhqOG9tMy9sYjdjbUthUGdQVC92T0U2RTNJR0lKaWc5elpiMzBpWGxJZ0o4UjlueEMvMmZnPT0%3D%7C1677387675401%7CVTJGc2RHVmtYMTlEUVJsa1RGdmswaFhyMXFlQkZOUnFvNCt0OGxtTGtjNWt4VzdmbDluZFBBZVdlRGptcTFJZXAyOXIxaFRqQk5RY0pCdms3bzkwRmc9PQ%3D%3D%7CVTJGc2RHVmtYMStqelpiM1RGUERkbHpQY1J2MHo5Nk9wcWYvRnlDOUxERUk4RVExOTllczRSNUlhSGxmUmlsRXpzdTBGN052RjVzVmRwcG4raFRQWHRUNXdhbFNyR1RLNU9iY0hRU1BMK05UaHRRUTcwbUwvbWdMeEI4RnY2Y3l3SlV2ZFBFTHZGV2tobVJlcG5aUXhyL3FPcHRkZmx0VXZtR3hoRUJxcjh1ZjBJcFZVS1l5RmQ4NC9Xa0VjbGoySEVZcG03S2pKVEVSaWlVVHU2Z2haTExReXJoOFAvN3pKOUJjWnBQZmJSVWxsUk9Yd0tCZk53Uk9wSXZ0Z29LNTdSN3JrSHV1MFlZc20xdWxkQVZ6bUx3THBLcEcwNDhiRGhSNHlpWngrU01uVG10YjFKMC9jb2VtSmI3ajlkRDAzd3VLcTBNVGY4R0FBQTd1SlozdWpPMkVFdDRBT0l1UVVsblpJbXdXSXI3eWRSZG4vMnNkK00wR0xSU2JxZU8zNlROU2xQcGQxVkNKT3ZQK1diaVA3NzZjeHpObkE2bnRhTG52R3FqaStkQkN5UVpQaTd3amwySVlvaEtXdGlNcjByQWNzRHo0Njd2TzJlVFVaaVdla1U5RUIzRU5veFJCWXZkU2haYUpyeHRjY0t2M3pOd0U2a0JsM2pnakRZbCtTVE12QWNpR0dXS2Z6T3oxNVoxeHBXVzVSeEUzNU1OZ2Ezc2RKcFg1STVHWkZvL0ZHMWtIS0doRDlpQnNWK0Y5UkxnaklCc2p5alZFdTRxaEVsVkdjQThNV1N0L29QaVBmR3l2RDRneHNVUUhMU3ZOdnVlMi8rb3VaeWFFcm9VUDh1T1NiZURBblVCSHJkNjlDSU1QbUdJcTNvbWpUb0tJNFE0cUZLSDI4ckw5bmpCSjFtK1Q0ZVRXWml6aDgrWWx1VU9SMnJkVUFHVmVtSmhGZHJ0RWI4TFp2eUVPSFZLalB1M29WcVlSb1oxQXZTVWhESW5ycVhnek4wSjNTYjNnRFNNK2JObXlVTXRpcFhiUEh2SkRzenMzSWdsdi9xOE9QeHI4VFRiUHdoZDFIWUlFL0E0SVVtL2NjdFlMY0hhNQ%3D%3D; JSESSIONID=F90B651C1C838D80BE882B24C9D63F8A; QN271=217bc6aa-758f-4cb5-8d18-a95283b08907"
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def start_requests(self):

        plat = platform.system().lower()
        if plat == 'linux' or plat == 'windows':
            connect = self.db_connect()
            cursor = connect.cursor()
            if self.table_exists(cursor, '2o7ww_qingdaolvyou') == 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,
                    callback=self.parse
                )

    # 列表解析
    def parse(self, response):
        
        _url = urlparse(self.spiderUrl)
        self.protocol = _url.scheme
        self.hostname = _url.netloc
        plat = platform.system().lower()
        if plat == 'windows_bak':
            pass
        elif plat == 'linux' or plat == 'windows':
            connect = self.db_connect()
            cursor = connect.cursor()
            if self.table_exists(cursor, '2o7ww_qingdaolvyou') == 1:
                cursor.close()
                connect.close()
                self.temp_data()
                return

        list = response.css('div#search-list div[class~="sight_item"]')
        
        for item in list:

            fields = QingdaolvyouItem()



            fields["laiyuan"] = self.remove_html(item.css('h3.sight_item_caption a.name::attr(href)').extract_first())
            fields["jiage"] = self.remove_html(item.css('span.sight_item_price em::text').extract_first())

            detailUrlRule = item.css('h3.sight_item_caption a.name::attr(href)').extract_first()
            if self.protocol in detailUrlRule:
                pass
            elif detailUrlRule.startswith('//'):
                detailUrlRule = self.protocol + ':' + detailUrlRule
            else:
                detailUrlRule = self.protocol + '://' + self.hostname + detailUrlRule
                fields["laiyuan"] = detailUrlRule

            yield scrapy.Request(url=detailUrlRule, meta={'fields': fields}, headers=self.headers, callback=self.detail_parse)


    # 详情解析
    def detail_parse(self, response):
        fields = response.meta['fields']

        try:
            if '(.*?)' in '''div.mp-description-detail div.mp-description-view span.mp-description-name::text''':
                fields["biaoti"] = re.findall(r'''div.mp-description-detail div.mp-description-view span.mp-description-name::text''', response.text, re.S)[0].strip()
            else:
                if 'biaoti' != 'xiangqing' and 'biaoti' != 'detail' and 'biaoti' != 'pinglun' and 'biaoti' != 'zuofa':
                    fields["biaoti"] = self.remove_html(response.css('''div.mp-description-detail div.mp-description-view span.mp-description-name::text''').extract_first())
                else:
                    fields["biaoti"] = emoji.demojize(response.css('''div.mp-description-detail div.mp-description-view span.mp-description-name::text''').extract_first())
        except:
            pass


        try:
            if '(.*?)' in '''div#mp-slider-content div.mp-description-image img::attr(src)''':
                fields["fengmian"] = re.findall(r'''div#mp-slider-content div.mp-description-image img::attr(src)''', response.text, re.S)[0].strip()
            else:
                if 'fengmian' != 'xiangqing' and 'fengmian' != 'detail' and 'fengmian' != 'pinglun' and 'fengmian' != 'zuofa':
                    fields["fengmian"] = self.remove_html(response.css('''div#mp-slider-content div.mp-description-image img::attr(src)''').extract_first())
                else:
                    fields["fengmian"] = emoji.demojize(response.css('''div#mp-slider-content div.mp-description-image img::attr(src)''').extract_first())
        except:
            pass


        try:
            if '(.*?)' in '''div.mp-description-onesentence::text''':
                fields["miaoshu"] = re.findall(r'''div.mp-description-onesentence::text''', response.text, re.S)[0].strip()
            else:
                if 'miaoshu' != 'xiangqing' and 'miaoshu' != 'detail' and 'miaoshu' != 'pinglun' and 'miaoshu' != 'zuofa':
                    fields["miaoshu"] = self.remove_html(response.css('''div.mp-description-onesentence::text''').extract_first())
                else:
                    fields["miaoshu"] = emoji.demojize(response.css('''div.mp-description-onesentence::text''').extract_first())
        except:
            pass


        try:
            if '(.*?)' in '''span.mp-description-address::text''':
                fields["weizhi"] = re.findall(r'''span.mp-description-address::text''', response.text, re.S)[0].strip()
            else:
                if 'weizhi' != 'xiangqing' and 'weizhi' != 'detail' and 'weizhi' != 'pinglun' and 'weizhi' != 'zuofa':
                    fields["weizhi"] = self.remove_html(response.css('''span.mp-description-address::text''').extract_first())
                else:
                    fields["weizhi"] = emoji.demojize(response.css('''span.mp-description-address::text''').extract_first())
        except:
            pass


        try:
            if '(.*?)' in '''span#mp-description-commentscore''':
                fields["dianping"] = re.findall(r'''span#mp-description-commentscore''', response.text, re.S)[0].strip()
            else:
                if 'dianping' != 'xiangqing' and 'dianping' != 'detail' and 'dianping' != 'pinglun' and 'dianping' != 'zuofa':
                    fields["dianping"] = self.remove_html(response.css('''span#mp-description-commentscore''').extract_first())
                else:
                    fields["dianping"] = emoji.demojize(response.css('''span#mp-description-commentscore''').extract_first())
        except:
            pass


        try:
            if '(.*?)' in '''span.mp-description-commentCount a::text''':
                fields["pinglun"] = re.findall(r'''span.mp-description-commentCount a::text''', response.text, re.S)[0].strip()
            else:
                if 'pinglun' != 'xiangqing' and 'pinglun' != 'detail' and 'pinglun' != 'pinglun' and 'pinglun' != 'zuofa':
                    fields["pinglun"] = self.remove_html(response.css('''span.mp-description-commentCount a::text''').extract_first())
                else:
                    fields["pinglun"] = emoji.demojize(response.css('''span.mp-description-commentCount a::text''').extract_first())
        except:
            pass


        try:
            if '(.*?)' in '''div.mp-charact-intro div.mp-charact-desc''':
                fields["tese"] = re.findall(r'''div.mp-charact-intro div.mp-charact-desc''', response.text, re.S)[0].strip()
            else:
                if 'tese' != 'xiangqing' and 'tese' != 'detail' and 'tese' != 'pinglun' and 'tese' != 'zuofa':
                    fields["tese"] = self.remove_html(response.css('''div.mp-charact-intro div.mp-charact-desc''').extract_first())
                else:
                    fields["tese"] = emoji.demojize(response.css('''div.mp-charact-intro div.mp-charact-desc''').extract_first())
        except:
            pass


        try:
            if '(.*?)' in '''div.mp-charact-content div.mp-charact-desc''':
                fields["kaifangshijian"] = re.findall(r'''div.mp-charact-content div.mp-charact-desc''', response.text, re.S)[0].strip()
            else:
                if 'kaifangshijian' != 'xiangqing' and 'kaifangshijian' != 'detail' and 'kaifangshijian' != 'pinglun' and 'kaifangshijian' != 'zuofa':
                    fields["kaifangshijian"] = self.remove_html(response.css('''div.mp-charact-content div.mp-charact-desc''').extract_first())
                else:
                    fields["kaifangshijian"] = emoji.demojize(response.css('''div.mp-charact-content div.mp-charact-desc''').extract_first())
        except:
            pass




        return fields

    # 去除多余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 qingdaolvyou(
                laiyuan
                ,biaoti
                ,fengmian
                ,miaoshu
                ,weizhi
                ,dianping
                ,pinglun
                ,jiage
                ,tese
                ,kaifangshijian
            )
            select
                laiyuan
                ,biaoti
                ,fengmian
                ,miaoshu
                ,weizhi
                ,dianping
                ,pinglun
                ,jiage
                ,tese
                ,kaifangshijian
            from 2o7ww_qingdaolvyou
            where(not exists (select
                laiyuan
                ,biaoti
                ,fengmian
                ,miaoshu
                ,weizhi
                ,dianping
                ,pinglun
                ,jiage
                ,tese
                ,kaifangshijian
            from qingdaolvyou where
             qingdaolvyou.laiyuan=2o7ww_qingdaolvyou.laiyuan
            and qingdaolvyou.biaoti=2o7ww_qingdaolvyou.biaoti
            and qingdaolvyou.fengmian=2o7ww_qingdaolvyou.fengmian
            and qingdaolvyou.miaoshu=2o7ww_qingdaolvyou.miaoshu
            and qingdaolvyou.weizhi=2o7ww_qingdaolvyou.weizhi
            and qingdaolvyou.dianping=2o7ww_qingdaolvyou.dianping
            and qingdaolvyou.pinglun=2o7ww_qingdaolvyou.pinglun
            and qingdaolvyou.jiage=2o7ww_qingdaolvyou.jiage
            and qingdaolvyou.tese=2o7ww_qingdaolvyou.tese
            and qingdaolvyou.kaifangshijian=2o7ww_qingdaolvyou.kaifangshijian
            ))
            limit {0}
        '''.format(random.randint(20,30))

        cursor.execute(sql)
        connect.commit()

        connect.close()



最后

最新计算机毕业设计选题篇-选题推荐(值得收藏)
计算机毕业设计精品项目案例-200套(值得订阅)

版权声明:本文为博主作者:一点毕设原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/qq_15801219/article/details/135965849

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
心中带点小风骚的头像心中带点小风骚普通用户
上一篇 2024年4月22日
下一篇 2024年4月22日

相关推荐