磁力搜索网站搭建

需求来源

爬虫

之前偶然间看见这篇文章(20230211现在已经访问不了了),就想着自己也整一个。

整一个

现有问题

现有的BT搜索网站存在关键词匹配问题,导致搜索结果与关键词关联度不高。

需求

为了搭建DHT爬虫、改进现有网站搜索准确率、测试MySQL数据库性能、测试网站并发量、对大量数据进行数据分析,需要搭建一个完整的磁力链接搜索引擎网站。

需求分析

搜集相关信息,分析现有的磁力链接搜索网站信息。对需求进行细化。

一个磁力链接网站应该包括:

  • 支持前端页面显示
    • 支持搜索引擎页面显示,类似于百度首页
    • 支持搜索引擎页面热词显示
    • 支持搜索结果整合显示
    • 支持显示某个磁力链接的详细信息
  • 支持搜索引擎功能
    • 支持获取搜索引擎页面输入的关键词
    • 支持关键词拆分
    • 支持通过关键词搜索数据库
    • 支持获取数据库数据
  • 支持数据库功能
    • 保存从DHT网络获取的数据
    • 支持对搜索引擎提供数据
  • 支持爬虫功能
    • 支持DHT原理获取磁力链接和磁力链接的详细信息
    • 支持将获取的数据保存到数据库

架构设计

根据一般网站的设计架构

flowchart LR

A[前端] --- B[Redis]
B --- C[搜索引擎]
B --- D
C --- D[数据库]
D --- E[爬虫]

系统概要设计

模块图为

flowchart LR

A[磁力搜索网站]
A --> B[前端]
A --> C[搜索引擎]
A --> D[数据库]
A --> E[爬虫]
B --> BA[搜索引擎页面]
B --> BB[热词]
B --> BC[搜索结果]
B --> BD[详细信息]
C --> CA[分词]
C --> CB[搜索数据库]
C --> CC[返回数据]
D --> DA[保存数据]
D --> DB[提供数据]
E --> EA[获取数据]
E --> EB[保存数据]

前端/搜索引擎使用php 8.4,分词使用结巴库,数据库使用MySQL 8.1,爬虫使用python

用户交互流程图

flowchart TB

A[开始] --> B[搜索框输入关键词]
B --> C{是否搜索}
C --No--> F
C --Yes--> D[显示搜索结果]
D --> E{选择某个条目}
E --Yes--> E1[显示详细信息]
E --No--> F[结束]

网站时序图

sequenceDiagram
Title: 网站交互时序图

actor 用户
用户->>前端: 打开网站
前端->>用户: 显示搜索引擎页面
用户->>前端: 输入关键字
用户->>前端: 点击搜索
前端->>搜索引擎: 关键词
搜索引擎->>数据库: 匹配数据
数据库->>前端: 数据
前端->>用户: 搜索结果页面
用户->>前端: 点击某个条目
前端->>数据库: 查询详细信息
数据库->>前端: 详细数据
前端->>用户: 详细信息页面

系统详细设计

前端

负责与用户交互显示部分

搜索引擎页面

一个带文本框的界面

搜索结果页面

一个列表,多页

详细信息页面

种子的详细信息

搜索引擎

关键词传递

获取用户输入的关键词

分词

拆分用户输入的句子,丢弃无意义的字、词。

匹配

通过拆分后的词组到数据库中查询对应数据

数据库

读取

通过select读取数据

保存

通过insert保存数据

匹配

通过关键词查询数据

爬虫

爬虫会一直在后台运行

获取数据

通过爬虫获取数据

保存数据

获取的数据保存至数据库。

数据保存

数据怎么获取取决于数据怎么保存,以什么格式保存,所以先说保存。一旦数据开始获取想要修改就很麻烦了,所有要先规划好。

首先数据库分为两类(当然,肯定在在同一个数据库中保存)简要信息(显示在搜索结果中的信息)和详细信息(点击搜索结果中的某一个)。磁力链接本质上是十六进制字符串,每类表都有16个。热词表用于显示搜索关键词热度。

数据库相关

在通过搜索引擎进行搜索时,只需要显示磁力链接的部分信息就可以了。

和这个类似

brief

字段包括:文件名、热度、文件大小、创建时间、文件格式

而显示详细信息时

info

字段包括:文件名、热度、磁力链接、文件大小、创建时间、文件数量、文件列表

文件列表这个字段,它的数量未知。我的处理是独立一个表。

表创建:

  • 简要信息一个表,详细信息中保存除简要信息的字段
  • 还有一种方法是详细信息保存所有字段,简要信息从详细信息中提取此部分信息,不知道两者有何差别,待网站搭建完成后再测试。

现在网站属于测试阶段,所以就先只保存在详细信息中,然后以索引的方式生成简要信息。

简要信息表

此表用于储存种子对应的信息。

1
2
3
4
5
6
7
8
9
10
11
12
create table if not exists `index_a` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hash` varchar(40) NOT NULL,
`name` varchar(1000) NOT NULL,
`hot` int(12) NOT NULL,
`create_time` int(12) NOT NULL,
`file_size` bigint(50) NOT NULL,
`file_num` int(8) NOT NULL,
`file_type` varchar(10) NOT NULL,
`update_time` int(12) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

这样的表有16个。

详细信息表

此表储存种子所表示的所有文件

1
2
3
4
5
6
create table if not exists `list_0` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(1000) NOT NULL,
`file_size` bigint(50) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

此表同样有16个

至此数据保存的格式确定了,下一步是获取数据并保存到数据库中

数据获取

磁力链接是获取不完的

我做不到从0开始,只能从之前的代码修改,之前的两个项目都是用Python,那就一条路走到黑。

原计划是打算基于别人的代码修改,经过测试,别人的代码无法实现获取数据和保存到数据库。数据库部分的代码与DHT部分代码有冲突,两者一起导致程序无法运行。

所以本系列采用的方式是别人的Python代码(就是保存到Redis的方式,毕竟已经用它获取了170万条数据了),然后用Python脚本将其解析保存到MySQL数据库中。

下面简单介绍一下Python版的原理和流程,后期会用C++写一个直接获取保存到MySQL的版本。

从GitHub上面找了现成的:

asyncDHT使用MySQL数据库存储数据,但是我在Ubuntu20.04+MySQL+Python3.8.5上面没有没有成功运行。magnet-dht可以使用,并且跑满带宽,但是使用Redis存储数据,而我不会使用Redis。

秃头

asyncDHT作者在阿里云ECS(1核、1G、100M/s)上跑了66小时。获取get_peers请求的info_hash 21,313,390条记录(不重复),announce_peer请求的info_hash 849,355条记录(不重复),get_peers和announce_peer请求的info_hash 76,411,582条记录(含重复)。

模块流程图为

flowchart LR

A[utils] --> B[crawler]
A[utils] --> C[metadata]
C[metadata] --> D[crawler]
E[bencode] --> C[metadata]
F[mysqlpool] --> C[metadata]
F[mysqlpool] --> B[crawler]

数据流为

flowchart TD

A(开始) --> B[receive_response_forever]
B[receive_response_forever] --> C[bootstrap]
C[bootstrap] --> D[send_find_node]
C[bootstrap] --> E[on_message]
E[on_message] --> F[on_find_node_response]
E[on_message] --> G[on_get_peers_request]
E[on_message] --> H[on_announce_peer_request]
G[on_get_peers_request] --> I[save_magnet]
H[on_announce_peer_request] --> I[save_magnet]

运行程序

running

这样就会有源源不断的数据填充到数据库表里面,除了本系列之外,MySQL入门、测试也会用到这些表、数据。

数据爬取

爬虫环境为:2xCPU + 8G RAM + 80G HD + Ubuntu LTS 20.04 + Apache2 2.4.41 + PHP 7.4.3 + MySQL 8.0.26 + Python3 3.8.10

经过接近两个月的爬取。获取到了大约3GB的数据,共计5051203条

state

state

state

我在腾讯云ECS(2核,4G,5M/s)上运行接近两周(运行时间太长我忘了具体时间),获取记录get_peers类型info_hash为8488890条,announce_peer类型info_hash为129条。

穷的想叮当

爬了那么长时间我才意识到链接是永远爬不完的。

熬夜

get_peers中0-f开头的数量为:

peer

get_announce中0-f开头的数量为:

announce

占比图为:

percent

那么我们进行下一步

Redis->MySQL

使用脚本将数据从Redis中提取并保存到MySQL中。

数据大约为505万条,单线程耗时12个小时。

导入了5050679条数据,其余524条数据因数据字符问题无法导入。

磁力文件

磁力链接总数太多,选取get_peers中b开头的磁力链接,只有50万条,这样爬取的种子不会太多。

但是找不到有效的BT种子仓库或者找的仓库无法直接获取,无法批量获取*.torrent文件,可能需要考虑从dht网络中直接获取种子文件。

待实现功能


磁力搜索网站搭建
https://blog.jackeylea.com/bt/introduction-of-torrent-webiste/
作者
JackeyLea
发布于
2020年12月3日
许可协议