一、引言
图一乐
在抖音上看到大家都引用云合数据作为国漫热度的数据来源,数据来源还是太过于单一,无法体现“统计学的魅力”,故突发奇想,自己做一个数据统计,抓取多个网站排行观看数据,综合对比。
不同网站统计方式会有所不同,因此将抓取多个网站,采用加权平均合并法(AI提供的思路),最终合成一个排行榜。
理想很丰满,现实很骨感,因为各个网站的资源不同,名称、分类不统一,导致最终实现的效果非常难看,大家只看获取数据部分就行了。
为什么不直接使用优爱腾?
简单来说就是独占作品太多,无法统一计算
二、网站
1.直接百度热门作品在线观看网站
![](https://i-blog.csdnimg.cn/direct/016553e4115d463d8f5c13c6619e7c39.png)
2.多人推荐的视频网站
![](https://i-blog.csdnimg.cn/direct/03c83652dff44a2f97fbacb33782f14f.png)
3.分类:内地、国漫、国产动漫、大陆等,
4.排序:按热度、按人气、按观看数等,
三、数量
目前仅做了抓取第一页数据(一般一页为20~50多部作品)的抓取逻辑
考虑到网站页面不一样,尽量选择打开链接就是筛选好的分类页面,获取第一页数据
四、技术
- Python
- Selenium
- 办公自动化Excel 1. openpyxl2. pandas
五、存储
Excel(便于后面直接插入公式计算)
六、思路
省流(该思路并不严谨)
获取单个作品在各个榜单中的排名,计算不同榜单排名的平均值,最后排序,数值越小排名越高
AI详细步骤:
步骤 1: 准备工作
确保你的数据如下所示:
- Sheet1(榜单1):A列为“排名”,B列为“名称”
- Sheet2(榜单2):A列为“排名”,B列为“名称”
步骤 2: 创建一个综合榜单
在新的工作表(如Sheet3)中创建一个包含所有可能作品名称的列表。这个列表应该包含出现在任一榜单中的所有作品。为了确保不会遗漏任何作品,你可以在Sheet3中先合并两个榜单的作品名称,然后去除重复项。
合并并去除重复项的方法:
- 在Sheet3中选择一个单元格,例如A1。
- 输入公式
=Sheet1!$B$2:$B$100
来引用Sheet1中的名称列,然后将此区域复制到另一个位置(如C列),再用=Sheet2!$B$2:$B$100
引用Sheet2的名称列。 - 选中这两个引用区域,转到“数据”选项卡,点击“删除重复项”。
这将会给你一个不重复的作品名称列表。
步骤 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,导致排序有问题
换了别的库也不行,这个排序只能手动了
八、效果
获取效果
公式计算结果
- 综合排行列需手动排序,空白为其网站在指定排名没有找到,该公式会把空白忽略。
- 本来想自动排序好的,但是Python无法获取公式的计算值,只能手动了
九、注意
- 每个网站的资源不一样,作品A可能在平台1上可以观看,但在平台2上就没有,会导致最终排名与实际不符
- 热度不代表质量
- 作品更新日该作品的热度会快速提升
- 部分网站会区分动画和动漫,部分不会区分,所以会出现诸如:猪猪侠、熊出没等子供向作品,目前并没有对其做区分操作
- 名称不一样会出现重复,如诛仙、诛仙 动画版
- 我对算法一窍不通,只能通过AI提供的思路进行排序,所以这个算法有非常大的缺陷,要求各个榜单的作品都存在,如果某一作品只在其中一个榜单,会导致最终的排名变高。但是考虑到各个网站的资源不同,这一现象应该普遍存在,所以最终的排名还需进一步优化。
- 没有做反爬措施,部分网站可能无法获取
- 图一乐
版权归原作者 vdoi 所有, 如有侵权,请联系我们删除。