feat: add tengxun category and batch helper
This commit is contained in:
@@ -21,6 +21,13 @@ HOME_HTML = """
|
||||
</div>
|
||||
"""
|
||||
|
||||
CATEGORY_HTML = """
|
||||
<div class="list_item">
|
||||
<a data-float="/x/cover/cid001/vid001.html"><img alt="三体" src="https://img.test/c.jpg"></a>
|
||||
<a>更新至30集</a>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
class TestTencentSpider(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -71,6 +78,48 @@ class TestTencentSpider(unittest.TestCase):
|
||||
},
|
||||
)
|
||||
|
||||
@patch.object(Spider, "fetch")
|
||||
def test_category_content_maps_filters_and_prefixes_channel(self, mock_fetch):
|
||||
mock_fetch.return_value = SimpleNamespace(text=CATEGORY_HTML)
|
||||
result = self.spider.categoryContent(
|
||||
"tv",
|
||||
"2",
|
||||
False,
|
||||
{
|
||||
"sort": "18",
|
||||
"iyear": "2024",
|
||||
"year": "2024",
|
||||
"type": "17",
|
||||
"feature": "4",
|
||||
"area": "2",
|
||||
"itrailer": "1",
|
||||
"sex": "1",
|
||||
},
|
||||
)
|
||||
request_url = mock_fetch.call_args.args[0]
|
||||
self.assertIn("channel=tv", request_url)
|
||||
self.assertIn("offset=21", request_url)
|
||||
self.assertIn("sort=18", request_url)
|
||||
self.assertIn("iyear=2024", request_url)
|
||||
self.assertIn("year=2024", request_url)
|
||||
self.assertIn("itype=17", request_url)
|
||||
self.assertIn("ifeature=4", request_url)
|
||||
self.assertIn("iarea=2", request_url)
|
||||
self.assertIn("itrailer=1", request_url)
|
||||
self.assertIn("gender=1", request_url)
|
||||
self.assertEqual(result["list"][0]["vod_id"], "tv$/x/cover/cid001/vid001.html")
|
||||
self.assertEqual(result["page"], 2)
|
||||
self.assertEqual(result["limit"], 21)
|
||||
self.assertEqual(result["pagecount"], 9999)
|
||||
|
||||
@patch.object(Spider, "fetch")
|
||||
def test_get_batch_video_info_parses_qzoutputjson_payload(self, mock_fetch):
|
||||
mock_fetch.return_value = SimpleNamespace(
|
||||
text='QZOutputJson={"results":[{"fields":{"vid":"vid001","title":"第1集","category_map":["0","正片"]}}]};'
|
||||
)
|
||||
result = self.spider._get_batch_video_info(["vid001"])
|
||||
self.assertEqual(result, [{"vid": "vid001", "title": "第1集", "type": "正片"}])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
+72
@@ -1,4 +1,5 @@
|
||||
# coding=utf-8
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
@@ -74,3 +75,74 @@ class Spider(BaseSpider):
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
return {"parse": 1, "jx": 1, "url": id, "header": self._headers()}
|
||||
|
||||
def _safe_json(self, text, strip_prefix="", strip_suffix=""):
|
||||
raw = str(text or "")
|
||||
if strip_prefix and raw.startswith(strip_prefix):
|
||||
raw = raw[len(strip_prefix):]
|
||||
if strip_suffix and raw.endswith(strip_suffix):
|
||||
raw = raw[: -len(strip_suffix)]
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
def _get_batch_video_info(self, vids):
|
||||
results = []
|
||||
for start in range(0, len(vids or []), 30):
|
||||
batch = vids[start:start + 30]
|
||||
if not batch:
|
||||
continue
|
||||
url = (
|
||||
"https://union.video.qq.com/fcgi-bin/data?otype=json&tid=1804&appid=20001238"
|
||||
"&appkey=6c03bbe9658448a4&union_platform=1&idlist=" + ",".join(batch)
|
||||
)
|
||||
response = self.fetch(url, headers=self._headers())
|
||||
payload = self._safe_json(getattr(response, "text", ""), strip_prefix="QZOutputJson=", strip_suffix=";")
|
||||
for item in payload.get("results", []):
|
||||
fields = item.get("fields", {})
|
||||
category_map = fields.get("category_map", [])
|
||||
results.append(
|
||||
{
|
||||
"vid": fields.get("vid", ""),
|
||||
"title": fields.get("title", ""),
|
||||
"type": category_map[1] if len(category_map) > 1 else "",
|
||||
}
|
||||
)
|
||||
return results
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
page = int(pg)
|
||||
offset = (page - 1) * 21
|
||||
params = [
|
||||
"_all=1",
|
||||
"append=1",
|
||||
f"channel={tid}",
|
||||
"listpage=1",
|
||||
f"offset={offset}",
|
||||
"pagesize=21",
|
||||
"iarea=-1",
|
||||
]
|
||||
options = dict(extend or {})
|
||||
if options.get("sort"):
|
||||
params.append(f"sort={options['sort']}")
|
||||
if options.get("iyear"):
|
||||
params.append(f"iyear={options['iyear']}")
|
||||
if options.get("year"):
|
||||
params.append(f"year={options['year']}")
|
||||
if options.get("type"):
|
||||
params.append(f"itype={options['type']}")
|
||||
if options.get("feature"):
|
||||
params.append(f"ifeature={options['feature']}")
|
||||
if options.get("area"):
|
||||
params.append(f"iarea={options['area']}")
|
||||
if options.get("itrailer"):
|
||||
params.append(f"itrailer={options['itrailer']}")
|
||||
if options.get("sex"):
|
||||
params.append(f"gender={options['sex']}")
|
||||
url = f"{self.base_host}/x/bu/pagesheet/list?" + "&".join(params)
|
||||
response = self.fetch(url, headers=self._headers())
|
||||
return {
|
||||
"list": self._parse_list_items(getattr(response, "text", ""), with_channel=True, channel_id=str(tid)),
|
||||
"page": page,
|
||||
"pagecount": 9999,
|
||||
"limit": 21,
|
||||
"total": 999999,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user