From 958ec914fc0fd5abbfabc92dc99b1f112567158d Mon Sep 17 00:00:00 2001 From: Harold <8866033@gmail.com> Date: Sun, 19 Apr 2026 18:24:41 +0800 Subject: [PATCH] feat: add dida list and search flows --- py/tests/test_滴答影视.py | 55 ++++++++++++++++++++++++++++++++ py/滴答影视.py | 67 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/py/tests/test_滴答影视.py b/py/tests/test_滴答影视.py index f532268..cedfae9 100644 --- a/py/tests/test_滴答影视.py +++ b/py/tests/test_滴答影视.py @@ -1,6 +1,7 @@ import unittest from importlib.machinery import SourceFileLoader from pathlib import Path +from unittest.mock import patch ROOT = Path(__file__).resolve().parents[1] @@ -40,6 +41,60 @@ class TestDidaSpider(unittest.TestCase): url = self.spider._build_category_url("2", "1", {}) self.assertEqual(url, "https://www.didahd.pro/show/2--time------1---") + def test_parse_cards_extracts_expected_fields(self): + html = """ +
+ """ + cards = self.spider._parse_cards(html) + self.assertEqual( + cards, + [ + { + "vod_id": "https://www.didahd.pro/detail/888.html", + "vod_name": "示例影片", + "vod_pic": "https://www.didahd.pro/cover.jpg", + "vod_remarks": "HD", + } + ], + ) + + @patch.object(Spider, "_request_html") + def test_category_content_uses_built_url_and_returns_page_result(self, mock_request_html): + mock_request_html.return_value = """ + + """ + result = self.spider.categoryContent("1", "2", False, {"area": "香港", "sort": "score"}) + self.assertEqual(mock_request_html.call_args.args[0], "https://www.didahd.pro/show/1-香港-score------2---") + self.assertEqual(result["page"], 2) + self.assertEqual(result["pagecount"], 3) + self.assertEqual(result["limit"], 12) + self.assertEqual(result["list"][0]["vod_name"], "分类影片") + + @patch.object(Spider, "_request_html") + def test_search_content_uses_search_url_and_parses_cards(self, mock_request_html): + mock_request_html.return_value = """ + + """ + result = self.spider.searchContent("繁花", False, "1") + self.assertEqual( + mock_request_html.call_args.args[0], + "https://www.didahd.pro/search/-------------.html?wd=%E7%B9%81%E8%8A%B1", + ) + self.assertEqual(result["list"][0]["vod_id"], "https://www.didahd.pro/detail/321.html") + self.assertEqual(result["pagecount"], 2) + if __name__ == "__main__": unittest.main() diff --git a/py/滴答影视.py b/py/滴答影视.py index 09c5150..1802148 100644 --- a/py/滴答影视.py +++ b/py/滴答影视.py @@ -1,6 +1,8 @@ # coding=utf-8 import json +import re import sys +from urllib.parse import quote from base.spider import Spider as BaseSpider @@ -112,3 +114,68 @@ class Spider(BaseSpider): f"{values.get('year', '')}" ) return self._build_url(path) + + def _request_html(self, path_or_url, referer=None): + target = path_or_url if str(path_or_url).startswith("http") else self._build_url(path_or_url) + headers = dict(self.headers) + headers["Referer"] = referer or self.headers["Referer"] + response = self.fetch(target, headers=headers, timeout=10) + if response.status_code != 200: + return "" + return response.text or "" + + def _clean_text(self, text): + return re.sub(r"\s+", " ", str(text or "").replace("\xa0", " ")).strip() + + def _parse_cards(self, html): + root = self.html(html) + if root is None: + return [] + items = [] + seen = set() + for card in root.xpath("//*[contains(@class,'myui-vodlist__box')]"): + href = ((card.xpath(".//*[contains(@class,'title')]//a[@href][1]/@href") or [""])[0]).strip() + title = ( + ((card.xpath(".//*[contains(@class,'title')]//a[@title][1]/@title") or [""])[0]).strip() + or self._clean_text("".join(card.xpath(".//*[contains(@class,'title')]//a[1]//text()"))) + ) + pic = ( + ((card.xpath(".//*[contains(@class,'lazyload')][1]/@data-original") or [""])[0]).strip() + or ((card.xpath(".//*[contains(@class,'lazyload')][1]/@src") or [""])[0]).strip() + or ((card.xpath(".//img[1]/@data-original") or [""])[0]).strip() + or ((card.xpath(".//img[1]/@src") or [""])[0]).strip() + ) + remarks = self._clean_text("".join(card.xpath(".//*[contains(@class,'pic-text')][1]//text()"))) + vod_id = self._build_url(href) + if not vod_id or not title or vod_id in seen: + continue + seen.add(vod_id) + items.append( + { + "vod_id": vod_id, + "vod_name": title, + "vod_pic": self._build_url(pic), + "vod_remarks": remarks, + } + ) + return items + + def categoryContent(self, tid, pg, filter, extend): + page = int(pg) + items = self._parse_cards(self._request_html(self._build_category_url(tid, pg, extend))) + return { + "list": items, + "page": page, + "pagecount": page + 1 if items else page, + "limit": 12, + "total": page * 12 + len(items), + } + + def searchContent(self, key, quick, pg="1"): + page = int(pg) + keyword = self._stringify(key).strip() + if not keyword: + return {"page": page, "pagecount": 0, "total": 0, "list": []} + url = f"{self.host}/search/-------------.html?wd={quote(keyword)}" + items = self._parse_cards(self._request_html(url)) + return {"page": page, "pagecount": page + 1 if items else page, "total": len(items), "list": items}