基于大数据+Hadoop的豆瓣电子图书推荐系统实现

2024-05-08 12:36

本文主要是介绍基于大数据+Hadoop的豆瓣电子图书推荐系统实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄

🌹简历模板、学习资料、面试题库、技术互助

🌹文末获取联系方式 📝

在这里插入图片描述


系列文章目录

基于大数据+Hadoop的豆瓣电子图书推荐系统实现


文章目录

  • 系列文章目录
  • 1、前言介绍
  • 2、功能设计
  • 3、功能实现
  • 库表设计
  • 5、关键代码
  • 6、Lunwen参考
  • 往期热门专栏回顾


1、前言介绍

随着信息技术的飞速发展,特别是互联网和移动通信技术的普及,数字化阅读逐渐成为人们获取知识和信息的重要方式。在这样的背景下,电子图书以其便捷性和丰富性受到了广泛欢迎。随着电子图书市场的不断扩大,书籍的种类和数量也在急剧增加,这为用户挑选书籍带来了挑战。为了解决信息过载的问题,个性化推荐系统应运而生,并逐渐成为在线阅读平台不可或缺的一部分。基于用户历史行为数据进行推荐的协同过滤算法尤为流行。处理庞大的用户群体和海量的图书数据需要强大的计算能力,传统的单机计算模式已无法满足需求。Hadoop作为一个开源的分布式计算平台,以其高容错性、高扩展性和对大数据处理的优秀能力,成为大数据分析的首选工具。因此,利用Hadoop来构建电子图书推荐系统,不仅可以有效处理和分析大规模数据集,提升推荐质量,还能保证系统的可扩展性和稳定性。

在这里插入图片描述
基于Hadoop的豆瓣电子图书推荐系统的研究与实现能够为用户提供更加精准和个性化的阅读推荐,从而优化用户体验,提高用户满意度和平台黏性。通过分析用户的历史阅读行为和偏好,系统可以发现用户的阅读模式,进而推荐更符合个人兴趣的书籍,帮助用户节省筛选时间,增强阅读效率。对于电子图书平台来说,一个高效的推荐系统可以促进更多优质内容的分发,增加用户流量和书籍销量,从而带动平台的经济效益。该系统的建立还有助于推动数据挖掘和机器学习技术在实际应用中的发展,为相关领域提供宝贵的实践经验和研究成果。最后,随着数据处理技术的不断进步,该研究还可以为未来电子图书推荐系统的改进提供理论基础和技术支持,具有长远的研究和应用价值。

2、功能设计

系统的功能设计是整个系统的运行基础,是一个把设计需求替换成以计算机系统的形式表示出来。通过对豆瓣电子图书推荐系统的调查、分析和研究,得出了该系统的总体规划,这是开发设计系统的初步核心。如下图所示:
在这里插入图片描述
爬虫数据集展示:
在这里插入图片描述

3、功能实现

在这里插入图片描述
当人们打开系统的网址后,首先看到的就是首页界面。在这里,人们能够看到系统的导航条,通过导航条导航进入各功能展示页面进行操作。系统首页界面如图5-1所示:
在这里插入图片描述
在注册流程中,用户在Vue前端填写必要信息(如用户名、密码等)并提交。前端将这些信息通过HTTP请求发送到Java后端。后端处理这些信息,检查用户名是否唯一,并将新用户数据存入MySQL数据库。完成后,后端向前端发送注册成功的确认,前端随后通知用户完成注册。这个过程实现了新用户的数据收集、验证和存储。注册页面如图5-2所示:
在这里插入图片描述

图5-2注册详细页面

豆瓣高分:在豆瓣高分页面的输入栏中输入书名、作者、出版社和标签进行查询,可以查看到豆瓣高分详细信息,并进行评论或收藏操作;豆瓣高分页面如图5-3所示:
在这里插入图片描述

图5-3豆瓣高分详细页面

个人中心:在个人中心页面可以对个人中心、修改密码、我的发布、我的收藏等进行详细操作;如图5-4所示:
在这里插入图片描述
在登录流程中,用户首先在Vue前端界面输入用户名和密码。这些信息通过HTTP请求发送到Java后端。后端接收请求,通过与MySQL数据库交互验证用户凭证。如果认证成功,后端会返回给前端,允许用户访问系统。这个过程涵盖了从用户输入到系统验证和响应的全过程。如图5-5所示。

用户管理功能在视图层(view层)进行交互,比如点击“查询、添加或删除”按钮或填写用户信息表单。这些用户表单动作被视图层捕获并作为请求发送给相应的控制器层(controller层)。控制器接收到这些请求后,调用服务层(service层)以执行相关的业务逻辑,例如验证输入数据的有效性和与数据库的交互。服务层处理完这些逻辑后,进一步与数据访问对象层(DAO层)交互,后者负责具体的数据操作如查看、修改或删除用户信息,并将操作结果返回给控制器。最终,控制器根据这些结果更新视图层,以便用户功能可以看到最新的信息或相应的操作反馈。如图5-7所示:
在这里插入图片描述

图5-7用户管理界面

豆瓣高分管理功能在视图层(view层)进行交互,比如点击“查询、添加、删除或爬取数据”按钮或填写豆瓣高分信息表单。这些豆瓣高分表单动作被视图层捕获并作为请求发送给相应的控制器层(controller层)。控制器接收到这些请求后,调用服务层(service层)以执行相关的业务逻辑,例如验证输入数据的有效性和与数据库的交互。服务层处理完这些逻辑后,进一步与数据访问对象层(DAO层)交互,后者负责具体的数据操作如查看、修改、查看评论或删除豆瓣高分信息,并将操作结果返回给控制器。最终,控制器根据这些结果更新视图层,以便豆瓣高分功能可以看到最新的信息或相应的操作反馈。如图5-8所示:
在这里插入图片描述

图5-8豆瓣高分管理界面

管理员进行爬取数据后,点击主页面右上角的看板,可以查看到系统简介、书名、作者统计、价格统计、出版社、评分统计、豆瓣高分总数、豆瓣高分信息等实时的分析图进行可视化管理;如图5-9所示:
在这里插入图片描述

图5-9看板界面

库表设计

表4-11:豆瓣高分
在这里插入图片描述

5、关键代码

# # -*- coding: utf-8 -*-# 数据爬取文件import scrapy
import pymysql
import pymssql
from ..items import DianzitushuItem
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 DianzitushuSpider(scrapy.Spider):name = 'dianzitushuSpider'spiderUrl = 'https://read.douban.com/j/kind/'start_urls = spiderUrl.split(";")protocol = ''hostname = ''realtime = Falsedef __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, '0n4b129m_dianzitushu') == 1:cursor.close()connect.close()self.temp_data()returnpageNum = 1 + 1for 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.schemeself.hostname = _url.netlocplat = 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, '0n4b129m_dianzitushu') == 1:cursor.close()connect.close()self.temp_data()returndata = json.loads(response.body)try:list = data["list"]except:passfor item in list:fields = DianzitushuItem()try:fields["title"] = emoji.demojize(self.remove_html(str( item["title"] )))except:passtry:fields["picture"] = emoji.demojize(self.remove_html(str( item["cover"] )))except:passtry:fields["salesprice"] = float( item["salesPrice"]/100)except:passtry:fields["wordcount"] = int( item["wordCount"])except:passtry:fields["author"] = emoji.demojize(self.remove_html(str(','.join(str(i['name']) for i in  item["author"]) )))except:passtry:fields["biaoqian"] = emoji.demojize(self.remove_html(str( item.get("biaoqian", "小说") )))except:passtry:fields["detailurl"] = emoji.demojize(self.remove_html(str('https://read.douban.com'+ item["url"] )))except:passdetailUrlRule = item["url"]if '["url"]'.startswith('http'):if '{0}' in '["url"]':detailQueryCondition = []detailUrlRule = '["url"]'i = 0while i < len(detailQueryCondition):detailUrlRule = detailUrlRule.replace('{' + str(i) + '}', str(detailQueryCondition[i]))i += 1else:detailUrlRule =item["url"]detailUrlRule ='https://read.douban.com'+ detailUrlRuleif detailUrlRule.startswith('http') or self.hostname in detailUrlRule:passelse:detailUrlRule = self.protocol + '://' + self.hostname + detailUrlRulefields["laiyuan"] = detailUrlRuleyield scrapy.Request(url=detailUrlRule, meta={'fields': fields}, callback=self.detail_parse)# 详情解析def detail_parse(self, response):fields = response.meta['fields']try:if '(.*?)' in '''span[itemprop="genre"]::text''':fields["genre"] = str( re.findall(r'''span[itemprop="genre"]::text''', response.text, re.S)[0].strip())else:if 'genre' != 'xiangqing' and 'genre' != 'detail' and 'genre' != 'pinglun' and 'genre' != 'zuofa':fields["genre"] = str( self.remove_html(response.css('''span[itemprop="genre"]::text''').extract_first()))else:try:fields["genre"] = str( emoji.demojize(response.css('''span[itemprop="genre"]::text''').extract_first()))except:passexcept:passtry:fields["chubanshe"] = str( response.xpath('''//span[text()="出版社"]/../span[@class="labeled-text"]/span[1]/text()''').extract()[0].strip())except:passtry:fields["cbsj"] = str( response.xpath('''//span[text()="出版社"]/../span[@class="labeled-text"]/span[2]/text()''').extract()[0].strip())except:passtry:if '(.*?)' in '''a[itemprop="provider"]::text''':fields["provider"] = str( re.findall(r'''a[itemprop="provider"]::text''', response.text, re.S)[0].strip())else:if 'provider' != 'xiangqing' and 'provider' != 'detail' and 'provider' != 'pinglun' and 'provider' != 'zuofa':fields["provider"] = str( self.remove_html(response.css('''a[itemprop="provider"]::text''').extract_first()))else:try:fields["provider"] = str( emoji.demojize(response.css('''a[itemprop="provider"]::text''').extract_first()))except:passexcept:passtry:if '(.*?)' in '''span.score::text''':fields["score"] = float( re.findall(r'''span.score::text''', response.text, re.S)[0].strip())else:if 'score' != 'xiangqing' and 'score' != 'detail' and 'score' != 'pinglun' and 'score' != 'zuofa':fields["score"] = float( self.remove_html(response.css('''span.score::text''').extract_first()))else:try:fields["score"] = float( emoji.demojize(response.css('''span.score::text''').extract_first()))except:passexcept:passtry:if '(.*?)' in '''span.amount::text''':fields["pingjiashu"] = int( re.findall(r'''span.amount::text''', response.text, re.S)[0].strip().replace('评价',''))else:if 'pingjiashu' != 'xiangqing' and 'pingjiashu' != 'detail' and 'pingjiashu' != 'pinglun' and 'pingjiashu' != 'zuofa':fields["pingjiashu"] = int( self.remove_html(response.css('''span.amount::text''').extract_first()).replace('评价',''))else:try:fields["pingjiashu"] = int( emoji.demojize(response.css('''span.amount::text''').extract_first()).replace('评价',''))except:passexcept:passreturn fields# 数据清洗def pandas_filter(self):engine = create_engine('mysql+pymysql://root:123456@localhost/spider0n4b129m?charset=UTF8MB4')df = pd.read_sql('select * from dianzitushu 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 * 1b[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.databaseNameexcept: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 1else:return 0# 数据缓存源def temp_data(self):connect = self.db_connect()cursor = connect.cursor()sql = '''insert into `dianzitushu`(id,title,picture,salesprice,wordcount,author,biaoqian,detailurl,genre,chubanshe,cbsj,provider,score,pingjiashu)selectid,title,picture,salesprice,wordcount,author,biaoqian,detailurl,genre,chubanshe,cbsj,provider,score,pingjiashufrom `0n4b129m_dianzitushu`where(not exists (selectid,title,picture,salesprice,wordcount,author,biaoqian,detailurl,genre,chubanshe,cbsj,provider,score,pingjiashufrom `dianzitushu` where`dianzitushu`.id=`0n4b129m_dianzitushu`.id))order by rand()limit 50;'''cursor.execute(sql)connect.commit()connect.close()

6、Lunwen参考

在这里插入图片描述
在这里插入图片描述


往期热门专栏回顾

专栏描述
Java项目实战介绍Java组件安装、使用;手写框架等
Aws服务器实战Aws Linux服务器上操作nginx、git、JDK、Vue
Java微服务实战Java 微服务实战,Spring Cloud Netflix套件、Spring Cloud Alibaba套件、Seata、gateway、shadingjdbc等实战操作
Java基础篇Java基础闲聊,已出HashMap、String、StringBuffer等源码分析,JVM分析,持续更新中
Springboot篇从创建Springboot项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回、全局异常处理、Swagger文档
Spring MVC篇从创建Spring MVC项目,到加载数据库、静态资源、输出RestFul接口、跨越问题解决到统一返回
华为云服务器实战华为云Linux服务器上操作nginx、git、JDK、Vue等,以及使用宝塔运维操作添加Html网页、部署Springboot项目/Vue项目等
Java爬虫通过Java+Selenium+GoogleWebDriver 模拟真人网页操作爬取花瓣网图片、bing搜索图片等
Vue实战讲解Vue3的安装、环境配置,基本语法、循环语句、生命周期、路由设置、组件、axios交互、Element-ui的使用等
Spring讲解Spring(Bean)概念、IOC、AOP、集成jdbcTemplate/redis/事务等

资料获取,更多粉丝福利,关注下方公众号获取

在这里插入图片描述

这篇关于基于大数据+Hadoop的豆瓣电子图书推荐系统实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/970334

相关文章

Java StringBuilder 实现原理全攻略

《JavaStringBuilder实现原理全攻略》StringBuilder是Java提供的可变字符序列类,位于java.lang包中,专门用于高效处理字符串的拼接和修改操作,本文给大家介绍Ja... 目录一、StringBuilder 基本概述核心特性二、StringBuilder 核心实现2.1 内部

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

SpringBoot AspectJ切面配合自定义注解实现权限校验的示例详解

《SpringBootAspectJ切面配合自定义注解实现权限校验的示例详解》本文章介绍了如何通过创建自定义的权限校验注解,配合AspectJ切面拦截注解实现权限校验,本文结合实例代码给大家介绍的非... 目录1. 创建权限校验注解2. 创建ASPectJ切面拦截注解校验权限3. 用法示例A. 参考文章本文

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF