💕💕作者:计算机源码社
💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流!
💕💕学习资料、程序开发、技术解答、文档报告
💕💕如需要源码,可以扫取文章下方二维码联系咨询
💕💕Java项目
💕💕微信小程序项目
💕💕Android项目
💕💕Python项目
💕💕PHP项目
💕💕ASP.NET项目
💕💕Node.js项目
💕💕选题推荐
项目实战|基于网络爬取技术的重庆旅游景点数据分析与可视化系统
1、选题背景
随着旅游业的迅猛发展,越来越多的人选择通过互联网获取和分享旅游信息,尤其是在旅游目的地选择上,游客往往依赖于在线平台的评价和推荐。重庆作为中国著名的旅游城市,拥有丰富的自然和人文景观,吸引了大量游客。去哪儿网等在线旅游平台上积累了大量与重庆旅游景点相关的数据,这些数据对于了解游客偏好、优化旅游资源配置、提升旅游体验具有重要价值。然而,面对如此庞大的数据量,传统的人工方式已无法满足分析需求。因此,开发一个能够自动化采集、处理和分析这些数据的系统显得尤为重要。
2、研究目的和意义
本系统的开发旨在构建一个基于Python的高效、全面的重庆旅游景点数据采集与分析平台。通过Scrapy爬虫技术,系统能够自动化地从去哪儿网获取重庆旅游景点的相关数据,并对这些数据进行清洗和处理,确保数据的准确性和实用性。系统将处理后的数据存储到MySQL数据库中,以便后续的管理和分析。同时,系统通过Echarts实现数据的可视化展示,帮助用户直观地了解重庆旅游景点的各项统计信息,如景点数量、评分、排名和点评情况等。通过搭建一个基于Python和Flask的Web平台,用户可以方便地进行数据管理和分析,为游客和相关机构提供决策支持。
开发基于Python的重庆旅游景点数据采集与分析系统,不仅能够提高数据采集和处理的效率,还能增强对旅游数据的分析能力。通过该系统,用户可以更快、更准地获取重庆旅游景点的相关信息,及时了解景点的热度、游客评价等关键信息。这对于提升游客体验、优化旅游资源配置以及支持相关决策具有重要意义。系统集成了周边美食和住宿管理功能,为游客提供了更加全面的旅游信息服务。该系统的开发与应用,体现了信息技术在旅游行业中的重要作用,推动了旅游服务的智能化、数据化发展。
3、系统功能设计
本课题究旨在开发一个基于Python的重庆旅游景点数据采集与分析系统,通过自动化的数据采集、处理、分析与可视化展示,实现对重庆旅游景点信息的全面掌握与深度分析。研究首先通过Scrapy爬虫技术从去哪儿网获取重庆旅游景点的相关数据,包括景点名称、评分、排名、点评、地址等多维度信息。爬取的数据经过数据处理与清洗,去除重复项和无效信息,确保数据的准确性和完整性。清洗后的数据将存储在MySQL数据库中,为后续的数据管理和分析提供稳定的数据基础。
研究的下一步重点在于对采集到的重庆旅游景点数据进行深入的统计与分析。系统将利用Echarts可视化框架,通过大屏展示重庆旅游景点的数量统计、评分统计、排名统计、点评统计等多项关键指标。此外,系统还将生成旅游景点地址的词云图,帮助用户直观地了解景点的分布情况。通过这些可视化分析,用户可以轻松获取重庆旅游景点的整体情况以及具体的排名和用户评价,为旅游决策提供有力的数据支持。
最后研究还将探讨如何基于Python和Flask框架搭建一个功能全面的Web网站。该网站不仅提供用户登录、旅游景点数据管理、用户管理等基础功能,还增加了周边美食和住宿管理模块,以便为用户提供更丰富的旅游信息。系统的可视化分析功能将整合在网站中,使用户能够通过友好的界面进行数据的查看和分析。本研究通过结合多种技术手段,致力于构建一个高效、实用的重庆旅游景点数据采集与分析系统,为旅游行业和相关决策提供支持。
4、系统页面设计
如需要源码,可以扫取文章下方二维码联系咨询
5、参考文献
[1]杨光辉,李源彬,杨红兵.大数据赋能的多任务旅游信息分析框架[J/OL].无线电通信技术,1-11[2024-08-24].http://kns.cnki.net/kcms/detail/13.1099.TN.20240710.1908.004.html.
[2]刘敏,王峥.大数据时代旅游酒店管理创新实践分析[J].旅游纵览,2024,(12):40-42.
[3]王大印,徐佳佳.大数据时代旅游个性化精准营销策略研究[J].旅游纵览,2024,(12):105-107.
[4]张珂.基于大数据的旅游者共享住宿消费行为特征提取方法[J].佳木斯大学学报(自然科学版),2024,42(06):49-51+104.
[5]张志辉.基于大数据分析的旅游市场趋势预测与策略研究[J].旅游与摄影,2024,(09):4-6.
[6]赵宁馨.基于大数据技术的在线游记数据分析与路线推荐研究[D].河北经贸大学,2024. DOI:10.27106/d.cnki.ghbju.2024.000683.
[7]李卫帆,刘晓静,毛磊,等.数据赋能特色旅游终端卷烟营销能力分析[J].财经界,2024,(13):57-59.DOI:10.19887/j.cnki.cn11-4098/f.2024.13.053.
[8]宁毅,陈金龙,罗德明,等.基于SpringBoot+Spark+Vue的旅游大数据分析平台的设计与实现[J].无线互联科技,2024,21(07):60-67.
[9]李茂平.融合改进AprioriAll算法与云计算的旅游物流路径数据分析模型研究[J].长春大学学报,2024,34(03):20-24.
[10]朱莉,李伟.数字技术赋能旅游产业创新实践探索[J].旅游纵览,2024,(06):183-185.
[11]黄正鹏,马欣,陈雪,等.基于线性回归算法对多彩贵州旅游数据的分析及应用[J].软件工程,2024,27(03):63-66.DOI:10.19644/j.cnki.issn2096-1472.2024.003.013.
[12]王康,毕素梅.大数据驱动下的旅游物流优化策略研究[J].特区经济,2024,(02):132-135.
[13]丁宇阳,胡涵,王莹露,等.基于区块链技术的旅游服务及可视化分析系统设计[J].长江信息通信,2024,37(02):166-169.DOI:10.20153/j.issn.2096-9759.2024.02.050.
[14]迟殿委,黄茵茵,徐红梅,等.基于地方旅游大数据的智慧旅游辅助决策服务平台设计[J].无线互联科技,2024,21(03):4-8.
[15]王寰焘.大数据时代旅游酒店管理优化路径研究[J].旅游与摄影,2024,(03):17-19.
[16]于佳,王伟.大数据技术在旅游酒店管理中的应用研究[J].旅游与摄影,2024,(03):27-29.
[17]谭明罡.大数据背景下邮轮旅游信息平台建设研究[J].旅游与摄影,2024,(03):24-26.
[18]王宪章.大数据技术在游客和消费统计的初步应用[J].旅游学刊,2024,39(02):17-18.DOI:10.19765/j.cnki.1002-5006.2024.02.007.
[19]牟莲新.智慧旅游发展中的数字技术创新与挑战分析[J].旅游与摄影,2024,(02):4-6.
[20]刘方磊.信创背景下旅游大数据分析系统的设计与对比[J].数字通信世界,2024,(01):52-54.
6、核心代码
# # -*- coding: utf-8 -*-
# 数据爬取文件
import scrapy
import pymysql
import pymssql
from ..items import LvyouxinxiItem
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 LvyouxinxiSpider(scrapy.Spider):
name = 'lvyouxinxiSpider'
spiderUrl = 'https://travel.qunar.com/search/place/22-chongqing-299979/4-----0/{}'
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, 'v4e6ribr_lvyouxinxi') == 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, 'v4e6ribr_lvyouxinxi') == 1:
cursor.close()
connect.close()
self.temp_data()
return
list = response.css('ul.b_destlist > li[class*="list_item clrfix"]')
for item in list:
fields = LvyouxinxiItem()
if '(.*?)' in '''h2.d_tit''':
try:
fields["title"] = str( re.findall(r'''h2.d_tit''', item.extract(), re.DOTALL)[0].strip())
except:
pass
else:
try:
fields["title"] = str( self.remove_html(item.css('h2.d_tit').extract_first()))
except:
pass
if '(.*?)' in '''a.d_img img::attr(src)''':
try:
fields["picture"] = str( re.findall(r'''a.d_img img::attr(src)''', item.extract(), re.DOTALL)[0].strip())
except:
pass
else:
try:
fields["picture"] = str( self.remove_html(item.css('a.d_img img::attr(src)').extract_first()))
except:
pass
if '(.*?)' in '''div.d_days::text''':
try:
fields["jyywsj"] = str( re.findall(r'''div.d_days::text''', item.extract(), re.DOTALL)[0].strip())
except:
pass
else:
try:
fields["jyywsj"] = str( self.remove_html(item.css('div.d_days::text').extract_first()))
except:
pass
if '(.*?)' in '''div.d_address''':
try:
fields["dizhi"] = str( re.findall(r'''div.d_address''', item.extract(), re.DOTALL)[0].strip())
except:
pass
else:
try:
fields["dizhi"] = str( self.remove_html(item.css('div.d_address').extract_first()))
except:
pass
if '(.*?)' in '''div.d_brief''':
try:
fields["jianjie"] = str( re.findall(r'''div.d_brief''', item.extract(), re.DOTALL)[0].strip())
except:
pass
else:
try:
fields["jianjie"] = str( self.remove_html(item.css('div.d_brief').extract_first()))
except:
pass
if '(.*?)' in '''a.d_img::attr(href)''':
try:
fields["xqdz"] = str( re.findall(r'''a.d_img::attr(href)''', item.extract(), re.DOTALL)[0].strip())
except:
pass
else:
try:
fields["xqdz"] = str( self.remove_html(item.css('a.d_img::attr(href)').extract_first()))
except:
pass
detailUrlRule = item.css('a.d_img::attr(href)').extract_first()
if self.protocol in detailUrlRule:
pass
elif detailUrlRule.startswith('//'):
detailUrlRule = self.protocol + ':' + detailUrlRule
elif detailUrlRule.startswith('/'):
detailUrlRule = self.protocol + '://' + self.hostname + detailUrlRule
# fields["laiyuan"] = detailUrlRule
else:
detailUrlRule = self.protocol + '://' + self.hostname + '/' + detailUrlRule
yield scrapy.Request(url=detailUrlRule, meta={'fields': fields}, callback=self.detail_parse, dont_filter=True)
# 详情解析
def detail_parse(self, response):
fields = response.meta['fields']
try:
if '(.*?)' in '''span.cur_score::text''':
fields["pingfen"] = float( re.findall(r'''span.cur_score::text''', response.text, re.S)[0].strip())
else:
if 'pingfen' != 'xiangqing' and 'pingfen' != 'detail' and 'pingfen' != 'pinglun' and 'pingfen' != 'zuofa':
fields["pingfen"] = float( self.remove_html(response.css('''span.cur_score::text''').extract_first()))
else:
try:
fields["pingfen"] = float( emoji.demojize(response.css('''span.cur_score::text''').extract_first()))
except:
pass
except:
pass
try:
if '(.*?)' in '''div.ranking span.sum::text''':
fields["paiming"] = int( re.findall(r'''div.ranking span.sum::text''', response.text, re.S)[0].strip())
else:
if 'paiming' != 'xiangqing' and 'paiming' != 'detail' and 'paiming' != 'pinglun' and 'paiming' != 'zuofa':
fields["paiming"] = int( self.remove_html(response.css('''div.ranking span.sum::text''').extract_first()))
else:
try:
fields["paiming"] = int( emoji.demojize(response.css('''div.ranking span.sum::text''').extract_first()))
except:
pass
except:
pass
try:
if '(.*?)' in '''a#more_cmt_href::text''':
fields["dianping"] = int( re.findall(r'''a#more_cmt_href::text''', response.text, re.S)[0].strip().replace('共', '').replace('条点评',''))
else:
if 'dianping' != 'xiangqing' and 'dianping' != 'detail' and 'dianping' != 'pinglun' and 'dianping' != 'zuofa':
fields["dianping"] = int( self.remove_html(response.css('''a#more_cmt_href::text''').extract_first()).replace('共', '').replace('条点评',''))
else:
try:
fields["dianping"] = int( emoji.demojize(response.css('''a#more_cmt_href::text''').extract_first()).replace('共', '').replace('条点评',''))
except:
pass
except:
pass
return fields
# 数据清洗
def pandas_filter(self):
engine = create_engine('mysql+pymysql://root:123456@localhost/spiderv4e6ribr?charset=UTF8MB4')
df = pd.read_sql('select * from lvyouxinxi 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 `lvyouxinxi`(
id
,title
,picture
,jyywsj
,dizhi
,jianjie
,xqdz
,pingfen
,paiming
,dianping
)
select
id
,title
,picture
,jyywsj
,dizhi
,jianjie
,xqdz
,pingfen
,paiming
,dianping
from `v4e6ribr_lvyouxinxi`
where(not exists (select
id
,title
,picture
,jyywsj
,dizhi
,jianjie
,xqdz
,pingfen
,paiming
,dianping
from `lvyouxinxi` where
`lvyouxinxi`.id=`v4e6ribr_lvyouxinxi`.id
))
'''
cursor.execute(sql)
connect.commit()
connect.close()
💕💕作者:计算机源码社
💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流!
💕💕学习资料、程序开发、技术解答、文档报告
💕💕如需要源码,可以扫取文章下方二维码联系咨询