<h1 align="center" style="font-size: 3rem; color: #1772b4">Animag 2.0</h1>
---
## 项目概述
一个用于搜索动漫磁力链接与种子的Python库。它拥有强大的可扩展性, 支持通过插件系统从不同来源搜索动画资源,并能够处理磁力链接、文件大小转换等功能。
## 主要特性
- 支持多个资源站点的搜索功能
- 可扩展的插件系统
- 文件大小单位转换
- CSV导出功能
- 磁力链接处理
- 时间格式转换
- 错误处理机制
## 安装
Animag可以使用pip轻松地安装:
```commandline
pip install animag
```
## 使用示例
```python
# 导入搜索器类
from animag import Searcher
# 创建搜索器实例
searcher = Searcher(plugin_name='dmhy',
no_search_errors=True)
# 搜索动画
results = searcher.search("葬送的芙莉莲",
collected=True)
# 打印搜索结果
print(results)
"""
示例输出(2024年12月22日的结果):
Search completed successfully: 葬送的芙莉莲
[Anime(time='2024/10/20 12:23', title='[7³ACG\u200b] \u200b葬送的芙莉莲/Sousou no Frieren S01 | 01-28 [简繁字幕] BDrip 1080p AV1 OPUS 2.0\u200b\u200b\u200b', size='17.1GB', magnet='magnet:?xt=urn:btih:...
"""
# 转换所有结果的文件大小为GB
searcher.size_format_all('MB')
# 保存结果到CSV文件
searcher.save_csv("search_results.csv")
```
## 核心组件
### Anime类
`Anime`类用于表示单个动画资源的信息
#### 主要属性
- `time`: 发布时间
- `title`: 标题
- `size`: 文件大小
- `magnet`: 磁力链接
- `torrent`: 种子链接
#### 主要方法
- `size_format()`: 转换文件大小单位
- `set_timefmt()`: 转换时间格式
### Searcher类
`Searcher`类是搜索功能的核心实现
#### 主要功能
- 初始化搜索插件
- 执行搜索操作
- 处理搜索结果
- 导出数据
#### 主要方法
- `search()`: 搜索动画资源
- `size_format_all()`: 批量转换文件大小单位
- `save_csv()`: 将搜索结果保存为CSV文件
- `set_timefmt()`: 设置时间格式
## 错误处理
系统定义了多种错误类型:
- `PluginImportError`: 插件导入错误
- `SearchRequestError`: 搜索请求错误
- `SearchParseError`: 搜索结果解析错误
- `SizeFormatError`: 文件大小格式化错误
- `TimeFormatError`: 时间格式化错误
- `SaveCSVError`: CSV保存错误
## 配置选项
### 搜索器初始化选项
- `plugin_name`: 插件名称(默认:'dmhy')
- `parser`: 解析器选项
- `verify`: 验证选项
- `timefmt`: 时间格式
- `no_search_errors`: 是否忽略搜索错误
### 搜索选项
- `keyword`: 搜索关键词
- `collected`: 是否收集结果
- `proxies`: 代理设置
- `system_proxy`: 是否使用系统代理
## 自定义插件
Animag支持安装自己实现的搜索插件,插件类必须继承`BasePlugin`类,并实现`search()`方法。
### 示例插件
```python
# myplugin.py
# 文件名必须是小写的插件名称
from animag import BasePlugin, Anime, Searcher
from typing import List, Optional
class MyPlugin(BasePlugin):
abstract = False # 这一行必须设置,否则不会被识别为插件
def __init__(self,
parser: Optional[str] = None,
verify: Optional[bool] = None,
timefmt: Optional[str] = None):
# 插件初始化
pass
def search(self, keyword: str,
collected: Optional[bool] = None,
proxies: Optional[dict] = None,
system_proxy: Optional[bool] = None,
**extra_options) -> List[Anime] | None:
# 实现搜索逻辑
pass
```
### 安装插件
将自定义插件安装到animag/plugins目录后,在搜索器初始化时,指定插件名称为`myplugin`即可,如果没有安装至此目录,也可以手动将模块导入至命名空间。
```python
searcher = Searcher(plugin_name='myplugin')
```
## 命令行接口 (CLI)
项目附赠了一个CLI工具,使用 Rich 库实现美观的控制台输出,支持交互式选择。
### 命令行参数
```commandline
animag [-h] -s SEARCH [-p PLUGIN] [-c]
```
#### 必选参数
-s, --search: 搜索关键词
#### 可选参数
- `-h`, `--help`: 显示帮助信息
- `-p`, `--plugin`: 指定搜索插件(默认:'dmhy')
- `-c`, `--collected`: 启用季度全集搜索模式
### 使用示例
```commandline
# 基本搜索
animag -s "葬送的芙莉莲"
# 使用特定插件搜索
animag -s "葬送的芙莉莲" -p nyaa
# 搜索季度全集
animag -s "葬送的芙莉莲" -c
```
## 注意事项
1. 目前所有的插件都需要代理才能工作,确保正确配置代理设置
2. 时间格式必须符合Python的时间格式字符串规范
Raw data
{
"_id": null,
"home_page": "https://github.com/adogecheems/animag",
"name": "animag",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "anime magnet torrent scrape spider rss expandable plugin acgrip dmhy nyaa tokyotosho miobt kisssub comicat",
"author": "adogecheems",
"author_email": "master@mmoe.work",
"download_url": "https://files.pythonhosted.org/packages/76/8f/ea39b0ca6efc7ed498f035c3b8f5c1f3c11763493a1e31c6061b02db8b6f/animag-2.0.0.tar.gz",
"platform": null,
"description": "<h1 align=\"center\" style=\"font-size: 3rem; color: #1772b4\">Animag 2.0</h1>\n\n---\n\n## \u9879\u76ee\u6982\u8ff0\n\n\u4e00\u4e2a\u7528\u4e8e\u641c\u7d22\u52a8\u6f2b\u78c1\u529b\u94fe\u63a5\u4e0e\u79cd\u5b50\u7684Python\u5e93\u3002\u5b83\u62e5\u6709\u5f3a\u5927\u7684\u53ef\u6269\u5c55\u6027\uff0c \u652f\u6301\u901a\u8fc7\u63d2\u4ef6\u7cfb\u7edf\u4ece\u4e0d\u540c\u6765\u6e90\u641c\u7d22\u52a8\u753b\u8d44\u6e90\uff0c\u5e76\u80fd\u591f\u5904\u7406\u78c1\u529b\u94fe\u63a5\u3001\u6587\u4ef6\u5927\u5c0f\u8f6c\u6362\u7b49\u529f\u80fd\u3002\n\n## \u4e3b\u8981\u7279\u6027\n\n- \u652f\u6301\u591a\u4e2a\u8d44\u6e90\u7ad9\u70b9\u7684\u641c\u7d22\u529f\u80fd\n- \u53ef\u6269\u5c55\u7684\u63d2\u4ef6\u7cfb\u7edf\n- \u6587\u4ef6\u5927\u5c0f\u5355\u4f4d\u8f6c\u6362\n- CSV\u5bfc\u51fa\u529f\u80fd\n- \u78c1\u529b\u94fe\u63a5\u5904\u7406\n- \u65f6\u95f4\u683c\u5f0f\u8f6c\u6362\n- \u9519\u8bef\u5904\u7406\u673a\u5236\n\n## \u5b89\u88c5\n\nAnimag\u53ef\u4ee5\u4f7f\u7528pip\u8f7b\u677e\u5730\u5b89\u88c5\uff1a\n\n```commandline\npip install animag\n```\n\n## \u4f7f\u7528\u793a\u4f8b\n\n```python\n# \u5bfc\u5165\u641c\u7d22\u5668\u7c7b\nfrom animag import Searcher\n\n# \u521b\u5efa\u641c\u7d22\u5668\u5b9e\u4f8b\nsearcher = Searcher(plugin_name='dmhy',\n no_search_errors=True)\n\n# \u641c\u7d22\u52a8\u753b\nresults = searcher.search(\"\u846c\u9001\u7684\u8299\u8389\u83b2\",\n collected=True)\n\n# \u6253\u5370\u641c\u7d22\u7ed3\u679c\nprint(results)\n\n\"\"\"\n\u793a\u4f8b\u8f93\u51fa(2024\u5e7412\u670822\u65e5\u7684\u7ed3\u679c)\uff1a\n\nSearch completed successfully: \u846c\u9001\u7684\u8299\u8389\u83b2\n[Anime(time='2024/10/20 12:23', title='[7\u00b3ACG\\u200b] \\u200b\u846c\u9001\u7684\u8299\u8389\u83b2/Sousou no Frieren S01 | 01-28 [\u7b80\u7e41\u5b57\u5e55] BDrip 1080p AV1 OPUS 2.0\\u200b\\u200b\\u200b', size='17.1GB', magnet='magnet:?xt=urn:btih:...\n\n\"\"\"\n\n# \u8f6c\u6362\u6240\u6709\u7ed3\u679c\u7684\u6587\u4ef6\u5927\u5c0f\u4e3aGB\nsearcher.size_format_all('MB')\n\n# \u4fdd\u5b58\u7ed3\u679c\u5230CSV\u6587\u4ef6\nsearcher.save_csv(\"search_results.csv\")\n```\n\n## \u6838\u5fc3\u7ec4\u4ef6\n\n### Anime\u7c7b\n\n`Anime`\u7c7b\u7528\u4e8e\u8868\u793a\u5355\u4e2a\u52a8\u753b\u8d44\u6e90\u7684\u4fe1\u606f\n\n#### \u4e3b\u8981\u5c5e\u6027\n\n- `time`: \u53d1\u5e03\u65f6\u95f4\n- `title`: \u6807\u9898\n- `size`: \u6587\u4ef6\u5927\u5c0f\n- `magnet`: \u78c1\u529b\u94fe\u63a5\n- `torrent`: \u79cd\u5b50\u94fe\u63a5\n\n#### \u4e3b\u8981\u65b9\u6cd5\n\n- `size_format()`: \u8f6c\u6362\u6587\u4ef6\u5927\u5c0f\u5355\u4f4d\n- `set_timefmt()`: \u8f6c\u6362\u65f6\u95f4\u683c\u5f0f\n\n### Searcher\u7c7b\n\n`Searcher`\u7c7b\u662f\u641c\u7d22\u529f\u80fd\u7684\u6838\u5fc3\u5b9e\u73b0\n\n#### \u4e3b\u8981\u529f\u80fd\n\n- \u521d\u59cb\u5316\u641c\u7d22\u63d2\u4ef6\n- \u6267\u884c\u641c\u7d22\u64cd\u4f5c\n- \u5904\u7406\u641c\u7d22\u7ed3\u679c\n- \u5bfc\u51fa\u6570\u636e\n\n#### \u4e3b\u8981\u65b9\u6cd5\n\n- `search()`: \u641c\u7d22\u52a8\u753b\u8d44\u6e90\n- `size_format_all()`: \u6279\u91cf\u8f6c\u6362\u6587\u4ef6\u5927\u5c0f\u5355\u4f4d\n- `save_csv()`: \u5c06\u641c\u7d22\u7ed3\u679c\u4fdd\u5b58\u4e3aCSV\u6587\u4ef6\n- `set_timefmt()`: \u8bbe\u7f6e\u65f6\u95f4\u683c\u5f0f\n\n## \u9519\u8bef\u5904\u7406\n\n\u7cfb\u7edf\u5b9a\u4e49\u4e86\u591a\u79cd\u9519\u8bef\u7c7b\u578b\uff1a\n\n- `PluginImportError`: \u63d2\u4ef6\u5bfc\u5165\u9519\u8bef\n- `SearchRequestError`: \u641c\u7d22\u8bf7\u6c42\u9519\u8bef\n- `SearchParseError`: \u641c\u7d22\u7ed3\u679c\u89e3\u6790\u9519\u8bef\n- `SizeFormatError`: \u6587\u4ef6\u5927\u5c0f\u683c\u5f0f\u5316\u9519\u8bef\n- `TimeFormatError`: \u65f6\u95f4\u683c\u5f0f\u5316\u9519\u8bef\n- `SaveCSVError`: CSV\u4fdd\u5b58\u9519\u8bef\n\n## \u914d\u7f6e\u9009\u9879\n\n### \u641c\u7d22\u5668\u521d\u59cb\u5316\u9009\u9879\n\n- `plugin_name`: \u63d2\u4ef6\u540d\u79f0\uff08\u9ed8\u8ba4\uff1a'dmhy'\uff09\n- `parser`: \u89e3\u6790\u5668\u9009\u9879\n- `verify`: \u9a8c\u8bc1\u9009\u9879\n- `timefmt`: \u65f6\u95f4\u683c\u5f0f\n- `no_search_errors`: \u662f\u5426\u5ffd\u7565\u641c\u7d22\u9519\u8bef\n\n### \u641c\u7d22\u9009\u9879\n\n- `keyword`: \u641c\u7d22\u5173\u952e\u8bcd\n- `collected`: \u662f\u5426\u6536\u96c6\u7ed3\u679c\n- `proxies`: \u4ee3\u7406\u8bbe\u7f6e\n- `system_proxy`: \u662f\u5426\u4f7f\u7528\u7cfb\u7edf\u4ee3\u7406\n\n## \u81ea\u5b9a\u4e49\u63d2\u4ef6\n\nAnimag\u652f\u6301\u5b89\u88c5\u81ea\u5df1\u5b9e\u73b0\u7684\u641c\u7d22\u63d2\u4ef6\uff0c\u63d2\u4ef6\u7c7b\u5fc5\u987b\u7ee7\u627f`BasePlugin`\u7c7b\uff0c\u5e76\u5b9e\u73b0`search()`\u65b9\u6cd5\u3002\n\n### \u793a\u4f8b\u63d2\u4ef6\n\n```python\n# myplugin.py\n# \u6587\u4ef6\u540d\u5fc5\u987b\u662f\u5c0f\u5199\u7684\u63d2\u4ef6\u540d\u79f0\n\nfrom animag import BasePlugin, Anime, Searcher\nfrom typing import List, Optional\n\n\nclass MyPlugin(BasePlugin):\n abstract = False # \u8fd9\u4e00\u884c\u5fc5\u987b\u8bbe\u7f6e\uff0c\u5426\u5219\u4e0d\u4f1a\u88ab\u8bc6\u522b\u4e3a\u63d2\u4ef6\n\n def __init__(self,\n parser: Optional[str] = None,\n verify: Optional[bool] = None,\n timefmt: Optional[str] = None):\n # \u63d2\u4ef6\u521d\u59cb\u5316\n pass\n\n def search(self, keyword: str,\n collected: Optional[bool] = None,\n proxies: Optional[dict] = None,\n system_proxy: Optional[bool] = None,\n **extra_options) -> List[Anime] | None:\n # \u5b9e\u73b0\u641c\u7d22\u903b\u8f91\n pass\n```\n\n### \u5b89\u88c5\u63d2\u4ef6\n\n\u5c06\u81ea\u5b9a\u4e49\u63d2\u4ef6\u5b89\u88c5\u5230animag/plugins\u76ee\u5f55\u540e\uff0c\u5728\u641c\u7d22\u5668\u521d\u59cb\u5316\u65f6\uff0c\u6307\u5b9a\u63d2\u4ef6\u540d\u79f0\u4e3a`myplugin`\u5373\u53ef\uff0c\u5982\u679c\u6ca1\u6709\u5b89\u88c5\u81f3\u6b64\u76ee\u5f55\uff0c\u4e5f\u53ef\u4ee5\u624b\u52a8\u5c06\u6a21\u5757\u5bfc\u5165\u81f3\u547d\u540d\u7a7a\u95f4\u3002\n\n```python\nsearcher = Searcher(plugin_name='myplugin')\n```\n\n## \u547d\u4ee4\u884c\u63a5\u53e3 (CLI)\n\n\u9879\u76ee\u9644\u8d60\u4e86\u4e00\u4e2aCLI\u5de5\u5177\uff0c\u4f7f\u7528 Rich \u5e93\u5b9e\u73b0\u7f8e\u89c2\u7684\u63a7\u5236\u53f0\u8f93\u51fa\uff0c\u652f\u6301\u4ea4\u4e92\u5f0f\u9009\u62e9\u3002\n\n### \u547d\u4ee4\u884c\u53c2\u6570\n\n```commandline\nanimag [-h] -s SEARCH [-p PLUGIN] [-c]\n```\n\n#### \u5fc5\u9009\u53c2\u6570\n\n-s, --search: \u641c\u7d22\u5173\u952e\u8bcd\n\n#### \u53ef\u9009\u53c2\u6570\n\n- `-h`, `--help`: \u663e\u793a\u5e2e\u52a9\u4fe1\u606f\n- `-p`, `--plugin`: \u6307\u5b9a\u641c\u7d22\u63d2\u4ef6\uff08\u9ed8\u8ba4\uff1a'dmhy'\uff09\n- `-c`, `--collected`: \u542f\u7528\u5b63\u5ea6\u5168\u96c6\u641c\u7d22\u6a21\u5f0f\n\n### \u4f7f\u7528\u793a\u4f8b\n\n```commandline\n\n# \u57fa\u672c\u641c\u7d22\nanimag -s \"\u846c\u9001\u7684\u8299\u8389\u83b2\"\n\n# \u4f7f\u7528\u7279\u5b9a\u63d2\u4ef6\u641c\u7d22\nanimag -s \"\u846c\u9001\u7684\u8299\u8389\u83b2\" -p nyaa\n\n# \u641c\u7d22\u5b63\u5ea6\u5168\u96c6\nanimag -s \"\u846c\u9001\u7684\u8299\u8389\u83b2\" -c\n```\n\n## \u6ce8\u610f\u4e8b\u9879\n\n1. \u76ee\u524d\u6240\u6709\u7684\u63d2\u4ef6\u90fd\u9700\u8981\u4ee3\u7406\u624d\u80fd\u5de5\u4f5c\uff0c\u786e\u4fdd\u6b63\u786e\u914d\u7f6e\u4ee3\u7406\u8bbe\u7f6e\n2. \u65f6\u95f4\u683c\u5f0f\u5fc5\u987b\u7b26\u5408Python\u7684\u65f6\u95f4\u683c\u5f0f\u5b57\u7b26\u4e32\u89c4\u8303\n",
"bugtrack_url": null,
"license": "AGPLv3",
"summary": "Anime magnet search library with strong expandability",
"version": "2.0.0",
"project_urls": {
"Homepage": "https://github.com/adogecheems/animag"
},
"split_keywords": [
"anime",
"magnet",
"torrent",
"scrape",
"spider",
"rss",
"expandable",
"plugin",
"acgrip",
"dmhy",
"nyaa",
"tokyotosho",
"miobt",
"kisssub",
"comicat"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0cf003b7e9e89a1d191c044ab2736ac890656ce3e68d899324dcebd4fb899275",
"md5": "87c148bcf71de7f9f0d00b1f6dc83105",
"sha256": "313fe02542c06f17f7426b94723aef94bd0a536bdcda5d1bfb7b4b0a84b92503"
},
"downloads": -1,
"filename": "animag-2.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "87c148bcf71de7f9f0d00b1f6dc83105",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 19898,
"upload_time": "2024-12-22T09:01:11",
"upload_time_iso_8601": "2024-12-22T09:01:11.811426Z",
"url": "https://files.pythonhosted.org/packages/0c/f0/03b7e9e89a1d191c044ab2736ac890656ce3e68d899324dcebd4fb899275/animag-2.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "768fea39b0ca6efc7ed498f035c3b8f5c1f3c11763493a1e31c6061b02db8b6f",
"md5": "36b4877729b1ce37556aa80ea0662c1e",
"sha256": "3307dea9c60941172d18f887082aafa715d0921333f0a95966dede133f759e0c"
},
"downloads": -1,
"filename": "animag-2.0.0.tar.gz",
"has_sig": false,
"md5_digest": "36b4877729b1ce37556aa80ea0662c1e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 16713,
"upload_time": "2024-12-22T09:01:14",
"upload_time_iso_8601": "2024-12-22T09:01:14.474366Z",
"url": "https://files.pythonhosted.org/packages/76/8f/ea39b0ca6efc7ed498f035c3b8f5c1f3c11763493a1e31c6061b02db8b6f/animag-2.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-22 09:01:14",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "adogecheems",
"github_project": "animag",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "requests",
"specs": []
},
{
"name": "bs4",
"specs": []
},
{
"name": "lxml",
"specs": []
},
{
"name": "rich",
"specs": []
}
],
"lcname": "animag"
}