fix: support nested cupfox player data
This commit is contained in:
@@ -123,6 +123,24 @@ class TestCupfoxSpider(unittest.TestCase):
|
|||||||
self.assertEqual(data["url"], "vid-1")
|
self.assertEqual(data["url"], "vid-1")
|
||||||
self.assertEqual(data["from"], "lineA")
|
self.assertEqual(data["from"], "lineA")
|
||||||
|
|
||||||
|
def test_extract_player_data_supports_nested_object_literal(self):
|
||||||
|
html = """
|
||||||
|
<script>
|
||||||
|
var player_aaaa={
|
||||||
|
"flag":"play",
|
||||||
|
"encrypt":0,
|
||||||
|
"vod_data":{"vod_name":"八千里路云和月","vod_actor":"王阳,万茜"},
|
||||||
|
"url":"DJP5QlL6j66wOTl+NrtIwkJCenh0ZVBlTHJzTWJWd0Y1eTNBd1crTmt5NmpjK05XOTFxb25iSTJ4d2RSUms4YllrVVhSU2xyK0JGcFFZZThibmVqU1BWUFlEMnVWTUpQVmR1Vm9FZHJJWlFaaHNaR3pmTHYwbjVyUE11dkdwbzVOMTJpRFpBK3cvYUl5RnNuQXNaelFZZ0plWVhWYitFenJOMHhUZz09",
|
||||||
|
"from":"rb",
|
||||||
|
"server":"no"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
"""
|
||||||
|
data = self.spider._extract_player_data(html)
|
||||||
|
self.assertEqual(data["encrypt"], 0)
|
||||||
|
self.assertEqual(data["vod_data"]["vod_name"], "八千里路云和月")
|
||||||
|
self.assertEqual(data["from"], "rb")
|
||||||
|
|
||||||
def test_decode2_recovers_shifted_text(self):
|
def test_decode2_recovers_shifted_text(self):
|
||||||
encoded = "QXdCQ2tE"
|
encoded = "QXdCQ2tE"
|
||||||
self.assertEqual(self.spider._decode2(encoded), "P0")
|
self.assertEqual(self.spider._decode2(encoded), "P0")
|
||||||
|
|||||||
@@ -160,14 +160,58 @@ class Spider(BaseSpider):
|
|||||||
return second["text"]
|
return second["text"]
|
||||||
|
|
||||||
def _extract_player_data(self, html_text):
|
def _extract_player_data(self, html_text):
|
||||||
matched = re.search(r"player_aaaa\s*=\s*(\{[\s\S]*?\})\s*;?", str(html_text or ""))
|
text = str(html_text or "")
|
||||||
|
matched = re.search(r"player_aaaa\s*=", text, re.I)
|
||||||
if not matched:
|
if not matched:
|
||||||
return None
|
return None
|
||||||
|
object_start = text.find("{", matched.end())
|
||||||
|
if object_start < 0:
|
||||||
|
return None
|
||||||
|
raw_object = self._extract_balanced_object(text, object_start)
|
||||||
|
if not raw_object:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
return json.loads(matched.group(1))
|
return json.loads(raw_object)
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _extract_balanced_object(self, text, start_index):
|
||||||
|
raw = str(text or "")
|
||||||
|
if start_index < 0 or start_index >= len(raw) or raw[start_index] != "{":
|
||||||
|
return ""
|
||||||
|
|
||||||
|
depth = 0
|
||||||
|
in_string = False
|
||||||
|
quote_char = ""
|
||||||
|
escaped = False
|
||||||
|
|
||||||
|
for index in range(start_index, len(raw)):
|
||||||
|
char = raw[index]
|
||||||
|
if in_string:
|
||||||
|
if escaped:
|
||||||
|
escaped = False
|
||||||
|
elif char == "\\":
|
||||||
|
escaped = True
|
||||||
|
elif char == quote_char:
|
||||||
|
in_string = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
if char in ('"', "'"):
|
||||||
|
in_string = True
|
||||||
|
quote_char = char
|
||||||
|
continue
|
||||||
|
|
||||||
|
if char == "{":
|
||||||
|
depth += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if char == "}":
|
||||||
|
depth -= 1
|
||||||
|
if depth == 0:
|
||||||
|
return raw[start_index : index + 1]
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
def _decode2(self, encoded):
|
def _decode2(self, encoded):
|
||||||
if not encoded:
|
if not encoded:
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
Reference in New Issue
Block a user