使用Selenium + headless Chrome获取QQ音乐Cookies

众所周知,鹅家反自动化做的很好,自己有个音乐API站的Cookies经常过期,为此联动Gocqhttp做了个获取Cookies的方案

配置Selenium环境

  1. 安装selenium
    1
    pip3 install selenium
  2. 安装Chrome dev(我觉得dev版本稳定一些)
    1
    2
    3
    wget https://dl.google.com/linux/direct/google-chrome-unstable_current_amd64.deb
    dpkg -i google-chrome-unstable_current_amd64.deb
    # 若遇到依赖问题安装失败可执行apt-get install -f后再安装
  3. 配置Chromedriver
    1
    google-chrome --version # 下载的driver一定得是对应版本的
    driver下载地址:https://googlechromelabs.github.io/chrome-for-testing/
    1
    2
    3
    4
    wget https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/121.0.6167.85/linux64/chromedriver-linux64.zip
    unzip ./chromedriver-linux64.zip -d ./
    mv ./chromedriver /usr/local/bin/
    chmod +x /usr/local/bin/chromedriver

自动化脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
options = webdriver.ChromeOptions()
options.binary_location = "/usr/bin/chromium-browser"
options.add_argument('--no-sandbox')
options.add_argument('--headless')
browser = None
temp_str = ""


# 这个函数用来包装失败重试行为,一次成功率太低,selenium难以设置event hook便只能这样干了
def dots(func):
def wrapper(*args, **kwargs):
result = False
id = 0
while result == False:
try:
func(*args, **kwargs)
result = True
print(f"{func.__name__}执行完成")
except Exception as e:
id = id+1
if (id == 10):
return False
else:
print(f"{func.__name__}执行出错{e},正在重试......")
time.sleep(1)
return True
return wrapper


@dots
def click_login():
element = browser.find_element(By.CLASS_NAME, "top_login__link")
element.click()
@dots
def switch_frame():
loginFrame = browser.find_element(By.ID, "login_frame")
browser.switch_to.frame(loginFrame)
@dots
def switch_frame2():
ptlogin_iframe = browser.find_element(By.ID, "ptlogin_iframe")
browser.switch_to.frame(ptlogin_iframe)
@dots
def img_get():
global temp_str
element = browser.find_element(By.ID, "qrlogin_img")
if element.get_attribute("src") != "":
time.sleep(1)
temp_str = browser.get_screenshot_as_base64()
@dots
def cookie_get():
global temp_str
cookie_script = """
return document.cookie
"""
temp_str = browser.execute_script(cookie_script)
def strProcedure(*functions):
for func in functions:
result = func()
if result is not True:
raise Exception(f"Function {func.__name__} returned False")
global temp_str
local_src = temp_str
temp_str = ""
return local_src

# 下面的函数是用来包装为WebAPI给gocqhttp调用的
def getImgUrl():
try:
global browser
if (browser != None):
browser.quit()
return {'res': -1, 'msg': '实例未正确关闭'}
browser = webdriver.Chrome(
options=options)
url = 'https://y.qq.com'
browser.get(url) # 打开网页
src = ""
except Exception as e:
print(f"执行出错:{e}")
return {'res': -1, 'msg': 'chrome出错,请之后重试'}
try:
src = strProcedure(click_login, switch_frame, switch_frame2, img_get)
except Exception as e:
browser.quit()
browser = None
print(f"执行出错:{e}")
return {'res': -1, 'msg': '执行出错,请之后重试'}
return {'res': 0, 'msg': src}
def getCookie(destory=True):
global browser
if (browser == None):
return {'res': -1, 'msg': '实例未正确开启'}
cookie = strProcedure(cookie_get)
if destory:
browser.quit()
browser = None
return {'res': 0, 'msg': cookie}

效果展示

长按图片可以直接二维码扫描登录,获取Cookies后推送到音乐API
效果

之后方向

想办法逆向这个二维码获取和cookies获取,抛弃掉浏览器这个内存耗子