import requests
from bs4 import BeautifulSoup
import re,os,subprocess
from datetime import timedelta, date
import yt_dlp
from audioRead import *
from newsProcess import news_to_db
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def get_xwlb_video_link(url):
"""
从央视网新闻联播页面抓取历史完整版视频链接
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Referer': 'https://tv.cctv.com/'
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.encoding = 'utf-8'
if response.status_code != 200:
logger.error(f"请求失败,状态码: {response.status_code}")
#print(f"请求失败,状态码: {response.status_code}")
return []
except Exception as e:
logger.error(f"请求异常: {e}")
return []
soup = BeautifulSoup(response.text, 'html.parser')
video_links = []
# 查找所有包含“完整版《新闻联播》”的链接
# 方法1: 查找包含 完整版《新闻联播》 的 a 标签
for a_tag in soup.find_all('a', href=True):
# 检查文本中是否包含“完整版”和“新闻联播”
title_text = a_tag.get_text(strip=True)
inner_html = str(a_tag)
# 判断是否是“完整版《新闻联播》”的链接
if ('完整版' in title_text and '新闻联播' in title_text) or \
(re.search(r']*>完整版\s*《新闻联播》', inner_html)):
video_url = a_tag['href']
# 提取日期信息(从标题或链接中)
date_match = re.search(r'\d{8}', title_text)
if not date_match:
# 从链接中提取日期,如 /2025/09/25/...VID...250925.shtml
date_match = re.search(r'/(\d{4})/(\d{2})/(\d{2})/', video_url)
if date_match:
year, month, day = date_match.groups()
date_str = f"{year}{month}{day}"
else:
date_str = "未知日期"
else:
date_str = date_match.group()
video_links.append({
'date': date_str,
'title': title_text.strip(),
'url': video_url,
'page_url': url
})
logger.info(f"✅ 找到新闻联播完整版: {date_str} -> {video_url}")
return video_url
def xwlb_urls(start: str, end: str):
"""
start/end 格式 '20240925'
返回列表,如 ['https://tv.cctv.com/lm/xwlb/day/20240925.shtml', ...]
"""
d0 = date(int(start[:4]), int(start[4:6]), int(start[6:8]))
d1 = date(int(end[:4]), int(end[4:6]), int(end[6:8]))
urls = []
for n in range((d1 - d0).days + 1):
day = d0 + timedelta(days=n)
urls.append({"url": f"https://tv.cctv.com/lm/xwlb/day/{day:%Y%m%d}.shtml", "date": f"{day:%Y%m%d}"})
#print(urls)
return urls
def get_all_video_links(start: str, end: str):
base_urls=xwlb_urls(start,end)
#print(base_urls)
video_urls = []
for url in base_urls:
video=get_xwlb_video_link(url['url'])
video_urls.append({"url":video,"date":url['date']})
return video_urls
'''
get_xwlb_video_link() 方法获得的url,
urls like: https://tv.cctv.com/2024/10/30/VIDEUlPz1Qusy41JFQj3LMLd241030.shtml
通过yt-dlp下载视频,保存为mp4文件,并用ffmpeg提取音频为mp3文件,文件名使用url 的日期部分,如上面的url应保存为 20241030.mp4 和 20241030.mp3
文件保存路径为当前目录下的 xwlb_video 文件夹,若不存在则创建。
'''
def download_and_extract_audio(video_url,date_str,download_dir):
"""
使用yt-dlp下载视频并提取音频
"""
# 从URL中提取日期
os.makedirs(download_dir, exist_ok=True)
# 构建文件路径
mp4_path = os.path.join(download_dir, f"{date_str}.mp4")
mp3_path = os.path.join(download_dir, f"{date_str}.mp3")
try:
# 使用yt-dlp库下载视频
logger.info(f"📥 开始下载 {date_str} 的视频...")
# 配置yt-dlp选项
ydl_opts = {
'outtmpl': mp4_path,
'format': 'best[ext=mp4]/best',
'progress_hooks': [lambda d: print(f"\r📥 下载进度: {d.get('_percent_str', 'N/A').strip()} | {d.get('_speed_str', 'N/A').strip()} | 已下载: {d.get('_downloaded_bytes_str', 'N/A')}", end='') if d['status'] == 'downloading' else None],
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([video_url])
logger.info(f"📥 下载 {date_str} 完成")
# 使用ffmpeg提取音频
logger.info(f"🎵 开始提取 {date_str} 的音频...")
result = subprocess.run([
"ffmpeg",
"-i", mp4_path,
"-c:a", "libmp3lame", # 明确指定MP3编码器
"-q:a", "0",
"-map", "a",
mp3_path,
"-y" # 覆盖已存在文件
], check=True, stdout=None, stderr=None)
logger.info(f"🎵 提取 {date_str} 音频完成")
logger.info(f"✅ 成功处理 {date_str}: {mp4_path}, {mp3_path}")
except Exception as e:
logger.error(f"❌ 处理 {date_str} 时发生异常: {e}")
# 在get_all_video_links函数后添加调用代码
def process_videos(start_date, end_date):
"""
处理指定日期范围内的所有视频
"""
video_urls = get_all_video_links(start_date, end_date)
for sub_url in video_urls:
if sub_url: # 确保url不为空
"""
date_match = re.search(r'/(\d{4})/(\d{2})/(\d{2})/', url)
if not date_match:
print(f"❌ 无法从URL提取日期: {url}")
return
year, month, day = date_match.groups()
date_str = f"{year}{month}{day}"
"""
date_str= sub_url['date']
url = sub_url['url']
# 创建保存目录
download_dir = "/home/simon/myquant/djapi/api/video/xwlb_video"
download_and_extract_audio(url,date_str,download_dir)
print("=" * 80)
# MP3文件路径
mp3_path = os.path.join(download_dir, f"{date_str}.mp3")
# 分析提示词
# prompt = "请总结这段由中国中央电视台新闻联播音频转为文字的文本,理解其主要内容并提取其中的关键信息。"
# 输出文件夹
output_folder = "/home/simon/myquant/djapi/api/video/audio_processing"
# 处理长音频
try:
result = process_long_audio(mp3_path, output_folder,date_str)
news_to_db(date_str)
# 打印分析结果
print("分析结果:\n")
print(result)
except Exception as e:
print(f"处理失败: {e}")
print("=" * 80)
# ========================
# 主程序执行
# ========================
if __name__ == "__main__":
import sys
import re
from datetime import datetime
# 检查命令行参数
if len(sys.argv) < 2:
print("用法: python getVideo5.py ")
print("日期格式: YYYYMMDD")
sys.exit(1)
start_date = sys.argv[1]
end_date = sys.argv[2] if len(sys.argv) > 2 and sys.argv[2] else start_date
# 检查日期格式
date_pattern = r'^\d{8}$'
if not re.match(date_pattern, start_date) or not re.match(date_pattern, end_date):
print("错误: 日期格式必须为 YYYYMMDD")
sys.exit(1)
# 检查日期有效性
try:
#start_dt = datetime.strptime(start_date, '%Y%m%d')
#end_dt = datetime.strptime(end_date, '%Y%m%d')
if start_date > end_date:
print(f"错误: start_date {start_date} 不能大于 end_date {end_date}")
sys.exit(1)
print("正在抓取央视《新闻联播》历史完整版视频链接...")
print("=" * 80)
process_videos(start_date, end_date)
exit()
except ValueError as e:
print(f"错误: 无效日期 - {e}")
sys.exit(1)