From 742de4d9e824e2ec6b4621eb1641fc5b7a6fac2b Mon Sep 17 00:00:00 2001 From: Harold <8866033@gmail.com> Date: Sat, 18 Apr 2026 11:58:08 +0800 Subject: [PATCH] feat: scaffold dbku spider parsing --- py/tests/test_dbku.py | 43 ++++++++++++++++++++ py/独播库.py | 91 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 py/tests/test_dbku.py create mode 100644 py/独播库.py diff --git a/py/tests/test_dbku.py b/py/tests/test_dbku.py new file mode 100644 index 0000000..7512f8b --- /dev/null +++ b/py/tests/test_dbku.py @@ -0,0 +1,43 @@ +import unittest +from importlib.machinery import SourceFileLoader +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +MODULE = SourceFileLoader("dbku_spider", str(ROOT / "独播库.py")).load_module() +Spider = MODULE.Spider + + +class TestDBKUSpider(unittest.TestCase): + def setUp(self): + self.spider = Spider() + self.spider.init() + + def test_home_content_exposes_expected_categories(self): + content = self.spider.homeContent(False) + class_ids = [item["type_id"] for item in content["class"]] + self.assertEqual(class_ids, ["index", "movie", "variety", "anime", "hk", "luju"]) + + def test_parse_list_cards_extracts_detail_url_title_cover_and_description(self): + html = """ +
+ + 更新至10集 +
+ """ + cards = self.spider._parse_list_cards(html) + self.assertEqual( + cards, + [ + { + "vod_id": "https://www.dbku.tv/voddetail/123.html", + "vod_name": "示例影片", + "vod_pic": "https://img.example/dbku.jpg", + "vod_remarks": "更新至10集", + } + ], + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/py/独播库.py b/py/独播库.py new file mode 100644 index 0000000..5223e36 --- /dev/null +++ b/py/独播库.py @@ -0,0 +1,91 @@ +# coding=utf-8 +import sys + +from base.spider import Spider as BaseSpider + +sys.path.append("..") + + +class Spider(BaseSpider): + def __init__(self): + self.name = "独播库" + self.host = "https://www.dbku.tv" + self.headers = { + "User-Agent": ( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/124.0.0.0 Safari/537.36" + ) + } + self.categories = [ + {"type_name": "连续剧", "type_id": "index"}, + {"type_name": "电影", "type_id": "movie"}, + {"type_name": "综艺", "type_id": "variety"}, + {"type_name": "动漫", "type_id": "anime"}, + {"type_name": "港剧", "type_id": "hk"}, + {"type_name": "陆剧", "type_id": "luju"}, + ] + + def init(self, extend=""): + return None + + def getName(self): + return self.name + + def homeContent(self, filter): + return {"class": self.categories} + + def homeVideoContent(self): + return {"list": []} + + def _build_url(self, href): + raw = str(href or "").strip() + if not raw: + return "" + if raw.startswith(("http://", "https://")): + return raw + if raw.startswith("//"): + return "https:" + raw + if raw.startswith("/"): + return self.host + raw + return self.host + "/" + raw + + def _parse_list_cards(self, html): + root = self.html(html) + results = [] + if root is None: + return results + + cards = root.xpath("//*[contains(@class,'myui-vodlist__box')]") + seen = set() + for card in cards: + href = "" + title = "" + pic = "" + for anchor in card.xpath(".//a[@href]"): + raw_href = (anchor.xpath("./@href") or [""])[0].strip() + if "/voddetail/" in raw_href: + href = self._build_url(raw_href) + title = ( + (anchor.xpath("./@title") or [""])[0].strip() + or "".join(anchor.xpath(".//text()")).strip() + ) + pic = ( + (anchor.xpath("./@data-original") or [""])[0].strip() + or (anchor.xpath("./@src") or [""])[0].strip() + ) + break + if not href or href in seen or not title: + continue + + remarks = "".join(card.xpath(".//*[contains(@class,'pic-text')][1]//text()")).strip() + seen.add(href) + results.append( + { + "vod_id": href, + "vod_name": title, + "vod_pic": self._build_url(pic), + "vod_remarks": remarks, + } + ) + return results