179 lines
6.4 KiB
Python
179 lines
6.4 KiB
Python
#coding=utf-8
|
||
#!/usr/bin/python
|
||
import os
|
||
import sys
|
||
import json
|
||
import threading
|
||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||
from socketserver import ThreadingMixIn
|
||
from importlib.machinery import SourceFileLoader
|
||
from urllib.parse import urlparse, parse_qs
|
||
import types
|
||
import base64
|
||
|
||
# ============================================================
|
||
# 禁止生成 __pycache__
|
||
# ============================================================
|
||
sys.dont_write_bytecode = True
|
||
|
||
# ============================================================
|
||
# 自动兼容旧版 Spider 导入
|
||
# ============================================================
|
||
if 'base' not in sys.modules:
|
||
base_module = types.ModuleType('base')
|
||
sys.modules['base'] = base_module
|
||
|
||
if 'base.spider' not in sys.modules:
|
||
import spider # spider.py 与 server.py 同目录
|
||
sys.modules['base.spider'] = spider
|
||
|
||
# ============================================================
|
||
# 强制标准输出为 UTF-8(防止中文打印报错)
|
||
# ============================================================
|
||
try:
|
||
sys.stdout.reconfigure(encoding='utf-8')
|
||
except Exception:
|
||
pass
|
||
|
||
# ============================================================
|
||
# Spider 动态加载
|
||
# ============================================================
|
||
_spider_module_cache = {} # 缓存模块对象
|
||
|
||
def load_spider(spider_name):
|
||
# 1️⃣ 检查模块缓存
|
||
if spider_name in _spider_module_cache:
|
||
module = _spider_module_cache[spider_name]
|
||
else:
|
||
# 2️⃣ 指定 sy 子目录
|
||
server_dir = os.path.dirname(os.path.abspath(__file__))
|
||
path = os.path.join(server_dir, "sy", f"{spider_name}.py")
|
||
if not os.path.exists(path):
|
||
raise FileNotFoundError(f"Spider file not found: {path}")
|
||
|
||
module = SourceFileLoader(spider_name, path).load_module()
|
||
_spider_module_cache[spider_name] = module
|
||
|
||
# 3️⃣ 每次生成新的 Spider 实例
|
||
spider_instance = module.Spider()
|
||
if hasattr(spider_instance, 'init'):
|
||
spider_instance.init(extend="") # 实时初始化
|
||
|
||
print(f"[载入] 已初始化 Spider: {spider_name}")
|
||
return spider_instance
|
||
|
||
# ============================================================
|
||
# 多线程 HTTPServer
|
||
# ============================================================
|
||
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||
daemon_threads = True
|
||
timeout = 10
|
||
|
||
# ============================================================
|
||
# HTTP 请求处理
|
||
# ============================================================
|
||
class SpiderHandler(BaseHTTPRequestHandler):
|
||
|
||
def do_GET(self):
|
||
self.connection.settimeout(10)
|
||
query = urlparse(self.path).query
|
||
params = parse_qs(query)
|
||
response = {}
|
||
|
||
sp = params.get('sp', [None])[0]
|
||
t = params.get('t', [None])[0]
|
||
pg = params.get('pg', ['1'])[0]
|
||
ids = params.get('ids', [None])[0]
|
||
play = params.get('play', [None])[0]
|
||
wd = params.get('wd', [None])[0]
|
||
filter_param = params.get('filter', [None])[0]
|
||
|
||
# 兼容 ext 参数(Base64 编码 JSON)
|
||
ext = params.get('ext', [None])[0]
|
||
ext_obj = {}
|
||
if ext:
|
||
try:
|
||
ext_json = base64.b64decode(ext).decode('utf-8')
|
||
ext_obj = json.loads(ext_json) if ext_json.strip() else {}
|
||
except Exception:
|
||
ext_obj = {}
|
||
|
||
if not sp:
|
||
self.send_error(400, "Missing 'sp' parameter (e.g. ?sp=Iktv)")
|
||
return
|
||
|
||
try:
|
||
spider = load_spider(sp)
|
||
|
||
# ===========================
|
||
# 根据参数判断访问类型
|
||
# ===========================
|
||
if (not t and not ids and not play and not wd) or (filter_param and not t and not ids and not play and not wd):
|
||
response = spider.homeContent(filter=filter_param)
|
||
access_type = "home"
|
||
elif ids:
|
||
response = spider.detailContent([ids])
|
||
access_type = "detail"
|
||
elif play:
|
||
response = spider.playerContent("", play, None)
|
||
access_type = "play"
|
||
elif wd:
|
||
response = spider.searchContent(key=wd, quick=False)
|
||
access_type = "search"
|
||
elif t:
|
||
response = spider.categoryContent(t, pg, None, ext_obj)
|
||
access_type = "category"
|
||
else:
|
||
response = spider.homeContent(filter=filter_param)
|
||
access_type = "home"
|
||
|
||
# ===========================
|
||
# 返回 JSON
|
||
# ===========================
|
||
self.send_response(200)
|
||
self.send_header("Content-type", "application/json; charset=utf-8")
|
||
self.end_headers()
|
||
try:
|
||
self.wfile.write(json.dumps(response, ensure_ascii=False).encode('utf-8'))
|
||
except BrokenPipeError:
|
||
print("[警告] 客户端已断开连接(BrokenPipeError)")
|
||
return
|
||
|
||
# 日志
|
||
try:
|
||
log_line = f"[访问] Spider={sp}, 类型={access_type}, params={params}"
|
||
print(log_line.encode('utf-8', 'ignore').decode('utf-8'))
|
||
except Exception as log_error:
|
||
print("[日志错误]", log_error)
|
||
|
||
except BrokenPipeError:
|
||
print("[警告] 客户端已断开连接(BrokenPipeError)")
|
||
except Exception as e:
|
||
self.send_response(500)
|
||
self.end_headers()
|
||
try:
|
||
self.wfile.write(str(e).encode('utf-8'))
|
||
except Exception:
|
||
pass
|
||
print(f"[错误] {e}")
|
||
|
||
# ============================================================
|
||
# 启动服务
|
||
# ============================================================
|
||
def run_server(host="0.0.0.0", port=8080):
|
||
try:
|
||
server = ThreadingHTTPServer((host, port), SpiderHandler)
|
||
print(f"[提示] 动态 Spider 服务已启动: http://{host}:{port}/?sp=YourSpider")
|
||
server.serve_forever()
|
||
except Exception as e:
|
||
print(f"[错误] 服务启动失败: {e}")
|
||
|
||
# ============================================================
|
||
# 命令行入口
|
||
# ============================================================
|
||
if __name__ == "__main__":
|
||
import argparse
|
||
parser = argparse.ArgumentParser()
|
||
parser.add_argument("--port", type=int, default=8080, help="端口号")
|
||
args = parser.parse_args()
|
||
run_server(port=args.port) |