不想每个月花钱买QQ音乐/网易云音乐会员,偶尔听听歌,发现没会员整个人心情都不好了;于是准备:
1.自己搭建navidrome服务,支持在windows/手机端用音流Stream music的app 愉快听歌
2.基于python的selenium半自动化远程下载音乐至服务器:想听什么歌;都能较为方便的添加到服务器中,不需要手动下载音乐,然后传输等等;
接下来先看看成品效果:

Navidrome页面.png

以及我通过命令行,输入百度云的音乐共享链接,自动化下载到服务器的效果:
selenium自动化下载.png
基本功能是可以保证的 --- 虽然会有些error,无伤大雅hhh

整体流程包含如下操作:

1.在服务器端部署Navidrome:

建议是通过docker部署,这部分操作不做赘述,各个平台的docker部署方法大同小异;如果不清楚如何部署docker,可以看我的一篇文章 哪吒监控部署 流媒体解锁:Grafana + Prometheus 中如何使用docker安装grafana的

2.将Navidrome的端口通过FRP内网穿透到外部

例如我穿透到music.overstic.top这个链接,就可以在外面也能听音乐了;这部分操作可以看我另一篇文章 FRP 内网穿透,支持通过域名访问内部服务器资源

3.安装Aria2下载软件

安装aria2的目的是,这个可以通过网页输入下载链接,然后直接下载到本地服务器;而且他有一个RPC下载,可以直接在百度云网页版中讲需要下载的文件直接推送到aria2,非常方便;Aria2的安装操作请看这篇文章 Aria2 下载器网页版配置流程 -- Windows版本

4.在Google浏览器上安装 篡改猴 Beta版,找到百度云直链的脚本

通过篡改猴的脚本,可以将百度云保存的文件获取直链,方便Aria2直接下载;同时脚本支持直接批量将直链通过RPC发送给我的Aria2后自动下载。

首先进入篡改猴Beta,如果链接失效直接在google搜索 篡改猴 Beta,找到chrome应用商店里面软件,然后安装;
安装完之后,右上角应该会出现两个图标:
篡改猴.png
其中红色的是Beta版本,百度云直链的脚本需要在Beta脚本上运行;黑色的是普通版本,也可以运行别的脚本,可以自行探索;

接下来在 Greasy Fork 油叉 上搜索百度云直链,找到可以使用的直链脚本,建议选择安装人数多的。我现在使用的是
网盘直链下载助手.png
网盘直链下载助手(自动显示暗号),当前用着还行,后面就不一定了;

下载好后,可以进入百度云盘的网页版,先看右上角的篡改猴是否有个数字1,如果有则表示这个脚本可以生效了;然后在云盘页面上找是否多了一个下载助手的按钮,有的话则说明可以使用
下载助手.png
我们主要会用到里面的RPC下载或者Aria下载;其中RPC下载只要在助手设置中配置好aria2下载页面的参数,就可以自动推送;Aria下载需要自己拷贝连接进去,稍微麻烦一些;

对于RPC下载,按照如下配置:
助手设置.png
其中主机则是你aria2 web服务在公网的地址;
PRC端口是aria2 server的端口;
RPC密钥同理
保存路径是服务器上音乐的保存路径

配置好后,如果你想批量传音乐,勾选音乐 -> 点击下载助手 -> 选择RPC下载 -> 在弹出的页面上选择发送全部连接即可;形如:
RPC下载.png

5.在Windows上部署selenium脚本:

包含两个脚本,一个是cookie获取脚本:

import time
import re
import random
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import *
from selenium.webdriver.chrome.service import Service
import pandas as pd 
import copy
import re
import os

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC   

service = Service("D:\chromedriver-win64\chromedriver.exe")
driver = webdriver.Chrome(service=service)

driver.get("https://pan.baidu.com/") 

Input("等待登陆,登陆后回车")

cookies = driver.get_cookies()
with open("baidu_cookies.json", "w") as f:
    json.dump(cookies, f)

print('Cookie 保存成功')
print('地址:')
print(os.path.join(os.getcwd(),"baidu_cookies.json"))

运行这个脚本,在弹出的页面正常登录账号后,即可将cookie记录;

第二个是百度云音乐保存脚本:
import time

import re
import random
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import *
from selenium.webdriver.chrome.service import Service
import pandas as pd 
import copy
import os
import json
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC   
from selenium.webdriver.common.action_chains import ActionChains


Timewait = 5
xpath_main_loginbutton = '//*[@id="layoutHeader"]/div/div/dl/dd[2]/a[1]'
xpath_login_userloginbutton = '//*[@id="TANGRAM__PSP_11__changePwdCodeItem"]'
xpath_login_autologinbutton = '//*[@id="TANGRAM__PSP_11__clientOnekeySumbit"]'
xpath_login_errorinfo = '//*[@id="TANGRAM__PSP_11__clientShareError"]'
xpath_login_user = '//*[@id="TANGRAM__PSP_11__userName"]'
xpath_login_pwd = '//*[@id="TANGRAM__PSP_11__password"]'
xpath_login_submit = '//*[@id="TANGRAM__PSP_11__submit"]'
xpath_login_agree = '//*[@id="TANGRAM__PSP_11__isAgree"]'
xpath_save_sure = '//*[@id="fileTreeDialog"]/div[3]/a[1]/span/span'
def check_login():
    #判断是否登陆
    try:
        element = driver.find_element('xpath',xpath_main_loginbutton)
        if element.text == "登录":
            return False
        elif element.text == "客户端下载":
            return True     
        else:
            return True
    except Exception as e:
        print('未找到"登陆"选项,请检查: {e}')
        return False
def login():
        element = driver.find_element('xpath',xpath_main_loginbutton)          
        print("点击登陆按钮")
        element.click() #点击登陆        
        time.sleep(Timewait)  
        
        print("点击账号登陆")    
        element_loginmethod = driver.find_element('xpath',xpath_login_userloginbutton)                  
        element_loginmethod.click() #点击登陆        
        time.sleep(Timewait)  
         
        print("尝试能否直接登陆")
        #判断能否直接登陆
        element_login = driver.find_element('xpath',xpath_login_autologinbutton)
        if element_login.text == "账号登录" or element_login.text == "直接登录":
            element_login.click()
            print("可以快捷登陆,尝试直接登陆")
            time.sleep(Timewait)
            
            element_grant_error = check_elements('授权已过期')
            if element_grant_error:
                print('授权已过期,重新输入账号密码')
                loginwithPWD()
            else:
                print("快捷登陆成功")
        else:
            print("无法快捷登陆,重新输入账号密码")
            loginwithPWD()    
            
def loginwithCookie():
    try:
        with open(r"D:\Shares\Disk1\代码\baidu_cookies.json", "r") as f:
            cookies = json.load(f)
            for cookie in cookies:
                driver.add_cookie(cookie)    
        driver.refresh() 
        time.sleep(Timewait)
    except FileNotFoundError:
        print("Cookies 文件不存在,请检查路径")
        
def loginwithPWD(usr_name = 'XXX',pwd = 'XXX'):                    
    #不能直接登陆
    print("不能直接登陆,输入账号密码")
    element_zhanghaologin = driver.find_element('xpath',xpath_login_userloginbutton)
    element_zhanghaologin.click()
    time.sleep(Timewait)
    
    print("点击账号登陆")
    element = driver.find_element('xpath','//*[@id="TANGRAM__PSP_11__clientOnekeyChangeLogin"]')
    element.click()  
    time.sleep(Timewait)    
    
    element_usrname = driver.find_element('xpath',xpath_login_user)
    element_usrname.clear()
    element_usrname.send_keys(usr_name)
    time.sleep(Timewait)
    
    element_pwd = driver.find_element('xpath',xpath_login_pwd)
    element_pwd.clear()
    element_pwd.send_keys(pwd)  
    time.sleep(Timewait)
    
    element_submit = driver.find_element('xpath',xpath_login_submit)
    while not element_submit.is_enabled():
        element_accept = driver.find_element('xpath',xpath_login_agree)
        element_accept.click()   
        time.sleep(Timewait)
    element_submit.click()
    time.sleep(Timewait)
    
    Input("确认是否正常登陆,若没有,手动登陆")

def check_elements(Str):
    Elements = driver.find_elements('xpath', "//*[contains(text(), '%s')]"%Str)
    Elements = [i for i in Elements if i.text == Str]
    if Elements:
        element = Elements[0]    
        return element                
    
def find_music():
    elements_best = []
    Music_name = []
    sequence = ['flac','mp3']
    for quality in sequence:
        print("查找%s格式"%quality)
        elements_cur = driver.find_elements('xpath', "//*[contains(text(), '%s')]/parent::div"%quality)
        for i in elements_cur:
            if i.text and (i.text.split('.' + quality)[0] not in Music_name) and  (not i.text.split('.' + quality)[1]):
                #判断条件:有对应格式名,有字符串,格式名前面是名字,格式名后面是空值
                Music_name.append(i.text.split('.' + quality)[0])
                elements_best.append(i)
                print(i.text)

    return Music_name,elements_best

def save_music(elements_best):
    if not elements_best:
        print("当前页面无目标歌曲,可能为文件夹,直接保存")
    else:
        for element in elements_best:
            element.click()
            time.sleep(1)
    
    print('保存到网盘')
    element_save = check_elements('保存到网盘')
    if element_save:
        element_save.click()
        time.sleep(Timewait)
    else:
        print('保存失败')
        return
        
    print('选择音乐文件夹')
    element_music = check_elements('音乐')
    if element_music:
        element_music.click()
        time.sleep(Timewait)
    else:
        print('选择失败')     
        return
    element_sure = check_elements('确定')
    if element_sure:
        element_sure.click()
        time.sleep(Timewait)
    else:
        print('选择确认按钮失败')   
        return
    time.sleep(3)
    
    element_success = check_elements('保存成功')
    if element_success:
        print('保存成功')
    else:
        print('保存失败')
    return
# def iterFind(): #文件夹迭代 没写完,如果多个文件夹不好退出
#     Music_name,elements_best = find_music()    
#     save_music(elements_best)  
#     FileElements = 

def check_ready():
    status = WebDriverWait(driver, 10).until(
        lambda driver: driver.execute_script("return document.readyState") == "complete"
    )    
    return status

def main(path,code):
    # path = 'https://pan.baidu.com/s/1EFPt2AqkOFCrY_AdEYcmdQ'
    # code = 'ad89'
    
    url = path + '?pwd=' + code 
    driver.get(url)  
    s = check_ready()
    if not s:
        raise Exception("页面未加载")
    try:    
        element_ex = check_elements('提取文件')
        element_ex.click()
        time.sleep(Timewait)
    except:
        pass
    check_ready()
    if not s:
        raise Exception("页面未加载")      
    time.sleep(Timewait)
    print("检查是否登陆")
    if not check_login():
        print("未登陆,尝试Cookie登陆")
        loginwithCookie() 
        time.sleep(Timewait)
    if not check_login():
        print("Cookie登陆失败,尝试自动登陆")
        loginwithCookie()         
    if not check_login():
        raise Exception("自动登陆失败,请手动尝试")    
    print("已登陆")        

运行这个脚本,如果是远程运行,在选择无头模式时输入yes/Y/y,本地运行可以输入n,则会跳出一个自动化网页,能够看到他是怎么自动化操作的;

首先输入百度云共享的连接,然后输入百度云共享的密码;接着就会自动将音乐文件保存到百度云的音乐文件夹中

6.获取 Hifini 账号

如果想用5中的脚本,建议使用Hifni里面的资源;每个资源都是由百度云共享的,包含链接和密码;

标签: none

添加新评论