删除 py/西瓜影视.py
This commit is contained in:
-336
@@ -1,336 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# by @PyramidStore AutoGen
|
||||
import re
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
import json
|
||||
from urllib.parse import quote
|
||||
from base.spider import Spider
|
||||
|
||||
|
||||
class Spider(Spider):
|
||||
|
||||
def init(self, extend=""):
|
||||
self.nav_host = 'https://www.xiguadh.com'
|
||||
self.headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
|
||||
}
|
||||
self.host = self._get_host()
|
||||
|
||||
def _get_host(self):
|
||||
"""获取视频站点 URL,失败时从导航页获取"""
|
||||
default_host = 'https://www.bzzdyy.com'
|
||||
try:
|
||||
r = self.fetch(default_host, headers=self.headers, timeout=10, verify=False)
|
||||
if r.status_code == 200:
|
||||
return default_host
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
r = self.fetch(self.nav_host, headers=self.headers, timeout=15, verify=False)
|
||||
html = r.text
|
||||
urls = re.findall(r'url:\s*["\']([^"\']+)["\']', html)
|
||||
for url in urls:
|
||||
if url.startswith('http') and 'xiguadh' not in url:
|
||||
return url.rstrip('/')
|
||||
except Exception:
|
||||
pass
|
||||
return default_host
|
||||
|
||||
def getName(self):
|
||||
return '西瓜影院'
|
||||
|
||||
def isVideoFormat(self, url):
|
||||
return False
|
||||
|
||||
def manualVideoCheck(self):
|
||||
return True
|
||||
|
||||
def homeContent(self, filter):
|
||||
try:
|
||||
r = self.fetch(self.host, headers=self.headers, timeout=15, verify=False)
|
||||
html = r.text
|
||||
# 提取主要分类
|
||||
nav_match = re.search(r'<ul class="stui-header__menu">(.*?)</ul>', html, re.DOTALL)
|
||||
if nav_match:
|
||||
nav_html = nav_match.group(1)
|
||||
categories = re.findall(r'<li[^>]*><a href="/index.php/vod/type/id/(\d+)\.html">([^<]+)</a></li>', nav_html)
|
||||
else:
|
||||
categories = []
|
||||
seen = set()
|
||||
classes = []
|
||||
for tid, name in categories:
|
||||
if tid not in seen:
|
||||
seen.add(tid)
|
||||
classes.append({'type_name': name, 'type_id': tid})
|
||||
if not classes:
|
||||
raise Exception('No categories found')
|
||||
# 提取首页推荐视频
|
||||
videos = self._parse_vodlist(html)
|
||||
except Exception:
|
||||
classes = [
|
||||
{'type_name': '电影', 'type_id': '20'},
|
||||
{'type_name': '连续剧', 'type_id': '37'},
|
||||
{'type_name': '动漫', 'type_id': '43'},
|
||||
{'type_name': '综艺', 'type_id': '45'},
|
||||
{'type_name': 'B站', 'type_id': '47'},
|
||||
{'type_name': '人人专区', 'type_id': '60'},
|
||||
]
|
||||
videos = []
|
||||
return {"class": classes, "list": videos}
|
||||
|
||||
def _parse_vodlist(self, html):
|
||||
"""解析视频列表"""
|
||||
items = re.findall(
|
||||
r'<a class="stui-vodlist__thumb[^"]*"\s+href="([^"]+)"\s+title="([^"]*)"[^>]*data-original="([^"]*)"',
|
||||
html
|
||||
)
|
||||
videos = []
|
||||
for href, title, pic in items:
|
||||
vod_id = re.search(r'/id/(\d+)\.html', href)
|
||||
if vod_id:
|
||||
vod_id = vod_id.group(1)
|
||||
else:
|
||||
continue
|
||||
remark_match = re.search(r'<span class="pic-text text-right"><b>([^<]+)</b></span>',
|
||||
html[html.find(href):html.find(href)+500] if href in html else '')
|
||||
remark = remark_match.group(1) if remark_match else ''
|
||||
if pic.startswith('/'):
|
||||
pic = self.host + pic
|
||||
videos.append({
|
||||
'vod_id': vod_id,
|
||||
'vod_name': title,
|
||||
'vod_pic': pic,
|
||||
'vod_remarks': remark,
|
||||
})
|
||||
return videos
|
||||
|
||||
def homeVideoContent(self):
|
||||
return ''
|
||||
|
||||
def categoryContent(self, tid, pg, filter, extend):
|
||||
pg = int(pg)
|
||||
url = f'{self.host}/index.php/vod/type/id/{tid}/page/{pg}.html'
|
||||
try:
|
||||
r = self.fetch(url, headers=self.headers, timeout=15, verify=False)
|
||||
html = r.text
|
||||
items = re.findall(
|
||||
r'<a class="stui-vodlist__thumb[^"]*"\s+href="([^"]+)"\s+title="([^"]*)"[^>]*data-original="([^"]*)"',
|
||||
html
|
||||
)
|
||||
videos = []
|
||||
for href, title, pic in items:
|
||||
vod_id = re.search(r'/id/(\d+)\.html', href)
|
||||
if vod_id:
|
||||
vod_id = vod_id.group(1)
|
||||
else:
|
||||
continue
|
||||
remark_match = re.search(r'<span class="pic-text text-right"><b>([^<]+)</b></span>',
|
||||
html[html.find(href):html.find(href)+500] if href in html else '')
|
||||
remark = remark_match.group(1) if remark_match else ''
|
||||
if pic.startswith('/'):
|
||||
pic = self.host + pic
|
||||
videos.append({
|
||||
'vod_id': vod_id,
|
||||
'vod_name': title,
|
||||
'vod_pic': pic,
|
||||
'vod_remarks': remark,
|
||||
})
|
||||
return {
|
||||
"list": videos,
|
||||
"page": pg,
|
||||
"pagecount": 9999,
|
||||
"limit": 90,
|
||||
"total": len(videos),
|
||||
}
|
||||
except Exception as e:
|
||||
return {"list": [], "page": pg, "pagecount": 1, "limit": 90, "total": 0}
|
||||
|
||||
def detailContent(self, ids):
|
||||
try:
|
||||
vod_id = ids[0] if isinstance(ids, list) else ids
|
||||
url = f'{self.host}/index.php/vod/detail/id/{vod_id}.html'
|
||||
r = self.fetch(url, headers=self.headers, timeout=15, verify=False)
|
||||
html = r.text
|
||||
title_match = re.search(r'<h1 class="title">([^<]+)</h1>', html)
|
||||
title = title_match.group(1).strip() if title_match else ''
|
||||
self._vod_name = title
|
||||
pic_match = re.search(r'<img class="lazyload" data-original="([^"]*)"', html)
|
||||
pic = pic_match.group(1) if pic_match else ''
|
||||
if pic.startswith('/'):
|
||||
pic = self.host + pic
|
||||
info_match = re.search(r'类型:([^/]+)\s*/\s*地区:([^/]+)\s*/\s*年份:(\d+)', html)
|
||||
type_name = info_match.group(1).strip() if info_match else ''
|
||||
area = info_match.group(2).strip() if info_match else ''
|
||||
year = info_match.group(3) if info_match else ''
|
||||
remark_match = re.search(r'状态:<span[^>]*>([^<]+)</span>', html)
|
||||
remark = remark_match.group(1).strip() if remark_match else ''
|
||||
director_match = re.search(r'导演:(.*?)</p>', html, re.DOTALL)
|
||||
director = ''
|
||||
if director_match:
|
||||
director = re.sub(r'<[^>]+>', '', director_match.group(1)).strip()
|
||||
actor_match = re.search(r'主演:([^<]+)', html)
|
||||
actor = actor_match.group(1).strip() if actor_match else ''
|
||||
desc_match = re.search(r'<span class="detail-content"[^>]*>([^<]+)</span>', html)
|
||||
desc = desc_match.group(1).strip() if desc_match else ''
|
||||
play_from = []
|
||||
play_url = []
|
||||
source_tabs = re.findall(r'<li><a href="#playlist\d+"[^>]*>([^<]+)</a></li>', html)
|
||||
for idx, source_name in enumerate(source_tabs):
|
||||
source_id = idx + 1
|
||||
episodes_match = re.search(
|
||||
f'<div id="playlist{source_id}" class="tab-pane[^"]*"[^>]*>.*?<ul class="stui-content__playlist[^"]*"[^>]*>(.*?)</ul>',
|
||||
html, re.DOTALL
|
||||
)
|
||||
if episodes_match:
|
||||
episodes = re.findall(r'<a href="([^"]+)">([^<]+)</a>', episodes_match.group(1))
|
||||
episode_list = []
|
||||
for ep_url, ep_name in episodes:
|
||||
episode_list.append(f'{ep_name}${self.host}{ep_url}')
|
||||
play_from.append(source_name)
|
||||
play_url.append('#'.join(episode_list))
|
||||
vod_play_from = '$$$'.join(play_from) if play_from else '默认'
|
||||
vod_play_url = '$$$'.join(play_url) if play_url else ''
|
||||
vod = {
|
||||
'vod_id': vod_id,
|
||||
'vod_name': title,
|
||||
'vod_pic': pic,
|
||||
'vod_year': year,
|
||||
'vod_area': area,
|
||||
'vod_remarks': remark,
|
||||
'vod_director': director,
|
||||
'vod_actor': actor,
|
||||
'vod_content': desc,
|
||||
'vod_play_from': vod_play_from,
|
||||
'vod_play_url': vod_play_url,
|
||||
}
|
||||
return {"list": [vod]}
|
||||
except Exception as e:
|
||||
return {"list": []}
|
||||
|
||||
def searchContent(self, key, quick, pg="1"):
|
||||
pg = int(pg)
|
||||
url = f'{self.host}/index.php/vod/search/wd/{quote(key)}.html'
|
||||
try:
|
||||
r = self.fetch(url, headers=self.headers, timeout=15, verify=False)
|
||||
html = r.text
|
||||
items = re.findall(
|
||||
r'<a class="stui-vodlist__thumb[^"]*"\s+href="([^"]+)"\s+title="([^"]*)"[^>]*data-original="([^"]*)"',
|
||||
html
|
||||
)
|
||||
videos = []
|
||||
for href, title, pic in items:
|
||||
vod_id = re.search(r'/id/(\d+)\.html', href)
|
||||
if vod_id:
|
||||
vod_id = vod_id.group(1)
|
||||
else:
|
||||
continue
|
||||
remark_match = re.search(r'<span class="pic-text text-right"><b>([^<]+)</b></span>',
|
||||
html[html.find(href):html.find(href)+500] if href in html else '')
|
||||
remark = remark_match.group(1) if remark_match else ''
|
||||
if pic.startswith('/'):
|
||||
pic = self.host + pic
|
||||
videos.append({
|
||||
'vod_id': vod_id,
|
||||
'vod_name': title,
|
||||
'vod_pic': pic,
|
||||
'vod_remarks': remark,
|
||||
})
|
||||
return {
|
||||
"list": videos,
|
||||
"page": pg,
|
||||
"pagecount": 9999,
|
||||
"limit": 90,
|
||||
"total": len(videos),
|
||||
}
|
||||
except Exception as e:
|
||||
return {"list": [], "page": pg, "pagecount": 1, "limit": 90, "total": 0}
|
||||
|
||||
def _clean_vod_name(self, name):
|
||||
import re
|
||||
if not name:
|
||||
return ''
|
||||
cleaned = re.sub(r'第\s*\d+\s*[集話话章部期]', '', name)
|
||||
cleaned = re.sub(r'EP\s*\d+', '', cleaned, flags=re.IGNORECASE)
|
||||
cleaned = re.sub(r'全\d+集', '', cleaned)
|
||||
cleaned = re.sub(r'更新至\d+集', '', cleaned)
|
||||
cleaned = re.sub(r'\d+集全', '', cleaned)
|
||||
cleaned = re.sub(r'[((].*?[))]', '', cleaned)
|
||||
cleaned = re.sub(r'\s*-\s*.*$', '', cleaned)
|
||||
cleaned = re.sub(r'\s+', ' ', cleaned)
|
||||
cleaned = re.sub(r'^[\s\-_,.,。、]+|[\s\-_,.,。、]+$', '', cleaned)
|
||||
return cleaned.strip()
|
||||
|
||||
def _build_danmaku_url(self, vod_name, vod_index=''):
|
||||
import re
|
||||
idx = 0
|
||||
if vod_index:
|
||||
s = str(vod_index).strip()
|
||||
m = re.search(r'第\s*(\d+)\s*[集話话章部期]', s)
|
||||
if m:
|
||||
idx = int(m.group(1))
|
||||
else:
|
||||
m = re.search(r'(\d+)', s)
|
||||
if m:
|
||||
idx = int(m.group(1))
|
||||
cleaned_name = self._clean_vod_name(vod_name)
|
||||
params = []
|
||||
if cleaned_name:
|
||||
params.append(f'vodName={quote(cleaned_name)}')
|
||||
params.append(f'vodIndex={idx}')
|
||||
query = '&'.join(params)
|
||||
return f'http://127.0.0.1:9978/proxy?do=appdanmu&{query}'
|
||||
|
||||
def playerContent(self, flag, id, vipFlags):
|
||||
try:
|
||||
ep_name = ''
|
||||
vod_index = ''
|
||||
if '$' in id:
|
||||
parts = id.split('$', 1)
|
||||
ep_name = parts[0]
|
||||
url = parts[1] if len(parts) > 1 else ''
|
||||
else:
|
||||
url = id if id.startswith('http') else f'{self.host}{id}'
|
||||
# 从 URL 中提取集数 (nid 参数)
|
||||
nid_match = re.search(r'nid/(\d+)\.html', url)
|
||||
if nid_match:
|
||||
vod_index = nid_match.group(1)
|
||||
danmaku_url = self._build_danmaku_url(self._vod_name, vod_index)
|
||||
r = self.fetch(url, headers=self.headers, timeout=15, verify=False)
|
||||
html = r.text
|
||||
iframe_match = re.search(r'<iframe[^>]+src="([^"]+)"', html)
|
||||
if iframe_match:
|
||||
iframe_url = iframe_match.group(1)
|
||||
if not iframe_url.startswith('http'):
|
||||
iframe_url = self.host + iframe_url
|
||||
return {
|
||||
"parse": 1,
|
||||
"url": iframe_url,
|
||||
"header": self.headers,
|
||||
"danmaku": danmaku_url
|
||||
}
|
||||
src_match = re.search(r'(https?://[^"\'<>\s]+\.m3u8[^"\'<>\s]*)', html)
|
||||
if src_match:
|
||||
return {
|
||||
"parse": 0,
|
||||
"url": src_match.group(1),
|
||||
"header": self.headers,
|
||||
"danmaku": danmaku_url
|
||||
}
|
||||
return {
|
||||
"parse": 1,
|
||||
"url": url,
|
||||
"header": self.headers,
|
||||
"danmaku": danmaku_url
|
||||
}
|
||||
except Exception as e:
|
||||
danmaku_url = self._build_danmaku_url(self._vod_name, '')
|
||||
return {"parse": 1, "url": id, "header": {}, "danmaku": danmaku_url}
|
||||
|
||||
def localProxy(self, param):
|
||||
return [200, {}, ""]
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
Reference in New Issue
Block a user