互联网小说资源网站非常的多,但是很多阅读资源都需要收费开会员才能阅读。因此本次毕业设计程序立足于网络爬虫技术采集互联网小说资源分析汇总至本小说推荐平台,基于用户协同过滤推荐算法对不同的用户展开个性化的小说内容推荐阅读。
一、程序设计
本次基于爬虫的小说推荐系统主要内容涉及:
主要功能模块:小说阅读推荐前端平台,小说数据管理与分析平台
主要包含技术:java爬虫,redis,springboot,mybatisplus,mysql,javascript,vue.js,html,css,HttpClient
主要包含算法及方法:Kmeans聚类,基于用户协同过滤,关键词加权计算
系统采用前后端分离的开发模式完成,小说推荐阅读前端平台主要采用Vue.js,javascript,html,CSS等技术实现。系统前后端数据交互,采用Ajax异步调用传输JSON实现。
小说推荐平台主要包括以下功能清单:
用户登录注册
首页小说推荐
热门小说推荐
小说热门排行榜
小说收藏排行榜
小说章节展示
小说在线阅读
小说推荐,点赞,收藏
小说分类阅读,小说检索
我的书架
二、效果实现
系统首页
小说详情
小说检索
章节阅读
用户登录
分类列表
后台管理
统计分析
其他效果省略
三、小说爬虫采集设计
本次毕设系统在互联网小说数据采集过程中,主要采用java实现小说基本信息 小说章节内容数据的采集,针对采集完成的小说数据按照小说类别进行归类计算,依托与玄幻小说,武侠小说,都市言情等种类划分。小说采集原网站主要来源与互联网免费小说资源网,主要的小说采集流程,如下图所示:
爬虫采集代码
代码语言:java复制 @PostConstruct
public void initNovelJob() {
new Thread(() -> {
logger.info("-------------------------------CrawlerTask 开始小说网站数据-------------------------------");
Document document = null;
String link = "https://www.zhetian.org/top/lastupdate.html";
for (int i = 0; i < 3; i ) {
try {
document = Jsoup.connect(link).ignoreContentType(true).post();
} catch (Exception e) {
System.out.println(link ",打开失败,重新尝试:" i);
}
if (null != document) break;
}
if (null == document) {
logger.info("-------------------------------CrawlerTask 爬取小说网站数据失败-------------------------------");
return;
}
Element body = document.body();
Elements nvs = body.select("body > section > div > div.w-left > div > div.body > ul > li > span.n > a:nth-child(2)");
for (int n = 0; n < nvs.size(); n ) {
if (n >= 10) break;
Document nd = null;
String nlink = nvs.get(n).attr("abs:href");
for (int i = 0; i < 3; i ) {
try {
nd = Jsoup.connect(nlink).ignoreContentType(true).post();
} catch (Exception e) {
System.out.println(nlink ",打开失败,重新尝试:" i);
}
if (null != nd) break;
}
if (null == nd) return;
String name = nd.select("body > section > div:nth-child(2) > div.w-left > div > div.header.line > h1").text();
String img = nd.select("body > section > div:nth-child(2) > div.w-left > div > div.body.novel > div.novelinfo > div.novelinfo-r > img").attr("abs:src");
String zz = nd.select("#author > i:nth-child(1) > a").text();
String lb = nd.select("#author > i:nth-child(2) > a").text();
String zt = nd.select("#author > i:nth-child(3)").text();
String dj = nd.select("#stats > i:nth-child(1)").text();
String tj = nd.select("#stats > i:nth-child(2)").text();
String sc = nd.select("#stats > i:nth-child(3)").text();
String gxsj = nd.select("#update > i:nth-child(1)").text();
String zxzj = nd.select("#update > i:nth-child(2) > a").text();
String nrjj = nd.select("#intro").text();
String uuid = Md5Utils.GetMD5Code(nlink);
template.update("insert ignore into t_novels_app (name,uuid,link,zz,lb,zt,dj,tj,sc,gxsj,zxzj,nrjj,img)"
" values(?,?,?,?,?,?,?,?,?,?,?,?,?)", new Object[]{name, uuid, nlink, zz, lb,
zt, dj, tj, sc, gxsj, zxzj, nrjj, img});
logger.info("连接:" nlink ",抓取成功");
Elements select = nd.select("body > section > div.card.mt20.fulldir > div.body > ul > li > a");
List<Object[]> args = Lists.newArrayList();
select.stream().forEach(item -> {
String cname = item.text();
String clink = item.attr("abs:href");
if (StringUtils.isEmpty(cname) || StringUtils.isEmpty(clink)) return;
args.add(new Object[]{uuid, cname, clink});
});
template.batchUpdate("insert ignore into t_novels_chapter (nid,name,link)"
" values(?,?,?)", args);
}
logger.info("-------------------------------CrawlerTask 爬取小说网站数据结束-------------------------------");
}).start();
}
@PostConstruct
public void crawlerNovelDetailJob() {
new Thread(() -> {
logger.info("-------------------------------CrawlerTask 开始遮天小说详情数据-------------------------------");
List<Map<String, Object>> cps = template.queryForList("SELECT id,link from t_novels_chapter WHERE ISNULL(content) AND status=1 limit 100");
if (CollectionUtils.isEmpty(cps)) {
logger.info("-------------------------------CrawlerTask 没有待执行任务,结束-------------------------------");
return;
}
List<Object[]> args = Lists.newArrayList();
cps.forEach(item -> {
Document document = null;
String link = (String) item.get("link");
for (int i = 0; i < 3; i ) {
try {
document = Jsoup.connect(link).ignoreContentType(true).post();
} catch (Exception e) {
System.out.println(link ",打开失败,重新尝试:" i);
}
if (null != document) break;
}
if (null == document) {
return;
}
String getUrl = "https://www.zhetian.org" Regex.get("get\(\'(.*)\'", document.html(), 1);
if (StringUtils.isBlank(getUrl)) return;
Document detail = null;
for (int i = 0; i < 3; i ) {
try {
detail = Jsoup.connect(getUrl).ignoreContentType(true).get();
} catch (Exception e) {
System.out.println(link ",打开失败,重新尝试:" i);
}
if (null != detail) break;
}
if (null == detail) return;
JSONObject object = JSONObject.parseObject(detail.body().html().replaceAll("\<br\\\ \/\>", "<br>"));
String content = object.getString("info");
if (StringUtils.isBlank(content)) return;
args.add(new Object[]{content, item.get("id")});
});
if (CollectionUtils.isEmpty(args)) {
logger.info("-------------------------------CrawlerTask 未抓取到具体章节内容,结束-------------------------------");
return;
}
template.batchUpdate("update t_novels_chapter SET content=? WHERE id=? ", args);
logger.info("-------------------------------CrawlerTask 爬取小说详情数据结束-------------------------------");
}).start();
}