117 lines
7.1 KiB
Python
117 lines
7.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
import json
|
|
import re
|
|
from urllib.parse import quote, urljoin
|
|
|
|
import requests
|
|
from lxml import etree
|
|
from base.spider import Spider
|
|
|
|
|
|
class Spider(Spider):
|
|
def getName(self): return "Gimy影视"
|
|
|
|
def init(self, extend=""):
|
|
self.host = "https://gimytv.biz"
|
|
self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": self.host + "/"}
|
|
self.classes = [{"type_id": "2", "type_name": "电视剧"}, {"type_id": "4", "type_name": "动漫"}, {"type_id": "3", "type_name": "综艺"}, {"type_id": "1", "type_name": "电影"}, {"type_id": "25", "type_name": "短剧"}]
|
|
subtypes = {
|
|
"1": [("全部", "1"), ("动作片", "6"), ("喜剧片", "7"), ("爱情片", "8"), ("科幻片", "9"), ("恐怖片", "10"), ("剧情片", "11"), ("战争片", "12"), ("动画电影", "24")],
|
|
"2": [("全部", "2"), ("陆剧", "13"), ("短剧", "25"), ("韩剧", "15"), ("美剧", "16"), ("日剧", "20"), ("台剧", "14"), ("海外剧", "21"), ("港剧", "22"), ("纪录片", "23")],
|
|
"3": [("全部", "3")], "4": [("全部", "4")], "25": [("全部", "25")]
|
|
}
|
|
years = [{"n": "全部", "v": ""}] + [{"n": str(x), "v": str(x)} for x in range(2026, 2015, -1)]
|
|
sorts = [{"n": "最新更新", "v": "time"}, {"n": "最新上架", "v": "time_add"}, {"n": "周人气", "v": "hits_week"}, {"n": "总人气", "v": "hits"}]
|
|
self.filters = {tid: [{"key": "type", "name": "类型", "value": [{"n": n, "v": v} for n, v in values]}, {"key": "year", "name": "年份", "value": years}, {"key": "by", "name": "排序", "value": sorts}] for tid, values in subtypes.items()}
|
|
|
|
def _get(self, url, sid=""):
|
|
try:
|
|
headers = dict(self.headers)
|
|
if sid: headers["Cookie"] = "sid=" + str(sid)
|
|
response = requests.get(url, headers=headers, timeout=15)
|
|
response.raise_for_status()
|
|
response.encoding = response.apparent_encoding or "utf-8"
|
|
return response.text
|
|
except Exception:
|
|
return ""
|
|
|
|
def _fix(self, url): return urljoin(self.host + "/", url or "")
|
|
|
|
def _parse_list(self, html):
|
|
if not html: return []
|
|
tree, result, seen = etree.HTML(html), [], set()
|
|
for node in tree.xpath('//a[contains(concat(" ",normalize-space(@class)," ")," video-pic ") and contains(@href,"/voddetail/")]'):
|
|
match = re.search(r"/voddetail/(\d+)\.html", node.get("href", ""))
|
|
if not match or match.group(1) in seen: continue
|
|
seen.add(match.group(1))
|
|
name = node.get("title") or "".join(node.xpath('.//img/@alt')).strip()
|
|
pic = node.get("data-original") or node.get("data-src") or node.get("data-lazyload") or "".join(node.xpath('.//img/@data-original | .//img/@data-src | .//img/@src'))
|
|
remark = "".join(node.xpath('.//*[contains(@class,"note")]//text()')).strip()
|
|
result.append({"vod_id": match.group(1), "vod_name": name.strip(), "vod_pic": self._fix(pic), "vod_remarks": remark})
|
|
return result
|
|
|
|
def _pagecount(self, tree, page):
|
|
values = [int(x) for x in tree.xpath('//a[contains(@href,"/vodshow/")]/@href') for x in re.findall(r"-(\d+)---", x)]
|
|
return max(values + [page])
|
|
|
|
def homeContent(self, filter): return {"class": self.classes, "list": self._parse_list(self._get(self.host + "/")), "filters": self.filters}
|
|
|
|
def categoryContent(self, tid, pg, filter, extend):
|
|
page, ext = max(1, int(pg or 1)), extend if isinstance(extend, dict) else {}
|
|
selected, year, by = str(ext.get("type") or tid), str(ext.get("year") or ""), str(ext.get("by") or "time")
|
|
url = f"{self.host}/vodshow/{selected}--{by}------{page}---{year}.html"
|
|
html = self._get(url)
|
|
tree = etree.HTML(html) if html else etree.HTML("<html/>")
|
|
videos = self._parse_list(html)
|
|
return {"page": page, "pagecount": self._pagecount(tree, page), "limit": len(videos), "total": self._pagecount(tree, page) * max(len(videos), 1), "list": videos}
|
|
|
|
def detailContent(self, ids):
|
|
result = []
|
|
for vid in ids:
|
|
html = self._get(f"{self.host}/voddetail/{vid}.html")
|
|
if not html: continue
|
|
tree = etree.HTML(html)
|
|
name = "".join(tree.xpath('//h1/text()')).strip() or "".join(tree.xpath('//h2/text()')).strip()
|
|
pic = "".join(tree.xpath('//meta[@property="og:image"]/@content | //div[contains(@class,"detail-pic")]//img/@data-original | //div[contains(@class,"detail-pic")]//img/@src'))
|
|
content = " ".join(x.strip() for x in tree.xpath('//span[contains(@class,"detail-intro")]//text() | //div[contains(@class,"details-content-all")]//text()') if x.strip())
|
|
sources, playlists = [], []
|
|
panels = tree.xpath('//div[contains(concat(" ",normalize-space(@class)," ")," playlist-mobile ")]')
|
|
for panel in panels:
|
|
episodes = panel.xpath('.//ul//a[contains(@href,"/video/")]')
|
|
if not episodes: continue
|
|
source = "".join(panel.xpath('./li[1]//text()')).strip() or "".join(panel.xpath('./span[1]//text()')).strip() or f"线路{len(sources) + 1}"
|
|
plays = []
|
|
for episode in episodes:
|
|
href = episode.get("href", "")
|
|
sid_match = re.search(r"sid=(\d+)", href)
|
|
onclick_match = re.search(r"changeSid\(['\"]?(\d+)", episode.get("onclick", ""))
|
|
sid = (onclick_match or sid_match).group(1) if onclick_match or sid_match else "1"
|
|
path = href.split("#", 1)[0]
|
|
label = "".join(episode.xpath(".//text()")).strip() or str(len(plays) + 1)
|
|
plays.append(f"{label}${path}@@{sid}")
|
|
sources.append(source)
|
|
playlists.append("#".join(plays))
|
|
result.append({"vod_id": str(vid), "vod_name": name, "vod_pic": self._fix(pic), "vod_content": content, "vod_play_from": "$$$".join(sources), "vod_play_url": "$$$".join(playlists)})
|
|
return {"list": result}
|
|
|
|
def searchContent(self, key, quick, pg="1"):
|
|
page = max(1, int(pg or 1))
|
|
url = f"{self.host}/vodsearch/-------------.html?wd={quote(key)}&page={page}"
|
|
return {"page": page, "pagecount": page, "list": self._parse_list(self._get(url))}
|
|
|
|
def playerContent(self, flag, id, vipFlags):
|
|
path, sid = (id.rsplit("@@", 1) + ["1"])[:2] if "@@" in id else (id, "1")
|
|
url = self._fix(path)
|
|
html = self._get(url, sid)
|
|
marker = "var player_aaaa="
|
|
if marker in html:
|
|
try:
|
|
data = json.JSONDecoder().raw_decode(html.split(marker, 1)[1])[0]
|
|
play_url = data.get("url", "")
|
|
if int(data.get("encrypt", 0)) == 1: play_url = quote(play_url, safe=":/?&=%")
|
|
if play_url and any(x in play_url.lower() for x in (".m3u8", ".mp4", ".flv")):
|
|
return {"parse": 0, "url": play_url, "header": {"User-Agent": self.headers["User-Agent"], "Referer": url}}
|
|
except Exception:
|
|
pass
|
|
return {"parse": 1, "url": url, "header": {**self.headers, "Cookie": "sid=" + sid}}
|