# 导入time模块，用于添加延时
import time

# 导入requests模块并重命名为req，用于发送HTTP请求
import requests as req

# 导入BeautifulSoup模块，用于解析HTML文档
from bs4 import BeautifulSoup

# 导入selenium的webdriver模块，用于控制浏览器
from selenium import webdriver

# 导入selenium的By模块，用于定位元素
from selenium.webdriver.common.by import By

# 导入selenium的Service模块，用于管理浏览器驱动服务
from selenium.webdriver.chrome.service import Service

# 导入webdriver_manager的ChromeDriverManager模块，用于自动管理Chrome驱动
from webdriver_manager.chrome import ChromeDriverManager


# 定义网易音乐爬虫类
class neteaseMusicSpider:
    # 初始化方法，设置爬虫的基本配置
    def __init__(self):
        # 设置目标URL，网易云音乐排行榜页面
        self.url = 'https://music.163.com/discover/toplist?id=3779629'
        # 设置请求头，模拟浏览器访问
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
        }
        # 初始化排行榜列表
        self.toplist = []

    # 获取页面内容的方法
    def get_page(self):
        # 用Selenium渲染页面，获取iframe
        # 创建Service对象，指定ChromeDriver路径
        service = Service(executable_path='/Users/zhaohaibo/Desktop/chromedriver-mac-x64/chromedriver')
        # 启动Chrome浏览器
        driver = webdriver.Chrome(service=service)
        # 访问目标网址
        driver.get(self.url)
        # 等待3秒，让JavaScript加载完成iframe和#document
        # time.sleep(3)

        # 定位iframe元素
        iframe_elem = driver.find_element(By.TAG_NAME, "iframe")
        # 打印iframe元素信息
        print(iframe_elem)
        # 切换到iframe的#document上下文
        driver.switch_to.frame(iframe_elem)

        # 提取iframe的完整HTML内容（即#document内容）
        iframe_html = driver.page_source
        # 关闭浏览器
        driver.quit()
        # 返回获取到的HTML内容
        return iframe_html

    # 解析页面内容的方法
    def parse_page(self):
        try:
            # 使用BeautifulSoup解析获取到的页面内容
            soup = BeautifulSoup(self.get_page(), 'html.parser')
            # 查找table > tbody标签下的所有的tr标签
            trs = soup.select('table > tbody')[0]
            # 返回找到的tr标签列表
            return trs
        except Exception as e:
            # 捕获异常并打印错误信息
            print('soup转换异常', e)
            # 返回None表示解析失败
            return None

    # 获取歌曲信息的方法
    def get_songs(self):
        # 初始化歌曲字典
        songs = {}
        try:
            # 调用parse_page方法获取解析后的HTML元素
            songs_html = self.parse_page()
            # 打印获取到的HTML元素及其类型
            print(songs_html, '\n', type(songs_html))
            # 遍历每个歌曲元素
            for song in songs_html:
                # 提取歌曲排行，通过CSS选择器定位元素并获取排行对应文本内容
                s_rank = song.select('td:nth-child(1) >div>span')[0].string
                # 提取歌曲标题，通过CSS选择器定位元素并获取title属性
                s_title = song.select('span > a > b')[0].get_attribute_list('title')[0]
                # 提取歌手信息，通过CSS选择器定位元素并获取title属性
                s_singer = song.select('td:nth-child(4) > div')[0].get_attribute_list('title')[0]
                # 提取歌曲时长，通过CSS选择器定位元素并获取文本内容
                s_duration = song.select('td.s-fc3 > span')[0].string
                # 提取歌曲ID，通过CSS选择器定位元素
                s_id = song.select('td:nth-child(2) > div > div > span')[0].get_attribute_list('data-res-id')[0]
                # 打印提取到的歌曲信息
                print(s_rank, s_id, s_title, s_singer, s_duration, '\n')
                # 将歌曲信息添加到字典中、方便后续写入数据库、表格存储
                songs[s_id] = {
                    'rank': s_rank,
                    'title': s_title,
                    'singer': s_singer,
                    'duration': s_duration
                }


        except Exception as e:
            # 捕获异常并打印错误信息
            print('异常', e)


# 程序入口点
if __name__ == '__main__':
    # 创建neteaseMusicSpider类的实例
    nms = neteaseMusicSpider()
    # 调用get_songs方法开始爬取歌曲信息
    nms.get_songs()
