import requests
import re
from lxml import etree
import os

class BiliBiliDanMu:
    def __init__(self, bv, filename):
        # 自动处理 BV 号，确保没有重复的 "BV" 前缀
        if bv.startswith("BV"):
            bv = bv[2:]
        # 根据 bv 号构造要爬取的视频 URL 地址
        self.video_url = "https://bilibili.com/video/BV" + bv
        self.filename = filename
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)\
             AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Edg/85.0.564.44"
        }

    # 获取视频的 cid
    def get_video_cid(self):
        response = requests.get(self.video_url, headers=self.headers, timeout=10)
        if response.status_code != 200:
            print(f"请求失败，状态码: {response.status_code}")
            return None

        html = response.content.decode()
        print(f"HTML 内容(前500字符): {html[:500]}")  # 打印部分 HTML 内容用于调试
        cid = re.findall(r'("cid":)([0-9]+)', html)
        # 有的视频没有这个字段，我们跳过它
        if len(cid) == 0:
            print("未找到 cid")
            return None
        else:
            return cid[0][-1]

    # 获取请求弹幕 XML 文件返回的内容
    def get_content(self, xml_url):
        response = requests.get(xml_url, headers=self.headers, timeout=10)
        return response.content

    # 解析获取到的内容，得到包含视频所有弹幕的列表
    def extract_danmu(self, content_str):
        html = etree.HTML(content_str)
        danmu_list = html.xpath("//d/text()")
        return danmu_list

    # 将弹幕逐行写入并保存为 txt 文件
    def save(self, save_items):
        # 确保输出目录存在
        output_dir = os.path.dirname(self.filename)
        os.makedirs(output_dir, exist_ok=True)  # 自动创建目录

        with open(self.filename, 'w', encoding='utf-8') as f:
            lines = []
            for item in save_items:
                lines.append(item + '\n')
            f.writelines(lines)
        print(f"弹幕已保存至 {self.filename}")

    # 爬虫的过程封装
    def crawl(self):
        cid = self.get_video_cid()
        # 跳过没有 cid 字段的视频
        if cid is not None:
            xml_url = "http://comment.bilibili.com/" + str(cid) + ".xml"
            content_str = self.get_content(xml_url)
            danmu_lst = self.extract_danmu(content_str)
            self.save(danmu_lst)
        else:
            print("视频没有有效的 cid，跳过此视频")

if __name__ == '__main__':
    bv = input("请输入视频的 bv 号: ")
    # 处理文件名，确保路径正确
    filename = 'E:/前端/软件工程/{}.txt'.format(str(bv))
    dm = BiliBiliDanMu(bv, filename)
    dm.crawl()