python爬虫爬取音乐-JS逆向爬虫
'# Python爬虫爬取音乐-JS逆向爬虫
一、背景与问题
在音乐网站爬取数据时,常遇到以下挑战:
- 动态生成的加密参数(如token)
- 前端JavaScript动态计算的请求参数
- 后端接口的动态签名机制
- 防止请求被识别的反爬虫机制
以网易云音乐为例,其音乐评论接口的请求参数包含动态生成的token和signature字段。传统爬虫无法直接获取这些参数,需要逆向分析前端JavaScript代码,找到生成规则后进行模拟计算。
二、基本原理
JS逆向爬虫的核心原理是:
- 通过浏览器开发者工具分析前端代码
- 找到关键的加密算法逻辑
- 用Python模拟执行JavaScript代码
- 构造合法的请求参数
- 发送请求获取数据
关键点在于理解前端JavaScript的运行时环境,包括:
- 全局变量作用域
- 异步函数执行顺序
- 模块化加载机制
- 依赖的第三方库(如crypto-js)
三、环境准备
pip install pyexecjs requests准备工具:
- Chrome浏览器开发者工具(F12)
- Python 3.8+
- 代码编辑器(VSCode/PyCharm)
四、核心实现
1. 分析JS代码
以网易云音乐为例,分析https://music.163.com/api/comment/接口的请求参数生成逻辑:
// 伪代码示例(简化版)
function getSignature() {
const crypto = require('crypto');
const token = 'xxxxx';
const key = '123456';
const data = token + key;
return crypto.createHash('md5').update(data).digest('hex');
}2. 逆向算法实现
import execjs
# 加载JavaScript代码
with open('signature.js', 'r') as f:
js_code = f.read()
# 构造参数
token = 'xxxxx' # 从页面获取的token
key = '123456' # 密钥
# 执行JS代码
ctx = execjs.compile(js_code)
signature = ctx.call('getSignature', token, key)
print(signature)3. 请求构造
import requests
headers = {
'User-Agent': 'Mozilla/5.0',
'Referer': 'https://music.163.com'
}
params = {
'type': '1',
'id': '190264',
'offset': '0',
'limit': '20',
'csrf_token': 'xxxxx'
}
response = requests.get(
'https://music.163.com/api/comment',
params=params,
headers=headers
)
print(response.json())五、完整案例
1. 网易云音乐评论爬取案例
步骤1:获取token
def get_token():
response = requests.get('https://music.163.com/api/v1/user/190264')
return response.cookies.get('__csrf_token')步骤2:构造请求参数
def get_signature(token):
js_code = """
const crypto = require('crypto');
function getSignature(token, key) {
const data = token + key;
return crypto.createHash('md5').update(data).digest('hex');
}
return getSignature;
"""
ctx = execjs.compile(js_code)
return ctx.call('getSignature', token, '123456')步骤3:发送请求
def get_comments():
token = get_token()
signature = get_signature(token)
params = {
'type': '1',
'id': '190264',
'offset': '0',
'limit': '20',
'csrf_token': token,
'signature': signature
}
response = requests.get(
'https://music.163.com/api/comment',
params=params,
headers={'User-Agent': 'Mozilla/5.0'}
)
return response.json()完整运行示例:
if __name__ == '__main__':
comments = get_comments()
for comment in comments['comments']:
print(f"{comment['user']['nickname']}: {comment['content']}")六、源码解析
1. JS逆向核心部分
// signature.js
const crypto = require('crypto');
function getSignature(token, key) {
const data = token + key;
return crypto.createHash('md5').update(data).digest('hex');
}关键点:
- 使用Node.js的crypto模块
- 通过MD5算法生成签名
- 需要完整的依赖环境(如crypto模块)
2. Python执行部分
import execjs
def execute_js(js_code, *args):
ctx = execjs.compile(js_code)
return ctx.call('getSignature', *args)注意:
- 需要完整的JS运行时环境
- 需要处理模块依赖
- 需要处理异步函数
七、进阶使用
1. 处理复杂加密
# 处理多层加密
js_code = """
const crypto = require('crypto');
function getComplexSignature(token, key) {
const first = crypto.createHash('md5').update(token).digest('hex');
const second = crypto.createHash('sha1').update(first + key).digest('hex');
return second;
}
"""
signature = execute_js(js_code, 'xxxxx', '123456')2. 处理动态加载
# 使用Selenium处理动态加载内容
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://music.163.com')
token = driver.get_cookie('__csrf_token')['value']
driver.quit()八、性能与工程实践
1. 性能优化
- 使用缓存机制:缓存token和签名
- 使用多线程:并发处理多个请求
- 使用代理池:避免IP被封禁
from concurrent.futures import ThreadPoolExecutor
def batch_request(urls):
results = []
with ThreadPoolExecutor(max_workers=5) as executor:
results = executor.map(fetch, urls)
return results2. 安全风险
- 遭遇反爬机制:网站可能更新加密算法
- IP封禁:频繁请求可能导致被封
- 法律风险:音乐数据版权问题
3. 异常处理
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")九、常见问题与踩坑
1. 常见错误
错误示例:
ctx.call('getSignature', token) # 缺少参数错误原因: JavaScript函数需要两个参数
解决方法:
ctx.call('getSignature', token, '123456')2. 参数处理错误
错误示例:
token = 'xxxxx' # 未正确获取解决方法:
token = get_token() # 使用正确的获取方式3. 依赖缺失
错误示例:
# 未加载crypto模块
ctx = execjs.compile("function getSignature() { ... }")解决方法:
ctx = execjs.compile("""
const crypto = require('crypto');
function getSignature() { ... }
""")十、最佳实践
1. 推荐方案
- 使用
pyexecjs执行JavaScript代码 - 使用
requests发送HTTP请求 - 使用
concurrent.futures进行并发处理 - 使用
fake_useragent生成随机User-Agent
2. 方案比较
| 方案 | 优点 | 缺点 |
|---|---|---|
| JS逆向 | 可处理复杂加密 | 需要维护JS运行时 |
| Selenium | 支持动态加载 | 资源消耗大 |
| 使用API | 无需逆向 | 需要API权限 |
3. 实际应用建议
适合使用JS逆向的场景:
- 数据是动态生成的
- 接口有加密参数
- 需要处理复杂算法
- 非常规的反爬机制
不适合使用的场景:
- 数据量极大
- 需要频繁请求
- 网站有强反爬机制
- 需要处理复杂前端框架(如React/Vue)
十一、总结
JS逆向爬虫是应对动态内容反爬的重要手段,但需要深入理解前端代码和算法逻辑。本文详细讲解了:
- JS逆向的基本原理
- 代码实现的完整流程
- 常见错误及解决方法
- 性能优化技巧
- 安全风险和法律注意事项
在实际开发中,应根据具体情况选择合适的方案。对于音乐网站这类存在动态加密的场景,JS逆向是有效的解决方案,但需注意法律风险和技术更新。通过合理的设计和优化,可以实现高效稳定的爬虫系统。
评论已关闭