玩偶聚合
This commit is contained in:
+61
-6
@@ -33,7 +33,7 @@ class TestErXiaoSpider(unittest.TestCase):
|
||||
def test_build_url_and_detect_pan_type(self):
|
||||
self.assertEqual(
|
||||
self.spider._build_url("/index.php/vod/detail/id/1.html"),
|
||||
"http://2xiaopan.fun/index.php/vod/detail/id/1.html",
|
||||
f"{self.spider.host}/index.php/vod/detail/id/1.html",
|
||||
)
|
||||
self.assertEqual(self.spider._detect_pan_type("https://pan.baidu.com/s/demo"), ("baidu", "百度资源"))
|
||||
self.assertEqual(self.spider._detect_pan_type("https://pan.quark.cn/s/demo"), ("quark", "夸克资源"))
|
||||
@@ -58,13 +58,55 @@ class TestErXiaoSpider(unittest.TestCase):
|
||||
{
|
||||
"vod_id": "/index.php/vod/detail/id/123.html",
|
||||
"vod_name": "示例影片",
|
||||
"vod_pic": "http://2xiaopan.fun/poster.jpg",
|
||||
"vod_pic": f"{self.spider.host}/poster.jpg",
|
||||
"vod_remarks": "HD",
|
||||
"vod_year": "2025",
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
def test_parse_cards_ignores_module_items_wrapper_and_keeps_each_card_separate(self):
|
||||
html = """
|
||||
<div id="main">
|
||||
<div class="module-items">
|
||||
<div class="module-item">
|
||||
<div class="module-item-pic">
|
||||
<a href="/index.php/vod/detail/id/111.html"></a>
|
||||
<img data-src="/poster-1.jpg" alt="影片一" />
|
||||
</div>
|
||||
<div class="module-item-text">HD</div>
|
||||
</div>
|
||||
<div class="module-item">
|
||||
<div class="module-item-pic">
|
||||
<a href="/index.php/vod/detail/id/222.html"></a>
|
||||
<img data-src="/poster-2.jpg" alt="影片二" />
|
||||
</div>
|
||||
<div class="module-item-text">更新至2集</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
cards = self.spider._parse_cards(html)
|
||||
self.assertEqual(
|
||||
cards,
|
||||
[
|
||||
{
|
||||
"vod_id": "/index.php/vod/detail/id/111.html",
|
||||
"vod_name": "影片一",
|
||||
"vod_pic": f"{self.spider.host}/poster-1.jpg",
|
||||
"vod_remarks": "HD",
|
||||
"vod_year": "",
|
||||
},
|
||||
{
|
||||
"vod_id": "/index.php/vod/detail/id/222.html",
|
||||
"vod_name": "影片二",
|
||||
"vod_pic": f"{self.spider.host}/poster-2.jpg",
|
||||
"vod_remarks": "更新至2集",
|
||||
"vod_year": "",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
@patch.object(Spider, "_request_html")
|
||||
def test_category_content_builds_reference_url_and_returns_page_payload(self, mock_request_html):
|
||||
mock_request_html.return_value = """
|
||||
@@ -82,7 +124,7 @@ class TestErXiaoSpider(unittest.TestCase):
|
||||
result = self.spider.categoryContent("2", "3", False, {})
|
||||
self.assertEqual(
|
||||
mock_request_html.call_args.args[0],
|
||||
"http://2xiaopan.fun/index.php/vod/show/id/2/page/3.html",
|
||||
f"{self.spider.host}/index.php/vod/show/id/2/page/3.html",
|
||||
)
|
||||
self.assertEqual(result["page"], 3)
|
||||
self.assertEqual(result["limit"], 1)
|
||||
@@ -102,14 +144,14 @@ class TestErXiaoSpider(unittest.TestCase):
|
||||
result = self.spider.searchContent("繁花", False, "2")
|
||||
self.assertEqual(
|
||||
mock_request_html.call_args.args[0],
|
||||
"http://2xiaopan.fun/index.php/vod/search/page/2/wd/%E7%B9%81%E8%8A%B1.html",
|
||||
f"{self.spider.host}/index.php/vod/search/page/2/wd/%E7%B9%81%E8%8A%B1.html",
|
||||
)
|
||||
self.assertEqual(
|
||||
result["list"][0],
|
||||
{
|
||||
"vod_id": "/index.php/vod/detail/id/789.html",
|
||||
"vod_name": "搜索影片",
|
||||
"vod_pic": "http://2xiaopan.fun/search.jpg",
|
||||
"vod_pic": f"{self.spider.host}/search.jpg",
|
||||
"vod_remarks": "抢先版",
|
||||
},
|
||||
)
|
||||
@@ -149,13 +191,26 @@ class TestErXiaoSpider(unittest.TestCase):
|
||||
"""
|
||||
detail = self.spider._parse_detail_page("/index.php/vod/detail/id/123.html", html)
|
||||
self.assertEqual(detail["vod_name"], "示例剧")
|
||||
self.assertEqual(detail["vod_pic"], "http://2xiaopan.fun/poster.jpg")
|
||||
self.assertEqual(detail["vod_pic"], f"{self.spider.host}/poster.jpg")
|
||||
self.assertEqual(detail["vod_year"], "2024")
|
||||
self.assertEqual(detail["vod_director"], "导演甲")
|
||||
self.assertEqual(detail["vod_actor"], "演员甲,演员乙")
|
||||
self.assertEqual(detail["vod_content"], "一段剧情简介")
|
||||
self.assertEqual(detail["pan_urls"], ["https://pan.quark.cn/s/q1", "https://pan.baidu.com/s/b1"])
|
||||
|
||||
def test_parse_detail_page_uses_only_first_mobile_play_poster(self):
|
||||
html = """
|
||||
<div class="page-title">示例剧</div>
|
||||
<div class="mobile-play"><img class="lazyload" data-src="/poster-main.jpg" /></div>
|
||||
<div class="mobile-play"><img class="lazyload" data-src="https://img.example.com/side.webp" /></div>
|
||||
<div class="mobile-play"><img class="lazyload" data-src="https://img.example.com/recommend.jpg" /></div>
|
||||
<div class="module-row-info">
|
||||
<p>https://pan.baidu.com/s/b1</p>
|
||||
</div>
|
||||
"""
|
||||
detail = self.spider._parse_detail_page("/index.php/vod/detail/id/123.html", html)
|
||||
self.assertEqual(detail["vod_pic"], f"{self.spider.host}/poster-main.jpg")
|
||||
|
||||
@patch.object(Spider, "_request_html")
|
||||
def test_detail_content_builds_pan_play_fields(self, mock_request_html):
|
||||
mock_request_html.return_value = """
|
||||
|
||||
+157
-39
@@ -18,15 +18,23 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
self.spider = Spider()
|
||||
self.spider.init()
|
||||
|
||||
def test_home_content_exposes_site_classes_and_category_filter(self):
|
||||
def test_home_content_exposes_recommend_and_site_classes_in_priority_order(self):
|
||||
content = self.spider.homeContent(False)
|
||||
self.assertEqual(
|
||||
[item["type_id"] for item in content["class"][:3]],
|
||||
["site_wanou", "site_zhizhen", "site_shandian"],
|
||||
[item["type_id"] for item in content["class"][:6]],
|
||||
[
|
||||
"site_recommend",
|
||||
"site_wanou",
|
||||
"site_muou",
|
||||
"site_labi",
|
||||
"site_zhizhen",
|
||||
"site_erxiao",
|
||||
],
|
||||
)
|
||||
self.assertEqual(content["class"][0]["type_name"], "玩偶")
|
||||
self.assertEqual(content["class"][0]["type_name"], "推荐")
|
||||
self.assertEqual(content["filters"]["site_wanou"][0]["key"], "categoryId")
|
||||
self.assertEqual(content["filters"]["site_wanou"][0]["value"][1], {"n": "电影", "v": "1"})
|
||||
self.assertEqual(content["filters"]["site_wanou"][0]["value"][1], {"n": "臻彩", "v": "44"})
|
||||
self.assertEqual(content["filters"]["site_recommend"][0]["value"][0], {"n": "全部", "v": "all"})
|
||||
|
||||
def test_home_content_exposes_zhizhen_site_and_categories(self):
|
||||
content = self.spider.homeContent(False)
|
||||
@@ -35,40 +43,58 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
content["filters"]["site_zhizhen"][0]["value"][1:],
|
||||
[
|
||||
{"n": "臻彩", "v": "26"},
|
||||
{"n": "电影", "v": "1"},
|
||||
{"n": "剧集", "v": "2"},
|
||||
{"n": "电视剧", "v": "2"},
|
||||
{"n": "动漫", "v": "3"},
|
||||
{"n": "综艺", "v": "4"},
|
||||
{"n": "短剧", "v": "5"},
|
||||
{"n": "老剧", "v": "24"},
|
||||
{"n": "严选", "v": "26"},
|
||||
],
|
||||
)
|
||||
|
||||
def test_home_content_exposes_shandian_site_and_categories(self):
|
||||
def test_home_content_exposes_muou_site_and_categories(self):
|
||||
content = self.spider.homeContent(False)
|
||||
type_ids = [item["type_id"] for item in content["class"]]
|
||||
self.assertIn("site_shandian", type_ids)
|
||||
self.assertIn("site_muou", type_ids)
|
||||
self.assertEqual(
|
||||
content["filters"]["site_shandian"][0]["value"][1:],
|
||||
content["filters"]["site_muou"][0]["value"][1:],
|
||||
[
|
||||
{"n": "臻选", "v": "25"},
|
||||
{"n": "电影", "v": "1"},
|
||||
{"n": "剧集", "v": "2"},
|
||||
{"n": "电视剧", "v": "2"},
|
||||
{"n": "动漫", "v": "3"},
|
||||
{"n": "纪录片", "v": "4"},
|
||||
{"n": "综艺", "v": "29"},
|
||||
{"n": "原盘", "v": "30"},
|
||||
],
|
||||
)
|
||||
|
||||
def test_home_content_exposes_kuaiying_and_ouge_site_categories(self):
|
||||
content = self.spider.homeContent(False)
|
||||
type_ids = [item["type_id"] for item in content["class"]]
|
||||
self.assertIn("site_kuaiying", type_ids)
|
||||
self.assertIn("site_ouge", type_ids)
|
||||
self.assertEqual(
|
||||
content["filters"]["site_kuaiying"][0]["value"][1:],
|
||||
[
|
||||
{"n": "臻彩", "v": "5"},
|
||||
{"n": "电影", "v": "1"},
|
||||
{"n": "电视剧", "v": "2"},
|
||||
{"n": "综艺", "v": "3"},
|
||||
{"n": "动漫", "v": "4"},
|
||||
{"n": "短剧", "v": "30"},
|
||||
{"n": "短剧", "v": "6"},
|
||||
{"n": "115", "v": "30"},
|
||||
{"n": "123", "v": "35"},
|
||||
{"n": "天移迅", "v": "36"},
|
||||
],
|
||||
)
|
||||
|
||||
def test_home_content_exposes_ouge_site_and_categories(self):
|
||||
content = self.spider.homeContent(False)
|
||||
type_ids = [item["type_id"] for item in content["class"]]
|
||||
self.assertIn("site_ouge", type_ids)
|
||||
self.assertEqual(content["class"][-1]["type_name"], "欧哥")
|
||||
self.assertEqual(
|
||||
content["filters"]["site_ouge"][0]["value"][1:],
|
||||
[
|
||||
{"n": "电影", "v": "1"},
|
||||
{"n": "剧集", "v": "2"},
|
||||
{"n": "电视剧", "v": "2"},
|
||||
{"n": "动漫", "v": "3"},
|
||||
{"n": "综艺", "v": "4"},
|
||||
{"n": "短剧", "v": "5"},
|
||||
@@ -182,6 +208,53 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
],
|
||||
)
|
||||
|
||||
def test_parse_cards_ignores_module_items_wrapper(self):
|
||||
site = {"id": "erxiao", "domains": ["https://www.2xiaopan.top"], "list_xpath": "//*[contains(@class,'module-item')]"}
|
||||
html = """
|
||||
<div id="main">
|
||||
<div class="module-items">
|
||||
<div class="module-item">
|
||||
<div class="module-item-pic">
|
||||
<a href="/index.php/vod/detail/id/111.html"></a>
|
||||
<img data-src="/poster-1.jpg" alt="影片一" />
|
||||
</div>
|
||||
<div class="module-item-text">HD</div>
|
||||
</div>
|
||||
<div class="module-item">
|
||||
<div class="module-item-pic">
|
||||
<a href="/index.php/vod/detail/id/222.html"></a>
|
||||
<img data-src="/poster-2.jpg" alt="影片二" />
|
||||
</div>
|
||||
<div class="module-item-text">更新至2集</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
cards = self.spider._parse_cards(site, html)
|
||||
self.assertEqual(
|
||||
cards,
|
||||
[
|
||||
{
|
||||
"vod_id": "site:erxiao:/index.php/vod/detail/id/111.html",
|
||||
"vod_name": "影片一",
|
||||
"vod_pic": "https://www.2xiaopan.top/poster-1.jpg",
|
||||
"vod_remarks": "HD",
|
||||
"vod_year": "",
|
||||
"_site": "erxiao",
|
||||
"_detail_path": "/index.php/vod/detail/id/111.html",
|
||||
},
|
||||
{
|
||||
"vod_id": "site:erxiao:/index.php/vod/detail/id/222.html",
|
||||
"vod_name": "影片二",
|
||||
"vod_pic": "https://www.2xiaopan.top/poster-2.jpg",
|
||||
"vod_remarks": "更新至2集",
|
||||
"vod_year": "",
|
||||
"_site": "erxiao",
|
||||
"_detail_path": "/index.php/vod/detail/id/222.html",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
@patch.object(Spider, "_request_with_failover")
|
||||
def test_category_content_uses_default_category_when_extend_missing(self, mock_request_with_failover):
|
||||
mock_request_with_failover.return_value = """
|
||||
@@ -197,6 +270,37 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
self.assertEqual(result["page"], 2)
|
||||
self.assertEqual(result["list"][0]["vod_name"], "分类影片")
|
||||
|
||||
@patch.object(Spider, "_fetch_site_home_recommend")
|
||||
def test_category_content_returns_recommend_results_with_site_tags(self, mock_fetch_site_home_recommend):
|
||||
mock_fetch_site_home_recommend.side_effect = lambda site, limit=30: {
|
||||
"wanou": [
|
||||
{
|
||||
"vod_id": "site:wanou:/voddetail/1.html",
|
||||
"vod_name": "繁花",
|
||||
"vod_pic": "https://img.example/w.jpg",
|
||||
"vod_remarks": "玩偶版",
|
||||
"vod_year": "2024",
|
||||
"_site": "wanou",
|
||||
"_detail_path": "/voddetail/1.html",
|
||||
}
|
||||
],
|
||||
"muou": [
|
||||
{
|
||||
"vod_id": "site:muou:/voddetail/2.html",
|
||||
"vod_name": "繁花",
|
||||
"vod_pic": "https://img.example/m.jpg",
|
||||
"vod_remarks": "木偶版",
|
||||
"vod_year": "2024",
|
||||
"_site": "muou",
|
||||
"_detail_path": "/voddetail/2.html",
|
||||
}
|
||||
],
|
||||
}.get(site["id"], [])
|
||||
result = self.spider.categoryContent("site_recommend", "1", False, {"recommendSite": "all"})
|
||||
self.assertEqual(result["total"], 1)
|
||||
self.assertEqual(result["list"][0]["vod_name"], "繁花")
|
||||
self.assertEqual(result["list"][0]["vod_remarks"], "[玩偶] 玩偶版")
|
||||
|
||||
def test_aggregate_search_results_merges_same_title_and_keeps_highest_priority_source(self):
|
||||
raw_results = [
|
||||
{
|
||||
@@ -247,8 +351,8 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
|
||||
@patch.object(Spider, "_fetch_site_search")
|
||||
def test_search_content_queries_sites_and_returns_aggregated_items(self, mock_fetch_site_search):
|
||||
mock_fetch_site_search.side_effect = [
|
||||
[
|
||||
results_by_site = {
|
||||
"wanou": [
|
||||
{
|
||||
"vod_id": "site:wanou:/voddetail/1.html",
|
||||
"vod_name": "繁花",
|
||||
@@ -259,7 +363,7 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
"_detail_path": "/voddetail/1.html",
|
||||
}
|
||||
],
|
||||
[
|
||||
"muou": [
|
||||
{
|
||||
"vod_id": "site:muou:/voddetail/2.html",
|
||||
"vod_name": "繁花",
|
||||
@@ -270,8 +374,8 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
"_detail_path": "/voddetail/2.html",
|
||||
}
|
||||
],
|
||||
[],
|
||||
]
|
||||
}
|
||||
mock_fetch_site_search.side_effect = lambda site, keyword, page: results_by_site.get(site["id"], [])
|
||||
result = self.spider.searchContent("繁花", False, "1")
|
||||
self.assertEqual(len(result["list"]), 1)
|
||||
self.assertEqual(result["list"][0]["vod_name"], "繁花")
|
||||
@@ -345,10 +449,22 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
self.spider.playerContent("quark#玩偶", "https://pan.quark.cn/s/demo", {}),
|
||||
{"parse": 0, "playUrl": "", "url": "https://pan.quark.cn/s/demo"},
|
||||
)
|
||||
self.assertEqual(
|
||||
self.spider.playerContent("quark#玩偶", "https://www.quark.cn/s/demo", {}),
|
||||
{"parse": 0, "playUrl": "", "url": "https://www.quark.cn/s/demo"},
|
||||
)
|
||||
self.assertEqual(
|
||||
self.spider.playerContent("baidu#玩偶", "https://pan.baidu.com/s/demo", {}),
|
||||
{"parse": 0, "playUrl": "", "url": "https://pan.baidu.com/s/demo"},
|
||||
)
|
||||
self.assertEqual(
|
||||
self.spider.playerContent("a189#玩偶", "https://cloud.189.cn/t/demo", {}),
|
||||
{"parse": 0, "playUrl": "", "url": "https://cloud.189.cn/t/demo"},
|
||||
)
|
||||
self.assertEqual(
|
||||
self.spider.playerContent("a139#玩偶", "https://yun.139.com/share/demo", {}),
|
||||
{"parse": 0, "playUrl": "", "url": "https://yun.139.com/share/demo"},
|
||||
)
|
||||
|
||||
def test_player_content_rejects_non_pan_url(self):
|
||||
self.assertEqual(
|
||||
@@ -460,22 +576,24 @@ class TestWanouAggregateSpider(unittest.TestCase):
|
||||
|
||||
@patch.object(Spider, "_fetch_site_search")
|
||||
def test_search_content_skips_site_errors(self, mock_fetch_site_search):
|
||||
mock_fetch_site_search.side_effect = [
|
||||
RuntimeError("boom"),
|
||||
[
|
||||
{
|
||||
"vod_id": "site:muou:/voddetail/2.html",
|
||||
"vod_name": "繁花",
|
||||
"vod_pic": "",
|
||||
"vod_remarks": "",
|
||||
"vod_year": "2024",
|
||||
"_site": "muou",
|
||||
"_detail_path": "/voddetail/2.html",
|
||||
}
|
||||
],
|
||||
[],
|
||||
[],
|
||||
]
|
||||
def fake_fetch(site, keyword, page):
|
||||
if site["id"] == "wanou":
|
||||
raise RuntimeError("boom")
|
||||
if site["id"] == "muou":
|
||||
return [
|
||||
{
|
||||
"vod_id": "site:muou:/voddetail/2.html",
|
||||
"vod_name": "繁花",
|
||||
"vod_pic": "",
|
||||
"vod_remarks": "",
|
||||
"vod_year": "2024",
|
||||
"_site": "muou",
|
||||
"_detail_path": "/voddetail/2.html",
|
||||
}
|
||||
]
|
||||
return []
|
||||
|
||||
mock_fetch_site_search.side_effect = fake_fetch
|
||||
result = self.spider.searchContent("繁花", False, "1")
|
||||
self.assertEqual(result["total"], 1)
|
||||
self.assertEqual(result["list"][0]["vod_name"], "繁花")
|
||||
|
||||
@@ -67,6 +67,9 @@ class Spider(BaseSpider):
|
||||
def _clean_text(self, text):
|
||||
return re.sub(r"\s+", " ", str(text or "").replace("\xa0", " ")).strip()
|
||||
|
||||
def _class_xpath(self, class_name):
|
||||
return f"contains(concat(' ', normalize-space(@class), ' '), ' {class_name} ')"
|
||||
|
||||
def _detect_pan_type(self, url):
|
||||
raw = str(url or "").strip()
|
||||
for pan_type, title, pattern in self.pan_patterns:
|
||||
@@ -92,15 +95,19 @@ class Spider(BaseSpider):
|
||||
|
||||
items = []
|
||||
seen = set()
|
||||
for node in root.xpath("//*[@id='main']//*[contains(@class,'module-item')]"):
|
||||
href = "".join(node.xpath(".//*[contains(@class,'module-item-pic')]//a[1]/@href")).strip()
|
||||
title = "".join(node.xpath(".//*[contains(@class,'module-item-pic')]//img[1]/@alt")).strip()
|
||||
item_xpath = self._class_xpath("module-item")
|
||||
pic_box_xpath = self._class_xpath("module-item-pic")
|
||||
text_xpath = self._class_xpath("module-item-text")
|
||||
caption_xpath = self._class_xpath("module-item-caption")
|
||||
for node in root.xpath(f"//*[@id='main']//*[{item_xpath}]"):
|
||||
href = "".join(node.xpath(f".//*[{pic_box_xpath}]//a[1]/@href")).strip()
|
||||
title = "".join(node.xpath(f".//*[{pic_box_xpath}]//img[1]/@alt")).strip()
|
||||
pic = (
|
||||
"".join(node.xpath(".//*[contains(@class,'module-item-pic')]//img[1]/@data-src")).strip()
|
||||
or "".join(node.xpath(".//*[contains(@class,'module-item-pic')]//img[1]/@src")).strip()
|
||||
"".join(node.xpath(f".//*[{pic_box_xpath}]//img[1]/@data-src")).strip()
|
||||
or "".join(node.xpath(f".//*[{pic_box_xpath}]//img[1]/@src")).strip()
|
||||
)
|
||||
remarks = self._clean_text("".join(node.xpath(".//*[contains(@class,'module-item-text')][1]//text()")))
|
||||
year = self._clean_text("".join(node.xpath(".//*[contains(@class,'module-item-caption')][1]//span[1]//text()")))
|
||||
remarks = self._clean_text("".join(node.xpath(f".//*[{text_xpath}][1]//text()")))
|
||||
year = self._clean_text("".join(node.xpath(f".//*[{caption_xpath}][1]//span[1]//text()")))
|
||||
if not href or not title or href in seen:
|
||||
continue
|
||||
seen.add(href)
|
||||
@@ -131,16 +138,20 @@ class Spider(BaseSpider):
|
||||
return {"page": page, "total": 0, "list": []}
|
||||
|
||||
items = []
|
||||
for node in root.xpath("//*[contains(@class,'module-search-item')]"):
|
||||
href = "".join(node.xpath(".//*[contains(@class,'video-serial')][1]/@href")).strip()
|
||||
title = "".join(node.xpath(".//*[contains(@class,'video-serial')][1]/@title")).strip()
|
||||
search_item_xpath = self._class_xpath("module-search-item")
|
||||
video_serial_xpath = self._class_xpath("video-serial")
|
||||
pic_box_xpath = self._class_xpath("module-item-pic")
|
||||
text_xpath = self._class_xpath("module-item-text")
|
||||
for node in root.xpath(f"//*[{search_item_xpath}]"):
|
||||
href = "".join(node.xpath(f".//*[{video_serial_xpath}][1]/@href")).strip()
|
||||
title = "".join(node.xpath(f".//*[{video_serial_xpath}][1]/@title")).strip()
|
||||
pic = (
|
||||
"".join(node.xpath(".//*[contains(@class,'module-item-pic')]//img[1]/@data-src")).strip()
|
||||
or "".join(node.xpath(".//*[contains(@class,'module-item-pic')]//img[1]/@src")).strip()
|
||||
"".join(node.xpath(f".//*[{pic_box_xpath}]//img[1]/@data-src")).strip()
|
||||
or "".join(node.xpath(f".//*[{pic_box_xpath}]//img[1]/@src")).strip()
|
||||
)
|
||||
remarks = self._clean_text(
|
||||
"".join(node.xpath(".//*[contains(@class,'video-serial')][1]//text()"))
|
||||
or "".join(node.xpath(".//*[contains(@class,'module-item-text')][1]//text()"))
|
||||
"".join(node.xpath(f".//*[{video_serial_xpath}][1]//text()"))
|
||||
or "".join(node.xpath(f".//*[{text_xpath}][1]//text()"))
|
||||
)
|
||||
if not href or not title:
|
||||
continue
|
||||
@@ -168,17 +179,23 @@ class Spider(BaseSpider):
|
||||
"pan_urls": [],
|
||||
}
|
||||
|
||||
mobile_play_xpath = self._class_xpath("mobile-play")
|
||||
lazyload_xpath = self._class_xpath("lazyload")
|
||||
page_title_xpath = self._class_xpath("page-title")
|
||||
info_title_xpath = self._class_xpath("video-info-itemtitle")
|
||||
row_info_xpath = self._class_xpath("module-row-info")
|
||||
|
||||
pic_candidates = root.xpath(
|
||||
"("
|
||||
f"//*[{mobile_play_xpath}]//*[{lazyload_xpath}]/@data-src | "
|
||||
f"//*[{mobile_play_xpath}]//*[{lazyload_xpath}]/@src"
|
||||
")[1]"
|
||||
)
|
||||
|
||||
detail = {
|
||||
"vod_id": vod_id,
|
||||
"vod_name": self._clean_text("".join(root.xpath("//*[contains(@class,'page-title')][1]//text()"))),
|
||||
"vod_pic": self._build_url(
|
||||
"".join(
|
||||
root.xpath(
|
||||
"//*[contains(@class,'mobile-play')]//*[contains(@class,'lazyload')][1]/@data-src | "
|
||||
"//*[contains(@class,'mobile-play')]//*[contains(@class,'lazyload')][1]/@src"
|
||||
)
|
||||
).strip()
|
||||
),
|
||||
"vod_name": self._clean_text("".join(root.xpath(f"//*[{page_title_xpath}][1]//text()"))),
|
||||
"vod_pic": self._build_url((pic_candidates[0] if pic_candidates else "").strip()),
|
||||
"vod_year": "",
|
||||
"vod_director": "",
|
||||
"vod_actor": "",
|
||||
@@ -186,7 +203,7 @@ class Spider(BaseSpider):
|
||||
"pan_urls": [],
|
||||
}
|
||||
|
||||
for label_node in root.xpath("//*[contains(@class,'video-info-itemtitle')]"):
|
||||
for label_node in root.xpath(f"//*[{info_title_xpath}]"):
|
||||
key = self._clean_text("".join(label_node.xpath(".//text()")))
|
||||
sibling = label_node.getnext()
|
||||
if sibling is None:
|
||||
@@ -203,7 +220,7 @@ class Spider(BaseSpider):
|
||||
elif "剧情" in key:
|
||||
detail["vod_content"] = text_value
|
||||
|
||||
for node in root.xpath("//*[contains(@class,'module-row-info')]//p"):
|
||||
for node in root.xpath(f"//*[{row_info_xpath}]//p"):
|
||||
text = self._clean_text("".join(node.xpath(".//text()")))
|
||||
if text:
|
||||
detail["pan_urls"].append(text)
|
||||
|
||||
+232
-61
@@ -15,6 +15,7 @@ class Spider(BaseSpider):
|
||||
def __init__(self):
|
||||
self.name = "玩偶聚合"
|
||||
self.filter_root = os.path.join(os.path.dirname(__file__), "../筛选")
|
||||
self.recommend_page_size = 20
|
||||
self.headers = {
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||||
@@ -48,7 +49,7 @@ class Spider(BaseSpider):
|
||||
{
|
||||
"id": "wanou",
|
||||
"name": "玩偶",
|
||||
"domains": ["https://wogg.xxooo.cf"],
|
||||
"domains": ["https://wogg.xxooo.cf", "https://www.wogg.net"],
|
||||
"filter_files": ["wogg.json"],
|
||||
"list_xpath": "//*[contains(@class,'module-item')]",
|
||||
"search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
@@ -56,65 +57,140 @@ class Spider(BaseSpider):
|
||||
"category_url": "/vodshow/{categoryId}--------{page}---.html",
|
||||
"category_url_with_filters": "/vodshow/{categoryId}-{area}-{by}-{class}-----{page}---{year}.html",
|
||||
"search_url": "/vodsearch/-------------.html?wd={keyword}&page={page}",
|
||||
"default_categories": [("1", "电影"), ("2", "电视剧"), ("3", "动漫"), ("4", "综艺")],
|
||||
"default_categories": [
|
||||
("44", "臻彩"),
|
||||
("1", "电影"),
|
||||
("2", "电视剧"),
|
||||
("3", "动漫"),
|
||||
("4", "综艺"),
|
||||
("5", "音乐"),
|
||||
("6", "短剧"),
|
||||
("46", "纪录片"),
|
||||
],
|
||||
},
|
||||
# {
|
||||
# "id": "muou",
|
||||
# "name": "木偶",
|
||||
# "domains": ["https://www.muou.site", "http://123.666291.xyz"],
|
||||
# "filter_files": ["mogg.json"],
|
||||
# "list_xpath": "//*[contains(@class,'module-item')]",
|
||||
# "search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
# "detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
# "category_url": "/vodshow/{categoryId}--------{page}---.html",
|
||||
# "search_url": "/vodsearch/-------------.html?wd={keyword}&page={page}",
|
||||
# "default_categories": [("1", "电影"), ("2", "电视剧"), ("3", "动漫"), ("29", "综艺")],
|
||||
# },
|
||||
# {
|
||||
# "id": "labi",
|
||||
# "name": "蜡笔",
|
||||
# "domains": ["http://xiaocge.fun"],
|
||||
# "filter_files": ["labi.json"],
|
||||
# "list_xpath": "//*[contains(@class,'module-item')]",
|
||||
# "search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
# "detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
# "category_url": "/vodshow/{categoryId}--------{page}---.html",
|
||||
# "search_url": "/vodsearch/-------------.html?wd={keyword}&page={page}",
|
||||
# "default_categories": [("1", "电影"), ("2", "电视剧"), ("3", "动漫"), ("4", "综艺")],
|
||||
# },
|
||||
{
|
||||
"id": "zhizhen",
|
||||
"name": "至臻",
|
||||
"domains": ["http://www.miqk.cc"],
|
||||
"filter_files": [],
|
||||
"id": "muou",
|
||||
"name": "木偶",
|
||||
"domains": ["https://www.muou.site", "https://www.muou.asia", "https://666.666291.xyz"],
|
||||
"filter_files": ["mogg.json"],
|
||||
"list_xpath": "//*[contains(@class,'module-item')]",
|
||||
"search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
"detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
"category_url": "/index.php/vod/show/id/{categoryId}/page/{page}.html",
|
||||
"search_url": "/index.php/vod/search/page/{page}/wd/{keyword}.html",
|
||||
"default_categories": [
|
||||
("25", "臻选"),
|
||||
("1", "电影"),
|
||||
("2", "剧集"),
|
||||
("2", "电视剧"),
|
||||
("3", "动漫"),
|
||||
("4", "纪录片"),
|
||||
("29", "综艺"),
|
||||
("30", "原盘"),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "labi",
|
||||
"name": "蜡笔",
|
||||
"domains": ["http://xiaocgege.shop", "http://fmao.shop"],
|
||||
"filter_files": ["labi.json"],
|
||||
"list_xpath": "//*[contains(@class,'module-item')]",
|
||||
"search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
"detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
"default_categories": [
|
||||
("29", "臻彩"),
|
||||
("1", "电影"),
|
||||
("2", "电视剧"),
|
||||
("3", "动漫"),
|
||||
("4", "综艺"),
|
||||
("5", "短剧"),
|
||||
("24", "蜡笔4K"),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "zhizhen",
|
||||
"name": "至臻",
|
||||
"domains": ["http://www.miqk.cc", "https://www.mihdr.top", "https://mihdr.top"],
|
||||
"filter_files": ["zhizhen.json"],
|
||||
"list_xpath": "//*[contains(@class,'module-item')]",
|
||||
"search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
"detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
"default_categories": [
|
||||
("26", "臻彩"),
|
||||
("1", "电影"),
|
||||
("2", "电视剧"),
|
||||
("3", "动漫"),
|
||||
("4", "综艺"),
|
||||
("5", "短剧"),
|
||||
("24", "老剧"),
|
||||
("26", "严选"),
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "erxiao",
|
||||
"name": "二小",
|
||||
"domains": [
|
||||
"https://www.2xiaopan.top",
|
||||
"https://www.erxiaozhan.top",
|
||||
"https://www.wexwp.cc",
|
||||
],
|
||||
"filter_files": ["erxiao.json"],
|
||||
"list_xpath": "//*[contains(@class,'module-item')]",
|
||||
"search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
"detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
"default_categories": [
|
||||
("4", "臻彩"),
|
||||
("1", "电影"),
|
||||
("2", "电视剧"),
|
||||
("3", "动漫"),
|
||||
("21", "综艺"),
|
||||
],
|
||||
},
|
||||
# {
|
||||
# "id": "huban",
|
||||
# "name": "虎斑",
|
||||
# "domains": ["http://154.222.27.33:20720", "http://xhban.xyz:20720", "http://103.45.162.207:20720"],
|
||||
# "filter_files": ["huban.json"],
|
||||
# "list_xpath": "//*[contains(@class,'module-item')]",
|
||||
# "search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
# "detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
# "default_categories": [
|
||||
# ("6", "臻彩"),
|
||||
# ("1", "电影"),
|
||||
# ("2", "电视剧"),
|
||||
# ("3", "综艺"),
|
||||
# ("4", "动漫"),
|
||||
# ("5", "短剧"),
|
||||
# ("30", "115网盘"),
|
||||
# ],
|
||||
# },
|
||||
# {
|
||||
# "id": "kuaiying",
|
||||
# "name": "快映",
|
||||
# "domains": ["http://154.201.83.50:12512", "http://xsayang.fun:12512"],
|
||||
# "filter_files": ["xiaoban.json"],
|
||||
# "list_xpath": "//*[contains(@class,'module-item')]",
|
||||
# "search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
# "detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
# "default_categories": [
|
||||
# ("5", "臻彩"),
|
||||
# ("1", "电影"),
|
||||
# ("2", "电视剧"),
|
||||
# ("3", "综艺"),
|
||||
# ("4", "动漫"),
|
||||
# ("6", "短剧"),
|
||||
# ("30", "115"),
|
||||
# ("35", "123"),
|
||||
# ("36", "天移迅"),
|
||||
# ],
|
||||
# },
|
||||
{
|
||||
"id": "shandian",
|
||||
"name": "闪电",
|
||||
"domains": ["https://sd.sduc.site"],
|
||||
"filter_files": [],
|
||||
"filter_files": ["shandian.json"],
|
||||
"list_xpath": "//*[contains(@class,'module-item')]",
|
||||
"search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
"detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
"category_url": "/index.php/vod/show/id/{categoryId}/page/{page}.html",
|
||||
"search_url": "/index.php/vod/search/page/{page}/wd/{keyword}.html",
|
||||
"default_categories": [
|
||||
("1", "电影"),
|
||||
("2", "剧集"),
|
||||
("2", "电视剧"),
|
||||
("3", "综艺"),
|
||||
("4", "动漫"),
|
||||
("30", "短剧"),
|
||||
@@ -122,17 +198,15 @@ class Spider(BaseSpider):
|
||||
},
|
||||
{
|
||||
"id": "ouge",
|
||||
"name": "欧歌",
|
||||
"name": "欧哥",
|
||||
"domains": ["https://woog.nxog.eu.org"],
|
||||
"filter_files": [],
|
||||
"filter_files": ["ouge.json"],
|
||||
"list_xpath": "//*[contains(@class,'module-item')]",
|
||||
"search_xpath": "//*[contains(@class,'module-search-item')]",
|
||||
"detail_pan_xpath": "//*[contains(@class,'module-row-info')]//p",
|
||||
"category_url": "/index.php/vod/show/id/{categoryId}/page/{page}.html",
|
||||
"search_url": "/index.php/vod/search/page/{page}/wd/{keyword}.html",
|
||||
"default_categories": [
|
||||
("1", "电影"),
|
||||
("2", "剧集"),
|
||||
("2", "电视剧"),
|
||||
("3", "动漫"),
|
||||
("4", "综艺"),
|
||||
("5", "短剧"),
|
||||
@@ -151,7 +225,47 @@ class Spider(BaseSpider):
|
||||
return {"list": []}
|
||||
|
||||
def _load_local_filter_groups(self, site):
|
||||
return []
|
||||
groups = []
|
||||
for filename in site.get("filter_files", []):
|
||||
if not filename:
|
||||
continue
|
||||
file_path = os.path.join(self.filter_root, filename)
|
||||
if not os.path.exists(file_path):
|
||||
continue
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as handle:
|
||||
raw = json.load(handle)
|
||||
except Exception:
|
||||
continue
|
||||
merged = {}
|
||||
for category_groups in raw.values() if isinstance(raw, dict) else []:
|
||||
if not isinstance(category_groups, list):
|
||||
continue
|
||||
for group in category_groups:
|
||||
key = str(group.get("key") or "").strip()
|
||||
if not key or key == "categoryId":
|
||||
continue
|
||||
bucket = merged.setdefault(
|
||||
key,
|
||||
{
|
||||
"key": key,
|
||||
"name": str(group.get("name") or key),
|
||||
"init": str(group.get("init") or ""),
|
||||
"value": [],
|
||||
},
|
||||
)
|
||||
for item in group.get("value", []):
|
||||
value = str(item.get("v") if isinstance(item, dict) else "")
|
||||
name = str(item.get("n") if isinstance(item, dict) else "")
|
||||
if not name:
|
||||
continue
|
||||
if not any(existing.get("v") == value for existing in bucket["value"]):
|
||||
bucket["value"].append({"n": name, "v": value})
|
||||
for group in merged.values():
|
||||
if not any(item.get("v") == "" for item in group["value"]):
|
||||
group["value"].insert(0, {"n": "全部", "v": ""})
|
||||
groups.append(group)
|
||||
return groups
|
||||
|
||||
def _build_site_filters(self, site):
|
||||
groups = [
|
||||
@@ -167,8 +281,20 @@ class Spider(BaseSpider):
|
||||
return groups
|
||||
|
||||
def homeContent(self, filter):
|
||||
classes = [{"type_id": f"site_{site['id']}", "type_name": site["name"]} for site in self.sites]
|
||||
filters = {f"site_{site['id']}": self._build_site_filters(site) for site in self.sites}
|
||||
classes = [{"type_id": "site_recommend", "type_name": "推荐"}]
|
||||
classes.extend({"type_id": f"site_{site['id']}", "type_name": site["name"]} for site in self.sites)
|
||||
filters = {
|
||||
"site_recommend": [
|
||||
{
|
||||
"key": "recommendSite",
|
||||
"name": "站点",
|
||||
"init": "all",
|
||||
"value": [{"n": "全部", "v": "all"}]
|
||||
+ [{"n": site["name"], "v": site["id"]} for site in self.sites],
|
||||
}
|
||||
]
|
||||
}
|
||||
filters.update({f"site_{site['id']}": self._build_site_filters(site) for site in self.sites})
|
||||
return {"class": classes, "filters": filters}
|
||||
|
||||
def _encode_site_vod_id(self, site_id, path):
|
||||
@@ -218,6 +344,13 @@ class Spider(BaseSpider):
|
||||
return "https:" + raw
|
||||
return str(base).rstrip("/") + "/" + raw.lstrip("/")
|
||||
|
||||
def _class_xpath(self, class_name):
|
||||
return f"contains(concat(' ', normalize-space(@class), ' '), ' {class_name} ')"
|
||||
|
||||
def _has_class(self, node, class_name):
|
||||
classes = f" {str(node.get('class') or '').strip()} "
|
||||
return f" {class_name} " in classes
|
||||
|
||||
def _build_category_url(self, site, category_id, pg, extend):
|
||||
values = dict(extend or {})
|
||||
values.setdefault("categoryId", category_id)
|
||||
@@ -237,7 +370,8 @@ class Spider(BaseSpider):
|
||||
}
|
||||
)
|
||||
else:
|
||||
path = site["category_url"].format(categoryId=values["categoryId"], page=int(pg))
|
||||
template = site.get("category_url") or "/index.php/vod/show/id/{categoryId}/page/{page}.html"
|
||||
path = template.format(categoryId=values["categoryId"], page=int(pg))
|
||||
return self._build_absolute_url(site["domains"][0], path)
|
||||
|
||||
def _request_with_failover(self, site, path_or_url, referer=None):
|
||||
@@ -263,17 +397,21 @@ class Spider(BaseSpider):
|
||||
|
||||
items = []
|
||||
seen = set()
|
||||
pic_box_xpath = self._class_xpath("module-item-pic")
|
||||
text_xpath = self._class_xpath("module-item-text")
|
||||
for card in root.xpath(site["list_xpath"]):
|
||||
if not self._has_class(card, "module-item"):
|
||||
continue
|
||||
href = ((card.xpath(".//a[@href][1]/@href") or [""])[0]).strip()
|
||||
title = (
|
||||
((card.xpath(".//img[@alt][1]/@alt") or [""])[0]).strip()
|
||||
or ((card.xpath(".//a[@title][1]/@title") or [""])[0]).strip()
|
||||
)
|
||||
pic = (
|
||||
((card.xpath(".//img[@data-src][1]/@data-src") or [""])[0]).strip()
|
||||
or ((card.xpath(".//img[@src][1]/@src") or [""])[0]).strip()
|
||||
((card.xpath(f".//*[{pic_box_xpath}]//img[1]/@data-src") or [""])[0]).strip()
|
||||
or ((card.xpath(f".//*[{pic_box_xpath}]//img[1]/@src") or [""])[0]).strip()
|
||||
)
|
||||
remarks = "".join(card.xpath(".//*[contains(@class,'module-item-text')][1]//text()")).strip()
|
||||
remarks = "".join(card.xpath(f".//*[{text_xpath}][1]//text()")).strip()
|
||||
if not href or not title or href in seen:
|
||||
continue
|
||||
seen.add(href)
|
||||
@@ -292,8 +430,31 @@ class Spider(BaseSpider):
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
site_id = str(tid).replace("site_", "", 1)
|
||||
site = self._get_site(site_id)
|
||||
values = extend if isinstance(extend, dict) else {}
|
||||
if site_id == "recommend":
|
||||
recommend_site_id = str(values.get("recommendSite") or "all")
|
||||
candidates = self.sites if recommend_site_id == "all" else [site for site in self.sites if site["id"] == recommend_site_id]
|
||||
merged = []
|
||||
for site in candidates:
|
||||
for item in self._fetch_site_home_recommend(site):
|
||||
matched = None
|
||||
for existing in merged:
|
||||
if self._is_same_title(existing, item):
|
||||
matched = existing
|
||||
break
|
||||
if matched is None:
|
||||
source_name = site["name"]
|
||||
remarks = str(item.get("vod_remarks") or "").strip()
|
||||
tagged = dict(item)
|
||||
tagged["vod_remarks"] = f"[{source_name}] {remarks}".strip()
|
||||
merged.append(tagged)
|
||||
page = int(pg)
|
||||
start = max(page - 1, 0) * self.recommend_page_size
|
||||
end = start + self.recommend_page_size
|
||||
paged = merged[start:end]
|
||||
return {"list": paged, "page": page, "limit": len(paged), "total": len(merged)}
|
||||
|
||||
site = self._get_site(site_id)
|
||||
category_id = values.get("categoryId") or site["default_categories"][0][0]
|
||||
html = self._request_with_failover(site, self._build_category_url(site, category_id, pg, values))
|
||||
items = self._parse_cards(site, html)
|
||||
@@ -313,13 +474,17 @@ class Spider(BaseSpider):
|
||||
items = []
|
||||
seen = set()
|
||||
xpath = site.get("search_xpath") or site["list_xpath"]
|
||||
video_serial_xpath = self._class_xpath("video-serial")
|
||||
text_xpath = self._class_xpath("module-item-text")
|
||||
for card in root.xpath(xpath):
|
||||
if "module-search-item" in xpath and not self._has_class(card, "module-search-item"):
|
||||
continue
|
||||
href = (
|
||||
((card.xpath(".//*[contains(@class,'video-serial')][1]/@href") or [""])[0]).strip()
|
||||
((card.xpath(f".//*[{video_serial_xpath}][1]/@href") or [""])[0]).strip()
|
||||
or ((card.xpath(".//*[@href][1]/@href") or [""])[0]).strip()
|
||||
)
|
||||
title = (
|
||||
((card.xpath(".//*[contains(@class,'video-serial')][1]/@title") or [""])[0]).strip()
|
||||
((card.xpath(f".//*[{video_serial_xpath}][1]/@title") or [""])[0]).strip()
|
||||
or ((card.xpath(".//img[@alt][1]/@alt") or [""])[0]).strip()
|
||||
or ((card.xpath(".//*[@title][1]/@title") or [""])[0]).strip()
|
||||
)
|
||||
@@ -327,7 +492,7 @@ class Spider(BaseSpider):
|
||||
((card.xpath(".//img[@data-src][1]/@data-src") or [""])[0]).strip()
|
||||
or ((card.xpath(".//img[@src][1]/@src") or [""])[0]).strip()
|
||||
)
|
||||
remarks = "".join(card.xpath(".//*[contains(@class,'module-item-text')][1]//text()")).strip()
|
||||
remarks = "".join(card.xpath(f".//*[{text_xpath}][1]//text()")).strip()
|
||||
if not href or not title or href in seen:
|
||||
continue
|
||||
seen.add(href)
|
||||
@@ -345,10 +510,16 @@ class Spider(BaseSpider):
|
||||
return items
|
||||
|
||||
def _fetch_site_search(self, site, keyword, pg):
|
||||
search_path = site["search_url"].format(keyword=quote(str(keyword)), page=int(pg))
|
||||
template = site.get("search_url") or "/index.php/vod/search/page/{page}/wd/{keyword}.html"
|
||||
search_path = template.format(keyword=quote(str(keyword)), page=int(pg))
|
||||
html = self._request_with_failover(site, search_path)
|
||||
return self._parse_search_cards(site, html)
|
||||
|
||||
def _fetch_site_home_recommend(self, site, limit=30):
|
||||
html = self._request_with_failover(site, "/")
|
||||
items = self._parse_cards(site, html)
|
||||
return items[:limit]
|
||||
|
||||
def _aggregate_search_results(self, items):
|
||||
groups = []
|
||||
for item in items:
|
||||
@@ -406,21 +577,21 @@ class Spider(BaseSpider):
|
||||
value = str(url or "").lower()
|
||||
if "pan.baidu.com" in value:
|
||||
return "baidu", "百度资源"
|
||||
if "pan.quark.cn" in value:
|
||||
if "quark.cn" in value:
|
||||
return "quark", "夸克资源"
|
||||
if "drive.uc.cn" in value:
|
||||
if "uc.cn" in value:
|
||||
return "uc", "UC资源"
|
||||
if "alipan.com" in value or "aliyundrive.com" in value:
|
||||
return "aliyun", "阿里资源"
|
||||
if "pan.xunlei.com" in value:
|
||||
if "xunlei.com" in value:
|
||||
return "xunlei", "迅雷资源"
|
||||
if "123pan.com" in value:
|
||||
return "a123", "123资源"
|
||||
if "115.com" in value:
|
||||
if "115.com" in value or "115cdn.com" in value:
|
||||
return "a115", "115资源"
|
||||
if "189.cn" in value:
|
||||
if "cloud.189.cn" in value or "189.cn" in value:
|
||||
return "a189", "天翼资源"
|
||||
if "139.com" in value:
|
||||
if "yun.139.com" in value or "139.com" in value:
|
||||
return "a139", "移动云资源"
|
||||
return "", ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user