上传文件至「/」

This commit is contained in:
2026-07-23 08:08:41 +02:00
parent 5aa36748c7
commit 643876e051
2 changed files with 1065 additions and 0 deletions
+622
View File
@@ -0,0 +1,622 @@
# -*- coding: utf-8 -*-
# 初见影视爬虫 - 爱豆儿解析版
import re
import json
import urllib.parse
import sys
sys.path.append('..')
from base.spider import Spider
class Spider(Spider):
def init(self, extend=""):
self.extend = extend
def getName(self):
return "初见影视"
def isVideoFormat(self, url):
return False
def manualVideoCheck(self):
return False
def destroy(self):
pass
host = 'https://cjysw.cc'
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; Mobile) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/114.0.0.0 Mobile Safari/537.36',
'Referer': host,
}
classes_config = [
("电影", "1"),
("剧集", "15"),
("动漫", "30"),
("综艺", "24"),
("纪录片", "63"),
("短剧", "47"),
("Netflix", "60"),
]
# ====== 只使用爱豆儿解析接口 ======
PARSE_API = "https://jx.aidouer.net/?url="
def homeContent(self, filter):
result = {}
classes = []
for name, tid in self.classes_config:
classes.append({
"type_name": name,
"type_id": tid
})
filters = {}
filters["1"] = [
{"key": "class", "name": "类型", "value": [
{"n": "全部", "v": ""},
{"n": "动作", "v": "动作"},
{"n": "喜剧", "v": "喜剧"},
{"n": "爱情", "v": "爱情"},
{"n": "科幻", "v": "科幻"},
{"n": "恐怖", "v": "恐怖"},
{"n": "剧情", "v": "剧情"},
{"n": "战争", "v": "战争"},
{"n": "犯罪", "v": "犯罪"},
{"n": "动画", "v": "动画"},
{"n": "奇幻", "v": "奇幻"},
{"n": "冒险", "v": "冒险"},
{"n": "悬疑", "v": "悬疑"},
{"n": "惊悚", "v": "惊悚"},
{"n": "古装", "v": "古装"},
{"n": "历史", "v": "历史"},
]},
{"key": "area", "name": "地区", "value": [
{"n": "全部", "v": ""},
{"n": "大陆", "v": "大陆"},
{"n": "香港", "v": "香港"},
{"n": "台湾", "v": "台湾"},
{"n": "美国", "v": "美国"},
{"n": "日本", "v": "日本"},
{"n": "韩国", "v": "韩国"},
{"n": "英国", "v": "英国"},
{"n": "法国", "v": "法国"},
{"n": "德国", "v": "德国"},
{"n": "泰国", "v": "泰国"},
{"n": "印度", "v": "印度"},
{"n": "其他", "v": "其他"},
]},
{"key": "year", "name": "年份", "value": [
{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
{"n": "2021", "v": "2021"},
{"n": "2020", "v": "2020"},
]},
]
filters["15"] = [
{"key": "class", "name": "类型", "value": [
{"n": "全部", "v": ""},
{"n": "国产剧", "v": "国产剧"},
{"n": "港剧", "v": "港剧"},
{"n": "台剧", "v": "台剧"},
{"n": "日剧", "v": "日剧"},
{"n": "韩剧", "v": "韩剧"},
{"n": "美剧", "v": "美剧"},
{"n": "英剧", "v": "英剧"},
{"n": "泰剧", "v": "泰剧"},
]},
{"key": "area", "name": "地区", "value": [
{"n": "全部", "v": ""},
{"n": "大陆", "v": "大陆"},
{"n": "香港", "v": "香港"},
{"n": "台湾", "v": "台湾"},
{"n": "美国", "v": "美国"},
{"n": "日本", "v": "日本"},
{"n": "韩国", "v": "韩国"},
{"n": "英国", "v": "英国"},
]},
{"key": "year", "name": "年份", "value": [
{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
{"n": "2023", "v": "2023"},
{"n": "2022", "v": "2022"},
]},
]
filters["30"] = [
{"key": "area", "name": "地区", "value": [
{"n": "全部", "v": ""},
{"n": "大陆", "v": "大陆"},
{"n": "日本", "v": "日本"},
{"n": "美国", "v": "美国"},
]},
{"key": "year", "name": "年份", "value": [
{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
]},
]
filters["24"] = [
{"key": "year", "name": "年份", "value": [
{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
]},
]
filters["63"] = [
{"key": "year", "name": "年份", "value": [
{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
{"n": "2024", "v": "2024"},
]},
]
filters["47"] = [
{"key": "year", "name": "年份", "value": [
{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
]},
]
filters["60"] = [
{"key": "year", "name": "年份", "value": [
{"n": "全部", "v": ""},
{"n": "2026", "v": "2026"},
{"n": "2025", "v": "2025"},
]},
]
result['filters'] = filters
rsp = self.fetch(self.host, headers=self.headers)
html = rsp.text
vlist = []
pattern = r'<a[^>]*href="([^"]+)"[^>]*class="[^"]*module-poster-item[^"]*"[^>]*>(.*?)</a>'
items = re.findall(pattern, html, re.DOTALL)
for href, item_html in items:
title_match = re.search(r'<div[^>]*class="[^"]*module-poster-item-title[^"]*"[^>]*>([^<]*)</div>', item_html)
title = title_match.group(1).strip() if title_match else ''
note_match = re.search(r'<div[^>]*class="[^"]*module-item-note[^"]*"[^>]*>([^<]*)</div>', item_html)
note = note_match.group(1).strip() if note_match else ''
pic_match = re.search(r'<img[^>]*data-original="([^"]+)"[^>]*>', item_html)
pic = pic_match.group(1) if pic_match else ''
if not pic:
pic_match = re.search(r'<img[^>]*src="([^"]+)"[^>]*>', item_html)
pic = pic_match.group(1) if pic_match else ''
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if href and not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
if title:
vlist.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': note
})
result['class'] = classes
result['list'] = vlist[:30]
return result
def homeVideoContent(self):
return {}
def categoryContent(self, tid, pg, filter, extend):
page = int(pg) if pg else 1
class_val = extend.get('class', '') if extend else ''
area_val = extend.get('area', '') if extend else ''
year_val = extend.get('year', '') if extend else ''
if page == 1:
if class_val and not area_val and not year_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/class/{class_val}.html"
elif area_val and not class_val and not year_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/area/{area_val}.html"
elif year_val and not class_val and not area_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/year/{year_val}.html"
elif class_val and area_val and not year_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/class/{class_val}/area/{area_val}.html"
elif class_val and year_val and not area_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/class/{class_val}/year/{year_val}.html"
elif area_val and year_val and not class_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/area/{area_val}/year/{year_val}.html"
else:
url = f"{self.host}/index.php/vod/show/id/{tid}.html"
else:
if class_val and not area_val and not year_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/class/{class_val}/page/{page}.html"
elif area_val and not class_val and not year_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/area/{area_val}/page/{page}.html"
elif year_val and not class_val and not area_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/year/{year_val}/page/{page}.html"
elif class_val and area_val and not year_val:
url = f"{self.host}/index.php/vod/show/id/{tid}/class/{class_val}/area/{area_val}/page/{page}.html"
else:
url = f"{self.host}/index.php/vod/show/id/{tid}/page/{page}.html"
rsp = self.fetch(url, headers=self.headers)
html = rsp.text
videos = []
pattern = r'<a[^>]*href="([^"]+)"[^>]*class="[^"]*module-poster-item[^"]*"[^>]*>(.*?)</a>'
items = re.findall(pattern, html, re.DOTALL)
for href, item_html in items:
title_match = re.search(r'<div[^>]*class="[^"]*module-poster-item-title[^"]*"[^>]*>([^<]*)</div>', item_html)
title = title_match.group(1).strip() if title_match else ''
note_match = re.search(r'<div[^>]*class="[^"]*module-item-note[^"]*"[^>]*>([^<]*)</div>', item_html)
note = note_match.group(1).strip() if note_match else ''
pic_match = re.search(r'<img[^>]*data-original="([^"]+)"[^>]*>', item_html)
pic = pic_match.group(1) if pic_match else ''
if not pic:
pic_match = re.search(r'<img[^>]*src="([^"]+)"[^>]*>', item_html)
pic = pic_match.group(1) if pic_match else ''
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if href and not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
if title:
videos.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': note
})
pagecount = 1
page_pattern = r'<a[^>]*class="[^"]*page-link[^"]*"[^>]*>(\d+)</a>'
page_matches = re.findall(page_pattern, html)
for p in page_matches:
if p.isdigit() and int(p) > pagecount:
pagecount = int(p)
result = {
'list': videos,
'page': page,
'pagecount': pagecount,
'limit': 90,
'total': 999999
}
return result
def detailContent(self, ids):
vid = ids[0]
if not vid.startswith('http'):
url = self.host + vid if vid.startswith('/') else self.host + '/' + vid
else:
url = vid
rsp = self.fetch(url, headers=self.headers)
html = rsp.text
info = {'vod_id': vid}
title_match = re.search(r'<h1[^>]*>([^<]+)</h1>', html)
if title_match:
info['vod_name'] = title_match.group(1).strip()
else:
title_match = re.search(r'<title>([^<]+)</title>', html)
if title_match:
info['vod_name'] = title_match.group(1).split('-')[0].strip()
pic_match = re.search(r'<img[^>]*data-original="([^"]+)"[^>]*class="[^"]*lazy[^"]*"[^>]*alt="[^"]*"[^>]*>', html)
if not pic_match:
pic_match = re.search(r'<img[^>]*src="([^"]+)"[^>]*class="[^"]*lazy[^"]*"[^>]*alt="[^"]*"[^>]*>', html)
if not pic_match:
pic_match = re.search(r'<div[^>]*class="[^"]*module-item-pic[^"]*"[^>]*>.*?<img[^>]*src="([^"]+)"', html, re.DOTALL)
if pic_match:
pic = pic_match.group(1)
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
info['vod_pic'] = pic
desc_match = re.search(r'<div[^>]*class="[^"]*module-info-introduction-content[^"]*"[^>]*>(.*?)</div>', html, re.DOTALL)
if desc_match:
info['vod_content'] = re.sub(r'<[^>]+>', '', desc_match.group(1)).strip()
info_items = re.findall(r'<div[^>]*class="[^"]*module-info-item[^"]*"[^>]*>.*?<span[^>]*class="[^"]*module-info-item-title[^"]*"[^>]*>([^<]*)</span>.*?<div[^>]*class="[^"]*module-info-item-content[^"]*"[^>]*>(.*?)</div>', html, re.DOTALL)
for title, value in info_items:
title = title.strip().replace('', '').replace(':', '')
value = re.sub(r'<[^>]+>', '', value).strip()
if '导演' in title:
info['vod_director'] = value
elif '主演' in title:
info['vod_actor'] = value
elif '集数' in title or '更新' in title:
info['vod_remarks'] = value
elif '年份' in title or '上映' in title:
info['vod_year'] = value
vod_id = None
player_match = re.search(r'var player_aaaa\s*=\s*({[^;]+})', html)
if player_match:
try:
player_data = json.loads(player_match.group(1))
if player_data.get('id'):
vod_id = player_data['id']
except:
pass
if not vod_id:
vod_match = re.search(r'/detail/(\d+)\.html', url)
if vod_match:
vod_id = vod_match.group(1)
else:
vod_match = re.search(r'/play/(\d+)-\d+-\d+\.html', url)
if vod_match:
vod_id = vod_match.group(1)
tabs = []
tab_pattern1 = r'<(?:div|a)[^>]*class="[^"]*module-tab-item[^"]*"[^>]*>.*?<span>([^<]+)</span>'
tabs = re.findall(tab_pattern1, html, re.DOTALL)
tabs = list(dict.fromkeys(tabs))
if not tabs:
tab_pattern2 = r'<span[^>]*class="[^"]*module-tab-value[^"]*"[^>]*>([^<]*)</span>'
tabs = re.findall(tab_pattern2, html)
tabs = list(dict.fromkeys(tabs))
if not tabs:
tab_pattern3 = r'选择播放源\s*([^<]+)'
tabs = re.findall(tab_pattern3, html)
tabs = list(dict.fromkeys(tabs))
if not tabs:
tabs = ['高清']
play_items = []
container_pattern = r'<div[^>]*class="[^"]*module-play-list[^"]*"[^>]*>(.*?)</div>'
containers = re.findall(container_pattern, html, re.DOTALL)
for container in containers:
link_pattern = r'<a[^>]*href="([^"]+)"[^>]*>(.*?)</a>'
links = re.findall(link_pattern, container, re.DOTALL)
for href, title in links:
title = re.sub(r'<[^>]+>', '', title).strip()
if not title:
title = '播放'
if href.startswith('/'):
href = self.host + href
if href not in [item.split('$')[-1] for item in play_items]:
play_items.append(f'{title}${href}')
if not play_items and vod_id:
for idx, tab_name in enumerate(tabs):
sid = idx + 1
total = 40
total_match = re.search(r'<small>(\d+)</small>', html)
if total_match:
total = int(total_match.group(1))
episodes = []
for nid in range(1, total + 1):
ep_name = f"{nid}"
ep_url = f"{self.host}/play/{vod_id}-{sid}-{nid}.html"
episodes.append(f'{ep_name}${ep_url}')
if episodes:
play_items.extend(episodes)
ktabs = []
klists = []
if play_items:
if len(tabs) == 1:
ktabs = tabs
klists = ['#'.join(play_items)]
else:
items_per_tab = max(1, len(play_items) // len(tabs))
for i in range(len(tabs)):
start = i * items_per_tab
end = start + items_per_tab if i < len(tabs) - 1 else len(play_items)
if start < len(play_items):
ktabs.append(tabs[i])
klists.append('#'.join(play_items[start:end]))
if not ktabs:
link_pattern = r'<a[^>]*class="[^"]*module-play-list-link[^"]*"[^>]*href="([^"]+)"[^>]*>([^<]+)</a>'
links = re.findall(link_pattern, html)
if links:
episodes = []
for href, title in links:
if href and not href.startswith('#'):
if not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
episodes.append(f'{title}${href}')
if episodes:
ktabs.append("播放")
klists.append('#'.join(episodes))
info["vod_play_from"] = '$$$'.join(ktabs) if ktabs else "初见影视"
info["vod_play_url"] = '$$$'.join(klists) if klists else ""
return {'list': [info]}
def searchContent(self, key, quick, pg="1"):
page = int(pg) if pg else 1
encoded_key = urllib.parse.quote(key, safe='')
url = f"{self.host}/index.php/vod/search.html?wd={encoded_key}&page={page}"
rsp = self.fetch(url, headers=self.headers)
html = rsp.text
videos = []
card_pattern = r'<div class="module-card-item[^"]*"[^>]*>(.*?)</div>\s*</div>\s*</div>'
cards = re.findall(card_pattern, html, re.DOTALL)
if not cards:
card_pattern = r'<div class="module-card-item[^"]*"[^>]*>(.*?)</div>'
temp_cards = re.findall(card_pattern, html, re.DOTALL)
cards = [c for c in temp_cards if len(c) > 100]
for card_html in cards:
href_match = re.search(r'<a[^>]*href="([^"]+)"[^>]*class="[^"]*module-card-item-poster[^"]*"[^>]*>', card_html)
if not href_match:
href_match = re.search(r'<a[^>]*href="([^"]+)"[^>]*>.*?<div class="module-card-item-title', card_html, re.DOTALL)
if not href_match:
href_match = re.search(r'<a[^>]*href="([^"]+)"[^>]*>', card_html)
href = href_match.group(1) if href_match else ''
title_match = re.search(r'<div class="module-card-item-title">.*?<a[^>]*>.*?<strong>([^<]+)</strong>', card_html, re.DOTALL)
if not title_match:
title_match = re.search(r'<strong>([^<]+)</strong>', card_html)
if not title_match:
title_match = re.search(r'<div class="module-card-item-title">.*?<a[^>]*>([^<]+)</a>', card_html, re.DOTALL)
title = title_match.group(1).strip() if title_match else ''
note_match = re.search(r'<div class="module-item-note">([^<]*)</div>', card_html)
note = note_match.group(1).strip() if note_match else ''
pic_match = re.search(r'<img[^>]*data-original="([^"]+)"[^>]*>', card_html)
if not pic_match:
pic_match = re.search(r'<img[^>]*src="([^"]+)"[^>]*>', card_html)
pic = pic_match.group(1) if pic_match else ''
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if href and not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
if title:
videos.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': note
})
if not videos:
try:
from pyquery import PyQuery as pq
data = pq(html)
for item in data('.module-card-item').items():
href = item('a.module-card-item-poster').attr('href') or ''
title = item('.module-card-item-title strong').text() or ''
note = item('.module-item-note').text() or ''
pic = item('img').attr('data-original') or ''
if title:
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if href and not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
videos.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': note
})
except:
pass
return {
'list': videos,
'page': page,
'pagecount': 9999,
'limit': 90,
'total': 999999
}
# ============================================================
# 使用爱豆儿解析接口
# ============================================================
def playerContent(self, flag, id, vipFlags):
if id.startswith('http'):
play_url = id
else:
play_url = self.host + id if id.startswith('/') else self.host + '/' + id
rsp = self.fetch(play_url, headers=self.headers)
html = rsp.text
real_url = play_url
# ====== 从 player_aaaa 提取 ======
player_match = re.search(r'var player_aaaa\s*=\s*({[^;]+})', html)
if player_match:
try:
player_data = json.loads(player_match.group(1))
if player_data.get('url'):
real_url = player_data['url'].replace('\\/', '/')
if real_url.startswith('//'):
real_url = 'https:' + real_url
except:
pass
# ====== 从 iframe 提取 ======
iframe_match = re.search(r'<iframe[^>]*src="([^"]+)"[^>]*>', html)
if iframe_match:
real_url = iframe_match.group(1)
if real_url.startswith('//'):
real_url = 'https:' + real_url
if real_url.startswith('/'):
real_url = self.host + real_url
# ====== 判断URL类型 ======
# 如果是m3u8/mp4,直接播放
if '.m3u8' in real_url or '.mp4' in real_url:
return {'parse': 0, 'url': real_url, 'header': self.headers}
# ====== 如果是第三方网站,使用爱豆儿解析 ======
need_parse = False
parse_keywords = [
'iqiyi.com', 'bilibili.com', 'v.qq.com', 'youku.com',
'qq.com', 'mgtv.com', 'sohu.com', 'le.com', 'pptv.com',
'爱奇艺', '腾讯', '优酷', '芒果', '乐视', '哔哩'
]
for keyword in parse_keywords:
if keyword in real_url:
need_parse = True
break
if need_parse:
parse_url = self.PARSE_API + urllib.parse.quote(real_url)
parse_headers = self.headers.copy()
parse_headers['Referer'] = 'https://jx.aidouer.net'
return {
'parse': 0,
'url': parse_url,
'header': parse_headers
}
return {'parse': 0, 'url': real_url, 'header': self.headers}
def localProxy(self, param):
return None
+443
View File
@@ -0,0 +1,443 @@
# -*- coding: utf-8 -*-
# 少货影视 - TVbox标准版
import re
import sys
import json
import urllib.parse
import urllib.request
import ssl
import http.cookiejar
sys.path.append('..')
from base.spider import Spider
ssl._create_default_https_context = ssl._create_unverified_context
class Spider(Spider):
def init(self, extend=""):
self.extend = extend
self.host = 'https://shdy3.com'
self.cookie_jar = http.cookiejar.CookieJar()
self.cookie_handler = urllib.request.HTTPCookieProcessor(self.cookie_jar)
self.opener = urllib.request.build_opener(self.cookie_handler)
self.fetch(self.host)
def getName(self):
return "少货影视"
def isVideoFormat(self, url):
return False
def manualVideoCheck(self):
return False
def destroy(self):
pass
headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 9; ALN-AL00 Build/PQ3B.190801.05281406; wv) AppleWebKit/537.36',
'accept-language': 'zh-CN,zh;q=0.9',
'Referer': 'https://shdy3.com/',
}
classes_config = [
("电影", "1"),
("电视剧", "2"),
("动漫", "4"),
]
def fetch(self, url):
try:
req = urllib.request.Request(url, headers=self.headers)
with self.opener.open(req, timeout=15) as response:
content = response.read()
try:
return content.decode('utf-8')
except:
return content.decode('gbk', errors='ignore')
except Exception as e:
print(f"请求失败: {e}")
return ''
def clean_html(self, text):
if not text:
return ''
text = re.sub(r'<[^>]+>', '', text)
text = re.sub(r'\s+', ' ', text)
return text.strip()
# ==================== 首页 ====================
def homeContent(self, filter):
result = {}
classes = []
for name, tid in self.classes_config:
classes.append({"type_name": name, "type_id": tid})
filters = {
"1": [{"key": "cateId", "name": "类型", "value": [
{"n": "全部", "v": "1"},
{"n": "喜剧", "v": "6"},
{"n": "爱情", "v": "7"},
{"n": "恐怖", "v": "8"},
{"n": "动作", "v": "9"},
{"n": "科幻", "v": "10"},
{"n": "战争", "v": "11"},
{"n": "犯罪", "v": "12"},
{"n": "动画", "v": "13"},
{"n": "奇幻", "v": "14"},
{"n": "剧情", "v": "15"},
{"n": "冒险", "v": "16"},
{"n": "悬疑", "v": "17"},
{"n": "惊悚", "v": "18"},
{"n": "其他", "v": "20"},
]}],
"2": [{"key": "cateId", "name": "类型", "value": [
{"n": "全部", "v": "2"},
{"n": "国产剧", "v": "20"},
{"n": "TVB", "v": "21"},
{"n": "韩剧", "v": "22"},
{"n": "美剧", "v": "23"},
{"n": "日剧", "v": "24"},
{"n": "英剧", "v": "25"},
{"n": "台剧", "v": "26"},
{"n": "其他", "v": "27"},
]}],
}
result['filters'] = filters
html = self.fetch(self.host)
vlist = []
if html:
items = re.findall(
r'<a[^>]*class="myui-vodlist__thumb[^"]*"[^>]*href="([^"]+)"[^>]*title="([^"]+)"[^>]*data-original="([^"]+)"[^>]*>.*?<span[^>]*class="pic-text[^"]*"[^>]*>(.*?)</span>',
html, re.DOTALL
)
for href, title, pic, remark in items[:12]:
if href and title:
if not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if pic and pic.startswith('//'):
pic = 'https:' + pic
vlist.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': self.clean_html(remark)
})
result['class'] = classes
result['list'] = vlist
return result
def homeVideoContent(self):
return {}
# ==================== 分类 ====================
def categoryContent(self, tid, pg, filter, extend):
page = int(pg) if pg else 1
if extend and 'cateId' in extend:
cateId = extend.get('cateId')
else:
cateId = tid
if page <= 1:
url = f"{self.host}/list/{cateId}.html"
else:
url = f"{self.host}/list/{cateId}-{page}.html"
html = self.fetch(url)
if not html:
return {'list': [], 'page': page, 'pagecount': 1}
videos = []
items = re.findall(
r'<div class="v_img">.*?<a href="([^"]+)" title="([^"]+)">.*?<img[^>]*data-original="([^"]+)".*?<div class="v_note">(.*?)</div>',
html, re.DOTALL
)
for href, title, pic, remark in items:
if href and title:
if not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if pic and pic.startswith('//'):
pic = 'https:' + pic
videos.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': self.clean_html(remark)
})
if not videos:
items2 = re.findall(
r'<a href="(/movie/[^"]+)" title="([^"]+)">.*?<img[^>]*data-original="([^"]+)"',
html, re.DOTALL
)
for href, title, pic in items2:
if href and title:
href = self.host + href if href.startswith('/') else self.host + '/' + href
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if pic and pic.startswith('//'):
pic = 'https:' + pic
videos.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': ''
})
pagecount = page
page_match = re.search(r'<span>\d+/(\d+)</span>', html)
if page_match:
pagecount = int(page_match.group(1))
else:
if re.search(r'<a[^>]*href="[^"]*-\d+\.html"[^>]*>下一页</a>', html):
pagecount = page + 1
else:
pagecount = page
return {
'list': videos,
'page': page,
'pagecount': pagecount,
'limit': len(videos),
'total': pagecount * len(videos) if videos else 999999
}
# ==================== 详情 ====================
def detailContent(self, ids):
vid = ids[0] if ids else ''
if not vid:
return {'list': []}
if not vid.startswith('http'):
vid = self.host + vid if vid.startswith('/') else self.host + '/' + vid
html = self.fetch(vid)
if not html:
return {'list': []}
info = {'vod_id': vid}
# ====== 标题 ======
title_match = re.search(r'<h1[^>]*class="v_title[^"]*"[^>]*>(.*?)</h1>', html, re.DOTALL)
info['vod_name'] = self.clean_html(title_match.group(1)) if title_match else '未知'
# ====== 海报 ======
pic_match = re.search(r'<img[^>]*class="lazyload"[^>]*data-original="([^"]+)"', html)
if pic_match:
pic = pic_match.group(1)
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if pic and pic.startswith('//'):
pic = 'https:' + pic
info['vod_pic'] = pic
else:
info['vod_pic'] = ''
# ====== 简介 ======
desc_match = re.search(r'<p[^>]*class="p_txt[^"]*"[^>]*>(.*?)</p>', html, re.DOTALL)
info['vod_content'] = self.clean_html(desc_match.group(1)) if desc_match else ''
# ====== 导演、演员、年份、类型、地区 ======
info['vod_director'] = ''
info['vod_actor'] = ''
info['vod_year'] = ''
info['type_name'] = ''
info['vod_area'] = ''
info_p = re.search(r'<p>(.*?)</p>', html, re.DOTALL)
if info_p:
text = info_p.group(1)
# 去除<a>标签
text = re.sub(r'<a[^>]*>.*?</a>', '', text)
text = self.clean_html(text)
# 用 / 分割
parts = text.split('/')
for part in parts:
part = part.strip()
if not part:
continue
# 导演
if '导演:' in part:
info['vod_director'] = part.replace('导演:', '').strip()
# 主演
elif '主演:' in part:
info['vod_actor'] = part.replace('主演:', '').strip()
# 如果只有纯文本且没有冒号
elif ':' not in part:
if re.match(r'^\d{4}$', part):
info['vod_year'] = part
elif part in ['大陆', '美国', '日本', '韩国', '英国', '法国', '德国', '意大利', '西班牙', '加拿大', '澳大利亚', '台湾', '香港', '泰国', '印度', '其他']:
info['vod_area'] = part
else:
info['type_name'] = part
# 如果没提取到年份,从其他地方匹配
if not info['vod_year']:
year_match = re.search(r'(\d{4})</a>', html)
if year_match:
info['vod_year'] = year_match.group(1)
# ====== 播放列表 ======
play_from = []
play_url = []
from_match = re.search(r'<ul[^>]*class="from_list"[^>]*>(.*?)</ul>', html, re.DOTALL)
link_match = re.search(r'<ul[^>]*class="play_list"[^>]*id="play_link"[^>]*>(.*?)</ul>', html, re.DOTALL)
if from_match and link_match:
names = re.findall(r'<li[^>]*>(.*?)</li>', from_match.group(1), re.DOTALL)
names = [self.clean_html(n) for n in names if n.strip()]
link_blocks = re.findall(r'<li[^>]*>(.*?)</li>', link_match.group(1), re.DOTALL)
if names and link_blocks and len(names) == len(link_blocks):
for idx, block in enumerate(link_blocks):
eps = re.findall(r'<a[^>]*href="([^"]+)"[^>]*>(.*?)</a>', block, re.DOTALL)
source_name = names[idx] if idx < len(names) else f"线路{idx+1}"
episodes = []
for ep_href, ep_name in eps:
ep_name = ep_name.strip()
if ep_name and ep_href:
if not ep_href.startswith('/'):
ep_href = '/' + ep_href
num = re.sub(r'[^0-9]', '', ep_name)
if num:
num = int(num)
else:
num = len(episodes) + 1
episodes.append((num, f'{ep_name}${ep_href}'))
if episodes:
episodes.sort(key=lambda x: x[0])
play_from.append(source_name)
play_url.append('#'.join([ep[1] for ep in episodes]))
if not play_from:
panels = re.findall(
r'<div[^>]*class="myui-panel_bd[^"]*"[^>]*>.*?<ul[^>]*class="myui-content__list[^"]*"[^>]*>(.*?)</ul>',
html, re.DOTALL
)
titles = re.findall(r'<h3[^>]*class="title"[^>]*>(.*?)</h3>', html)
if panels:
for idx, panel in enumerate(panels):
eps = re.findall(r'<a[^>]*href="([^"]+)"[^>]*>(.*?)</a>', panel, re.DOTALL)
source_name = titles[idx] if idx < len(titles) else f"线路{idx+1}"
episodes = []
for ep_href, ep_name in eps:
ep_name = ep_name.strip()
if ep_name and ep_href:
if not ep_href.startswith('/'):
ep_href = '/' + ep_href
num = re.sub(r'[^0-9]', '', ep_name)
if num:
num = int(num)
else:
num = len(episodes) + 1
episodes.append((num, f'{ep_name}${ep_href}'))
if episodes:
episodes.sort(key=lambda x: x[0])
play_from.append(source_name)
play_url.append('#'.join([ep[1] for ep in episodes]))
if not play_from:
all_eps = re.findall(r'<a[^>]*href="(/play/[^"]+)"[^>]*>([^<]+)</a>', html, re.DOTALL)
if all_eps:
episodes = []
for ep_href, ep_name in all_eps:
ep_name = ep_name.strip()
if ep_name and ep_href:
if not ep_href.startswith('/'):
ep_href = '/' + ep_href
num = re.sub(r'[^0-9]', '', ep_name)
if num:
num = int(num)
else:
num = len(episodes) + 1
episodes.append((num, f'{ep_name}${ep_href}'))
if episodes:
episodes.sort(key=lambda x: x[0])
play_from.append("骚火影视")
play_url.append('#'.join([ep[1] for ep in episodes]))
info["vod_play_from"] = '$$$'.join(play_from) if play_from else "骚火影视"
info["vod_play_url"] = '$$$'.join(play_url) if play_url else ""
return {'list': [info]}
# ==================== 搜索 ====================
def searchContent(self, key, quick, pg="1"):
page = int(pg) if pg else 1
encoded_key = urllib.parse.quote(key, safe='')
url = f"{self.host}/s----------.html?wd={encoded_key}"
html = self.fetch(url)
if not html:
return {'list': [], 'page': page, 'pagecount': 0, 'limit': 90, 'total': 0}
videos = []
li_pattern = r'<li[^>]*class="clearfix"[^>]*>(.*?)</li>'
items = re.findall(li_pattern, html, re.DOTALL)
for item in items:
pic = ''
pic_match = re.search(r'data-original="([^"]+)"', item)
if pic_match:
pic = pic_match.group(1)
title_match = re.search(r'<a[^>]*href="([^"]+)"[^>]*title="([^"]+)"', item)
if not title_match:
continue
href = title_match.group(1)
title = title_match.group(2).strip()
remark = ''
remark_match = re.search(r'<span[^>]*class="pic-text[^"]*"[^>]*>(.*?)</span>', item)
if remark_match:
remark = self.clean_html(remark_match.group(1))
if href and title:
if not href.startswith('http'):
href = self.host + href if href.startswith('/') else self.host + '/' + href
if pic and not pic.startswith('http'):
pic = self.host + pic if pic.startswith('/') else self.host + '/' + pic
if pic and pic.startswith('//'):
pic = 'https:' + pic
videos.append({
'vod_id': href,
'vod_name': title,
'vod_pic': pic,
'vod_remarks': remark
})
return {'list': videos, 'page': page, 'pagecount': 999, 'limit': 90, 'total': 999999}
# ==================== 播放 ====================
def playerContent(self, flag, id, vipFlags):
"""
播放接口 - 完全模仿JS版本的play函数
"""
if id.startswith('http'):
final_url = id
else:
if id.startswith('/'):
final_url = self.host.rstrip('/') + id
else:
final_url = self.host.rstrip('/') + '/' + id
return {"parse": 1, "url": final_url, "jx": 0}
def localProxy(self, param):
return None