0


【Selenium&办公自动化Excel】视频网站国漫热度数据分析

一、引言

图一乐

在抖音上看到大家都引用云合数据作为国漫热度的数据来源,数据来源还是太过于单一,无法体现“统计学的魅力”,故突发奇想,自己做一个数据统计,抓取多个网站排行观看数据,综合对比。

不同网站统计方式会有所不同,因此将抓取多个网站,采用加权平均合并法(AI提供的思路),最终合成一个排行榜。

理想很丰满,现实很骨感,因为各个网站的资源不同,名称、分类不统一,导致最终实现的效果非常难看,大家只看获取数据部分就行了。

为什么不直接使用优爱腾?

简单来说就是独占作品太多,无法统一计算

二、网站

1.直接百度热门作品在线观看网站

    ![](https://i-blog.csdnimg.cn/direct/016553e4115d463d8f5c13c6619e7c39.png)

2.多人推荐的视频网站

    ![](https://i-blog.csdnimg.cn/direct/03c83652dff44a2f97fbacb33782f14f.png)

3.分类:内地、国漫、国产动漫、大陆等,

4.排序:按热度、按人气、按观看数等,

三、数量

目前仅做了抓取第一页数据(一般一页为20~50多部作品)的抓取逻辑

考虑到网站页面不一样,尽量选择打开链接就是筛选好的分类页面,获取第一页数据

四、技术

  1. Python
  2. Selenium
  3. 办公自动化Excel 1. openpyxl2. pandas

五、存储

Excel(便于后面直接插入公式计算)

六、思路

省流(该思路并不严谨)

获取单个作品在各个榜单中的排名,计算不同榜单排名的平均值,最后排序,数值越小排名越高

AI详细步骤:

步骤 1: 准备工作

确保你的数据如下所示:

  • Sheet1(榜单1):A列为“排名”,B列为“名称”
  • Sheet2(榜单2):A列为“排名”,B列为“名称”

步骤 2: 创建一个综合榜单

在新的工作表(如Sheet3)中创建一个包含所有可能作品名称的列表。这个列表应该包含出现在任一榜单中的所有作品。为了确保不会遗漏任何作品,你可以在Sheet3中先合并两个榜单的作品名称,然后去除重复项。

合并并去除重复项的方法:
  1. 在Sheet3中选择一个单元格,例如A1。
  2. 输入公式 =Sheet1!$B$2:$B$100 来引用Sheet1中的名称列,然后将此区域复制到另一个位置(如C列),再用 =Sheet2!$B$2:$B$100 引用Sheet2的名称列。
  3. 选中这两个引用区域,转到“数据”选项卡,点击“删除重复项”。

这将会给你一个不重复的作品名称列表。

步骤 3: 获取两个榜单的排名

在新工作表中添加两列用于存放来自两个榜单的排名信息。使用

VLOOKUP

或更推荐的

XLOOKUP

函数来查找并填充这两个榜单中每个作品的排名。

示例公式(假设你的作品名称在Sheet3的A2开始)

对于榜单1(Sheet1)的排名,在B列输入:

=IFERROR(XLOOKUP($A2, Sheet1!$B$2:$B$100, Sheet1!$A$2:$A$100), "")

对于榜单2(Sheet2)的排名,在C列输入:

=IFERROR(XLOOKUP($A2, Sheet2!$B$2:$B$100, Sheet2!$A$2:$A$100), "")

步骤 4: 计算平均排名

在新工作表中再添加一列用于计算平均排名。使用

AVERAGE

函数来计算每个作品的平均排名。

示例公式(假设榜单1排名在B列,榜单2排名在C列)
=AVERAGE(B2:C2)

如果你希望忽略空值(即如果某个作品只出现在一个榜单中),可以使用以下公式:

=AVERAGEIF(B2:C2, "<>")

步骤 5: 排序

最后,根据计算出的平均排名对作品进行排序。选择平均排名所在的列,然后使用“数据”菜单下的“排序”功能,按照平均排名升序或降序排列。

通过以上步骤,你应该能够成功地使用Excel将两个榜单的数据合成一个新的榜单,并根据平均排名对作品进行排序。如果你有任何问题或者需要进一步的帮助,请随时告知。

七、Python

Selenium

使用Selenium,已做通用爬取设计,只需要增加里面字典参数即可,3个参数

url: 网站分类排行的URL(直接打开之后就是已经筛选为国漫并按热度、人气等分类排序的页面)

xpath: 作品名称XPath表达式,应匹配到全部的作品名称

sheet_name: 保存到Excel文件的工作表名称

因为涉及到后面的公式计算,所以只用了Excel保存

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import pandas as pd
import time
import logging

# 设置Selenium WebDriver
def setup_driver(headless=True):
    print('setup_driver')

    if headless == True:
        print('已启用无头模式,将不显示浏览器窗口')

    # 设置Chrome选项
    options = Options()

    if headless:
        options.add_argument('--headless')  # 启用无头模式
        options.add_argument('--disable-gpu')  # 在无头模式下通常需要禁用GPU加速

    # options.add_argument('--no-sandbox')  # 解决DevToolsActivePort文件不存在的报错
    # options.add_argument('--disable-dev-shm-usage')  # 解决资源受限问题
    # options.add_argument('--ignore-certificate-errors')  # 忽略证书错误
    # options.add_argument('--window-size=1920x1080')  # 设置窗口大小,对于某些网站可能会影响页面加载
    #
    # # 设置日志级别以减少输出信息
    # options.add_argument('--log-level=3')  # FATAL 级别,仅显示严重错误

    try:
        # 初始化WebDriver
        driver = webdriver.Chrome(options=options)

        print('谷歌打开成功')

        return driver
    except Exception as e:
        logging.error(f"Failed to initialize WebDriver: {e}")
        raise

# 打开网站并获取数据
def scrape_data(driver, url, xpath, max_elements=None):
    if max_elements is not None:
        print(f'抓取数量:{max_elements}')

    try:
        # 设置页面加载的最大时间为30秒
        driver.set_page_load_timeout(30)

        driver.get(url)
        time.sleep(3)  # 等待页面加载完成,可以根据实际情况调整等待时间或使用显式等待

        elements = driver.find_elements(By.XPATH, xpath)

        # 如果指定了最大抓取数量,则限制抓取数量
        if max_elements is not None and len(elements) > max_elements:
            elements = elements[:max_elements]

        # 提取文本内容
        data = [element.text for element in elements]

        return data
    except Exception as e:
        print(f"Failed to scrape data: {e}")

def save_to_excel_multiple_sheets(data_dict, filename='output.xlsx'):
    """
    将数据保存到Excel文件的不同工作表,并添加序号列。

    :param data_dict: 包含多个工作表数据的字典,键为工作表名称,值为数据列表
    :param filename: 输出的Excel文件名,默认为'output.xlsx'
    """
    with pd.ExcelWriter(filename, engine='openpyxl') as writer:
        for sheet_name, data in data_dict.items():
            # 为每条数据添加序号
            if data:
                df = pd.DataFrame(data, columns={'名称'})
                df.insert(0, '序号', range(1, len(df) + 1))
            else:
                df = pd.DataFrame(columns=['序号', '名称'])  # 如果数据为空,创建空的DataFrame

            df.to_excel(writer, sheet_name=sheet_name, index=False)

if __name__ == '__main__':
    # 保存路径
    filename = r'E:\test\数据.xlsx'

    # 抓取数量
    max_elements = 30

    # url: 网站分类排行的URL(直接打开之后就是已经筛选为国漫并按热度、人气等分类排序的页面)
    # xpath: 作品名称XPath表达式,应匹配到全部的作品名称
    # sheet_name: 保存到Excel文件的工作表名称
    websites = [
        {
            'url': 'https://www.kuyoo.com/vodshow/32--hits---------.html',
             'xpath': '//ul[@class="myui-vodlist clearfix"]/li//h4',
             'sheet_name': '天空影视'
        },
        {
            'url': 'https://www.sxzqsw.com/vodshow/32-%E5%A4%A7%E9%99%86-hits---------.html',
             'xpath': '//ul[@class="stui-vodlist clearfix"]/li//h4',
             'sheet_name': '淘剧影院'
        },
        {
            'url': 'https://nyafun.cc/index.php/vod/show/area/%E5%A4%A7%E9%99%86/by/hits/id/24.html',
            'xpath': '//ul[@class="hl-vod-list clearfix"]/li//div[@class="hl-item-text"]',
            'sheet_name': 'NyaFun动漫'
        },
        {
            'url': 'https://www.ssrfun.com/vodshow/1/area/%E5%A4%A7%E9%99%86/by/hits/lang/%E5%9B%BD%E8%AF%AD.html',
            'xpath': '//div[@class="module"]/a//div[@class="module-poster-item-title"]',
            'sheet_name': 'SSRFun动漫'
        },
        {
            'url': 'https://www.ziyedm.com/show/anime-%E4%B8%AD%E5%9B%BD-hits--%E5%9B%BD%E8%AF%AD-------/',
            'xpath': '//ul[contains(@class,"mt4 animate-in fade-in")]/li//h3',
            'sheet_name': '子夜动漫'
        },
    ]

    # 无头参数
    headless = True

    # 初始化WebDriver
    driver = setup_driver(headless=headless)

    try:
        # 创建字典来保存每个网站的数据
        data_dict = {}
        data_list = []

        websites_len = len(websites)
        if websites_len == 0:
            print('没有网站')
            exit()

        print(f'网站数量:{websites_len}')

        for site in websites:
            print(f"正在抓取:{site['sheet_name']} - {site['url']}")
            data = scrape_data(driver, site['url'], site['xpath'], max_elements)
            print('data:', data)

            if data is None:
                print('抓取错误')
                continue

            # 保存到不同工作表
            data_dict[site['sheet_name']] = data

            # 或者保存到同一工作表
            for item in data:
                data_list.append([site['url'], item])

            print('')

        if data_dict:
            # 选择一种保存方式
            save_to_excel_multiple_sheets(data_dict, filename)

            print(f'保存路径:{filename}')
    finally:
        # 关闭浏览器
        driver.quit()

计算

新增“综合排行”工作表,存放全部数据,删除重复数据,在该工作表中插入公式,

因为涉及到不同的工作表计算,所以Excel的格式不能修改,还有工作表名称也不能修改,否则计算会出错。

from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
import pandas as pd

# 创建新的工作表
def create_sheet(workbook, sheet_name):
    if sheet_name in workbook.sheetnames:
        print(f"工作表:'{sheet_name}' 已存在")
        return

    workbook.create_sheet(title=sheet_name)
    # workbook.save(file_path)
    #
    # print(f"已成功添加工作表 '{sheet_name}' 到文件 '{file_path}'")

# 获取所有榜单名称数据,删除重复数据
def get_all_data(workbook, order_sheet_name):
    all_data = []
    for sheet in workbook.worksheets:
        sheet_name = sheet.title

        # 跳过排行工作表
        if sheet_name == order_sheet_name:
            continue

        rows = sheet.iter_rows(min_row=2, values_only=True)
        for row in rows:
            name = row[1]  # 注意:column_index是从1开始的,而row索引是从0开始的
            if name is not None and isinstance(name, str):  # 只添加非空且为字符串类型的名称
                all_data.append(name.strip())

    # 删除重复数据
    all_data = list(set(all_data))
    return all_data

# 将数据写入到指定的工作表中
def write_to_sheet(workbook, data, target_sheet_name, column_index=1):
    try:
        # 检查目标工作表是否存在,不存在则创建
        if target_sheet_name not in workbook.sheetnames:
            workbook.create_sheet(title=target_sheet_name)

        target_sheet = workbook[target_sheet_name]

        # 清空目标工作表(可选)
        target_sheet.delete_rows(1, target_sheet.max_row)

        # 写入标题行(可选)
        target_sheet[f'{get_column_letter(column_index)}1'] = '名称'

        # 写入数据
        for idx, item in enumerate(data, start=2):  # 从第二行开始写入
            target_sheet[f'{get_column_letter(column_index)}{idx}'] = item

    except Exception as e:
        print(f'写入排行工作表失败:{e}')

# 获取对应榜单的排名
def get_rank_from_sheet(workbook, order_sheet_name):
    # 获取所有榜单名称
    all_sheet = []
    for sheet in workbook.worksheets:
        sheet_name = sheet.title
        all_sheet.append(sheet_name)
    print(all_sheet)

    # 写入表头
    sheet = workbook[order_sheet_name]
    for col_num, header in enumerate(all_sheet, start=2):
        col_letter = get_column_letter(col_num)
        sheet[f'{col_letter}1'] = header

    workbook.save(file_path)
    print('写入工作表表头成功')

    # 获取最大行数
    first_sheet_name = workbook.sheetnames[0]
    sheet = workbook[first_sheet_name]
    max_row = sheet.max_row
    effective_rows = 0
    for row in sheet.iter_rows(min_row=1, max_row=max_row, values_only=True):
        if any(cell is not None for cell in row):
            effective_rows += 1
    print(f'第一个工作表最大行数:{effective_rows}')

    # 获取最大列数
    sheet = workbook[order_sheet_name]
    max_col = 0
    for col_idx, cell in enumerate(sheet[1], start=1):
        max_col = col_idx
    print('有效列数:', max_col)

    # 获取综合排行工作表最大行数
    sheet = workbook[order_sheet_name]
    max_row = sheet.max_row
    order_rows = 0
    for row in sheet.iter_rows(min_row=1, max_row=max_row, values_only=True):
        if any(cell is not None for cell in row):
            order_rows += 1
    print(f'综合排行工作表最大行数:{order_rows}')

    # 获取单个名称在对应工作表中的排名
    for col in range(2, max_col):
        sheet_name = sheet.cell(row=1, column=col).value

        # 遍历每行
        for row_num in range(2, order_rows + 1):
            # 单元格
            target_cell = sheet.cell(row=row_num, column=col)
            print(f'单元格:{target_cell}')

            # 拼接公式
            formula = f'=IFERROR(XLOOKUP($A{row_num},{sheet_name}!$B$2:$B${effective_rows},{sheet_name}!$A$2:$A${effective_rows}),"")'
            print(formula)

            target_cell.value = formula

    print('')

    # 综合排名计算
    # 查找表头"综合排行"的列索引(基于字母)
    header_row = 1  # 假设表头在第一行
    column_index = 1
    for cell in sheet[header_row]:
        if cell.value == "综合排行":
            column_letter = cell.column_letter  # 获取列字母
            column_index = cell.column  # 获取列索引(数字形式)
            print(f"找到表头'综合排行'位于: 列 {column_letter} (索引 {column_index})")

    # 获取统计结束列字母
    AVERAGEIF_end_col = get_column_letter(column_index - 1)

    for row_num in range(2, order_rows):
        # 单元格
        target_cell = sheet.cell(row=row_num, column=column_index)
        print(f'单元格:{target_cell}')

        # 拼接公式
        formula = f'=AVERAGEIF(B{row_num}:{AVERAGEIF_end_col}{row_num},"<>")'
        print(formula)

        target_cell.value = formula

if __name__ == '__main__':
    file_path = r'E:\test\数据.xlsx'
    order_sheet_name = '综合排行'
    # order_file = 'E:\test\综合排行.xlsx'

    try:
        # 加载现有的工作簿
        workbook = load_workbook(filename=file_path)

        # 创建排序用的工作表
        create_sheet(workbook, order_sheet_name)

        # 获取唯一数据
        unique_names = get_all_data(workbook, order_sheet_name)
        # print(unique_names)

        # 将唯一数据写入到指定工作表
        write_to_sheet(workbook, unique_names, order_sheet_name, column_index=1)

        # 添加计算公式
        get_rank_from_sheet(workbook, order_sheet_name)

        # 保存
        workbook.save(file_path)

        print(f'保存路径:{file_path}')
    except Exception as e:
        print(f'保存失败:{e}')

排序

就差最后一步,但是使用openpyxl库读取Excel公式计算的值都是None,导致排序有问题

换了别的库也不行,这个排序只能手动了

八、效果

获取效果

公式计算结果

  1. 综合排行列需手动排序,空白为其网站在指定排名没有找到,该公式会把空白忽略。
  2. 本来想自动排序好的,但是Python无法获取公式的计算值,只能手动了

九、注意

  1. 每个网站的资源不一样,作品A可能在平台1上可以观看,但在平台2上就没有,会导致最终排名与实际不符
  2. 热度不代表质量
  3. 作品更新日该作品的热度会快速提升
  4. 部分网站会区分动画和动漫,部分不会区分,所以会出现诸如:猪猪侠、熊出没等子供向作品,目前并没有对其做区分操作
  5. 名称不一样会出现重复,如诛仙、诛仙 动画版
  6. 我对算法一窍不通,只能通过AI提供的思路进行排序,所以这个算法有非常大的缺陷,要求各个榜单的作品都存在,如果某一作品只在其中一个榜单,会导致最终的排名变高。但是考虑到各个网站的资源不同,这一现象应该普遍存在,所以最终的排名还需进一步优化。
  7. 没有做反爬措施,部分网站可能无法获取
  8. 图一乐
标签: python selenium 爬虫

本文转载自: https://blog.csdn.net/qq_48180611/article/details/144248013
版权归原作者 vdoi 所有, 如有侵权,请联系我们删除。

“【Selenium&办公自动化Excel】视频网站国漫热度数据分析”的评论:

还没有评论