#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ video-capture · 取视频(最小、合规集) 只做两件事,用于把「一个视频」落到本地待抽帧: 1) 本地文件:直接登记(--file) 2) 直链媒体 URL:下载(--url,需 .mp4/.mov/.webm/.m4v 等直链) ⛔ 不做:平台页内抓取(抖音/B站/YouTube 等页面解析)、⛔ 不调任何付费接口。 —— 如需平台视频,请先用浏览器工具把视频下到本地,再用 --file 传入(本工具不代抓)。 依赖:ffprobe(校验)+ Python 标准库。可选 curl(更快)。 用法: python fetch_video.py --file D:/a.mp4 --out ./video python fetch_video.py --url https://host/x.mp4 --out ./video """ import argparse import json import os import shutil import subprocess import sys import urllib.request UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/126.0 Safari/537.36" def probe(path): try: r = subprocess.run( ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-show_entries", "stream=codec_type,width,height", "-of", "json", path], capture_output=True, text=True, encoding="utf-8", errors="replace") j = json.loads(r.stdout or "{}") dur = float((j.get("format") or {}).get("duration") or 0) w = h = 0 for s in (j.get("streams") or []): if s.get("codec_type") == "video": w, h = int(s.get("width") or 0), int(s.get("height") or 0) break return {"duration": round(dur, 3), "resolution": f"{w}x{h}"} except Exception: return {} def download(url, dest): req = urllib.request.Request(url, headers={"User-Agent": UA, "Referer": url}) with urllib.request.urlopen(req, timeout=90) as r, open(dest, "wb") as f: shutil.copyfileobj(r, f) def main(): ap = argparse.ArgumentParser() g = ap.add_mutually_exclusive_group(required=True) g.add_argument("--file", help="本地视频路径") g.add_argument("--url", help="直链媒体 URL(.mp4/.mov/.webm/.m4v)") ap.add_argument("--out", default="video", help="输出目录") args = ap.parse_args() os.makedirs(args.out, exist_ok=True) if args.file: if not os.path.exists(args.file): print(json.dumps({"ok": False, "error": f"找不到文件:{args.file}"}), file=sys.stderr) sys.exit(2) dest = os.path.join(args.out, os.path.basename(args.file)) if os.path.abspath(dest) != os.path.abspath(args.file): shutil.copy2(args.file, dest) else: if not os.path.splitext(args.url.split("?")[0])[1].lower() in (".mp4", ".mov", ".webm", ".m4v", ".mkv"): print(json.dumps({"ok": False, "error": "仅支持直链媒体 URL(.mp4/.mov/.webm/.m4v/.mkv);平台页内抓取不在本工具范围"}), file=sys.stderr) sys.exit(2) dest = os.path.join(args.out, "video" + os.path.splitext(args.url.split("?")[0])[1].lower()) try: download(args.url, dest) except Exception as e: print(json.dumps({"ok": False, "error": f"下载失败:{e}"}), file=sys.stderr) sys.exit(1) meta = probe(dest) print(json.dumps({"ok": True, "video": os.path.abspath(dest), **meta}, ensure_ascii=False, indent=2)) if __name__ == "__main__": main()