plugin/panta/panta插件设计文档.md
PanTa搜索插件是一个用于从91panta.cn网站搜索并提取网盘链接的Go语言插件。该插件能够智能识别多种网盘链接类型,并自动关联提取码,是一个高性能、高可靠性的网络爬虫实现。
插件采用模块化设计,主要包含以下几个核心部分:
// 预编译的正则表达式
var (
topicIDRegex = regexp.MustCompile(`topicId=(\d+)`)
yearRegex = regexp.MustCompile(`\(([0-9]{4})\)`)
postTimeRegex = regexp.MustCompile(`发表时间:(.+)`)
pwdParamRegex = regexp.MustCompile(`[?&]pwd=([0-9a-zA-Z]+)`)
pwdPatterns = []*regexp.Regexp{...}
netDiskPatterns = []*regexp.Regexp{...}
)
设计思想:
var (
isNetDiskLinkCache = sync.Map{}
determineLinkTypeCache = sync.Map{}
extractPasswordCache = sync.Map{}
topicIDCache = sync.Map{}
postTimeCache = sync.Map{}
yearCache = sync.Map{}
linkExtractCache = sync.Map{}
threadLinksCache = sync.Map{}
)
设计思想:
sync.Map实现线程安全的缓存,避免频繁的重复计算const (
pluginName = "panta"
searchURLTemplate = "https://www.91panta.cn/search?keyword=%s"
threadURLTemplate = "https://www.91panta.cn/thread?topicId=%s"
defaultPriority = 2
defaultTimeout = 10
defaultConcurrency = 30
// ... 其他配置常量
)
设计思想:
type PantaPlugin struct {
client *http.Client
maxConcurrency int
currentConcurrency int
responseTimes []time.Duration
responseTimesMutex sync.Mutex
lastAdjustTime time.Time
}
设计思想:
func init() {
plugin.RegisterGlobalPlugin(NewPantaPlugin())
}
func NewPantaPlugin() *PantaPlugin {
// 创建优化的HTTP传输层
transport := &http.Transport{...}
// 创建HTTP客户端
client := &http.Client{...}
// 启动定期清理缓存的goroutine
go startCacheCleaner()
// 创建插件实例
plugin := &PantaPlugin{...}
// 启动自适应并发控制
go plugin.startConcurrencyAdjuster()
return plugin
}
设计思想:
func (p *PantaPlugin) Search(keyword string) ([]model.SearchResult, error) {
// 对关键词进行URL编码
encodedKeyword := url.QueryEscape(keyword)
// 构建搜索URL
searchURL := fmt.Sprintf(searchURLTemplate, encodedKeyword)
// 创建请求
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
// ... 设置请求头
// 使用带重试的请求方法发送HTTP请求
resp, err := p.doRequestWithRetry(req)
// ... 处理响应
// 解析搜索结果
return p.parseSearchResults(doc)
}
设计思想:
func (p *PantaPlugin) parseSearchResults(doc *goquery.Document) ([]model.SearchResult, error) {
// ... 初始化变量
// 创建信号量控制并发数
semaphore := make(chan struct{}, p.currentConcurrency)
// 创建结果通道和错误通道
resultChan := make(chan model.SearchResult, 100)
errorChan := make(chan error, 100)
// 预先收集所有需要处理的话题项
var topicItems []*goquery.Selection
// ... 收集话题项
// 批量处理所有话题项
for i, s := range topicItems {
wg.Add(1)
// 为每个话题创建一个goroutine
go func(index int, s *goquery.Selection) {
// ... 处理单个话题项
// 提取话题ID、标题、摘要、发布时间等
// 提取链接
// 将结果发送到结果通道
}(i, s)
}
// 等待所有goroutine完成
// 收集结果
// 调整并发数
return results, nil
}
设计思想:
func (p *PantaPlugin) extractLinksFromElement(s *goquery.Selection, yearFromTitle string) []model.Link {
// 创建缓存键
// 检查缓存
// 批量处理所有链接
// 提取链接类型和提取码
// 根据链接类型进行特殊处理
// 缓存结果
return links
}
设计思想:
func (p *PantaPlugin) fetchThreadLinks(topicID string) ([]model.Link, error) {
// 检查缓存
// 构建请求
// 发送请求并处理响应
// 解析HTML
// 提取链接和提取码
// 缓存结果
return links, nil
}
设计思想:
func extractTextLinks(text string, yearFromTitle string) []model.Link {
// 快速过滤
// 并发提取链接和提取码
// 智能关联算法
// 特殊处理不同类型的网盘链接
return links
}
设计思想:
func extractPassword(content string, url string) string {
// 缓存检查
// URL参数提取
// 关键词检查
// 正则匹配
// 缓存结果
return password
}
设计思想:
func determineLinkType(url string) string {
// 缓存检查
// 域名匹配
// 缓存结果
return linkType
}
设计思想:
func isNetDiskLink(url string) bool {
// 缓存检查
// 域名快速匹配
// 缓存结果
return isNetDisk
}
设计思想:
func (p *PantaPlugin) startConcurrencyAdjuster() {
ticker := time.NewTicker(concurrencyAdjustInterval * time.Second)
defer ticker.Stop()
for range ticker.C {
p.adjustConcurrency()
}
}
func (p *PantaPlugin) adjustConcurrency() {
// 计算平均响应时间
// 根据响应时间调整并发数
}
func (p *PantaPlugin) recordResponseTime(d time.Duration) {
// 记录响应时间
}
设计思想:
func (p *PantaPlugin) doRequestWithRetry(req *http.Request) (*http.Response, error) {
// 重试循环
// 指数退避算法
// 响应时间记录
return resp, err
}
设计思想:
func startCacheCleaner() {
ticker := time.NewTicker(1 * time.Hour)
defer ticker.Stop()
for range ticker.C {
// 清空所有缓存
}
}
设计思想:
// 为每个链接找到最合适的提取码
// 使用评分系统选择最佳匹配
设计思想:
// 使用正则表达式和域名列表识别不同类型的网盘链接
设计思想:
transport := &http.Transport{
MaxIdleConns: 200,
IdleConnTimeout: 120 * time.Second,
MaxIdleConnsPerHost: 50,
MaxConnsPerHost: 100,
DisableKeepAlives: false,
ForceAttemptHTTP2: true,
WriteBufferSize: 16 * 1024,
ReadBufferSize: 16 * 1024,
// ... 其他配置
}
设计思想:
// 使用信号量控制并发数
// 使用goroutine并行处理多个任务
// 使用通道安全地收集结果
设计思想:
// 多级缓存系统
// 定期清理机制
设计思想:
// 预编译正则表达式
// 减少回溯的正则模式
设计思想:
// 预先收集所有需要处理的项
// 批量处理减少重复操作
设计思想:
// 指数退避重试
// 错误类型判断
设计思想:
// 当无法获取详细信息时使用已有信息
// 当主要数据源失败时尝试备用方法
设计思想:
// 实现SearchPlugin接口
var _ plugin.SearchPlugin = (*PantaPlugin)(nil)
设计思想:
// 功能分解为独立函数
// 关注点分离
设计思想:
// 使用常量定义配置参数
// 支持动态调整部分参数
设计思想:
问题:提取码关联不准确 解决方案:使用评分系统考虑多种因素,提高关联准确性
问题:网络请求超时 解决方案:实现重试机制和超时控制
问题:内存使用过高 解决方案:定期清理缓存,控制并发数量
问题:CPU使用率过高 解决方案:优化正则表达式,减少不必要的计算
问题:某些网盘链接识别失败 解决方案:持续更新网盘链接模式,支持新的网盘类型