你来你也可以做一个网盘搜索引擎

你来你也可以做一个网盘搜索引擎 ​✨文章摘要(AI生成)

在这篇文章中,笔者分享了他在过去两年间的一个小型网盘搜索引擎项目,以复习和实践搜索引擎的相关知识。

项目使用了多个技术栈,包括 Scrapy、ElasticSearch、NestJS 和 VueJS,整体架构相对简化。

笔者详细描述了爬虫的实现思路,从种子网站爬取网盘资源并使用正则表达式提取链接,最终将数据索引到 ElasticSearch 中。文章还提到在部署过程中遇到的 IP 管理问题,提醒读者注意安全设置。后端部分提供了简单的搜索和建议接口,而前端则使用了腾讯的 UI 库,构建了一个用户友好的搜索界面。项目没有开源的计划,并且笔者认为这个过程为他提供了宝贵的实践经验。

前言 ​两年前笔者做过一个当时非常有成就感的小型搜索引擎,但回过头一看,全忘完了🙃,为了复习一下以前的知识,前面写过一篇文章总结概括了一下搜索引擎的原理。但作为程序员,光是理论肯定是不够的,所以得实践一下。以前的文章搜索引擎说实话没啥用,所以这次为了让项目更加有意思一点,决定做的是一个网盘类的搜索引擎,也算是有点用处。

笔者将整个搜索引擎简化了很多,甚至比两年前做的那个小型搜索引擎还要简单,但也算是一个微型搜索引擎了,帮助笔者实践了部分知识。

项目演示 ​

线上演示地址:pan.justin3go.com

至文章发布 3 个月内该地址应该都可以访问。服务器暂时买了 3 个月的放在那里,3 个月之后看是否还有空闲的服务器,否则应该就会下线该服务。

技术概览 ​让我们还是先看看之前这篇文章的一个架构图:

然后具体来说笔者使用了如下技术栈:

爬虫框架:Scrapy索引存储/搜索:ElasticSearch后端服务:NestJS前端服务:VueJS部署:Docker爬虫 ​本章不会介绍 Scrapy 的使用,只会大致讲讲笔者的思路,框架使用请见Scrapy 官网

找一些种子网站,比如知乎、贴吧中网盘资源分享的圈子爬取该网页,文章类搜索引擎就是识别标题、正文之类的,而网盘类搜索引擎更加简单,直接使用正则表达式识别域名就可以了,比如阿里云盘的正则就是aliyundrive.com/s/[A-Za-z0-9]{11}将提取的内容做处理并索引到 ElasticSearch 之中提取该网页的所有外链,并过滤,比如资源链接(图片、视频、音乐)之类,继续爬取这些外链,重复该步骤这里笔者将爬行深度限制为了 10,因为一般离导航网站越远,越不重要,就节省资源,不爬取了。

python 代码就不贴了,笔者已经很久没写过 python 代码了,这次写 python 代码基本上都是说说思路,然后 GPT 帮助笔者写的,反正感觉挺烂的,但总算 Debug 能力还在,把这堆代码跑起来了。

最后部署就用了 node 的 pm2 守护这个爬虫进程,放在服务器上一直运行就行了。

索引 ​部署方面使用 Docker 进行部署

部署流程笔者基本上都是参考的这篇文章,整体下来也比较简单,就不再重新部署演示了。

需要注意的是,不要为了贪图方便,不设置 IP 白名单,笔者就是因为家里网络属于动态 IP,为了本地开发方便,就没有单独设置 IP 白名单,结果爬取了 3 周的数据全部被删除了,而且还不长记性,被删除了 2 次:

MD,我的 Elasticsearch 的索引全被删除了,之前想着没人知道我的 IP 地... #掘金沸点#https://juejin.cn/pin/7262761740524372029

太猖狂了,删我 ES 数据库 - #掘金沸点#https://juejin.cn/pin/7264921613552058402

所以这里要么使用iptables工具进行限制,或者直接使用云厂商的安全组策略,仅允许应用服务器的 IP 访问。

应用服务 ​最后就是应用服务了,这些就轻车熟路了。

后端部分 ​为了简单,笔者这里后端就只写了两个接口,一个是搜索的接口,一个是搜索建议的接口,就是输入前半截,提示后半截这种。

如下是 NestJS 中service部分:

tsimport { Injectable } from '@nestjs/common';

import { ElasticsearchService } from '@nestjs/elasticsearch';

import { SearchDto } from './dto/search.dto';

import { SuggestDto } from './dto/suggest.dto';

@Injectable()

export class SearchService {

constructor(private readonly elasticsearchService: ElasticsearchService) {}

async search(data: SearchDto) {

const { pageNo, pageSize, query } = data;

const esRes = await this.elasticsearchService.search({

index: 'pan',

body: {

from: (pageNo - 1) * pageSize, // 从哪里开始

size: pageSize, // 查询条数

query: {

match: {

title: query, // 搜索查询到的内容

},

},

highlight: {

pre_tags: [""],

post_tags: [''],

fields: {

title: {},

},

fragment_size: 40,

},

},

});

// 组装参数

const finalRes = {

took: esRes.body.took,

total: esRes.body.hits.total.value,

data: esRes.body.hits?.hits.map((item: any) => ({

title: item._source.title,

pan_url: item._source.pan_url,

extract_code: item._source.extract_code,

highlight: item.highlight,

})),

};

return finalRes;

}

async suggest(data: SuggestDto) {

const { input } = data;

const esRes = await this.elasticsearchService.search({

index: 'pan',

suggest_field: 'suggest',

suggest_mode: 'always',

suggest_size: 20,

suggest_text: input,

});

return esRes.body.suggest;

}

}非常少,后端服务基本上就只写上面这几行代码,啥用户系统、安全限制都没做。没必要,只是为了演示,先做主要功能,如果有需要再迭代就行了,多半也不会继续开发了。

前端部分 ​整个前端页面就只有一个页面,也非常简单,稍微麻烦一点的就是兼容了一下移动端显示,UI 库使用的是腾讯的 UI 库-TDesign,感觉还挺好看的,其他就没啥特别的了,如下是那个主页面的具体代码:

template部分:

htmlscript部分

htmlcss部分

scss还有一些其他零碎的代码就不贴了,主要页面就是上述部分。

最后 ​整体开发下来一个感受就是:由于人为简化了很多,所以每一部分,比如前端、后端、爬虫、部署之类的单独看都非常简单,但整个流程走下来却是较为复杂的,比如遇到 BUG 排查就会较为耗时。

项目应该不会开源,也没开源的必要,毕竟代码没怎么整理,比如前端项目用脚手架创建的AboutView.vue笔者都没删除。