一、目标站点分析
页面结构与数据来源 静态HTML仅提供基础页面框架,核心数据(如影视列表、详情信息、播放源)均通过异步接口动态加载。通过浏览器开发者工具(Network-XHR/Fetch)分析可知:
- 影视列表通过
/api/movie/list类接口返回JSON数据 - 详情页数据依赖
/api/movie/detail?id=xxx - 播放源地址由
/api/play/source?vid=xxx接口提供
技术栈与渲染方式 前端监测到Vue.js框架特征(如data-v-属性),结合接口返回数据格式推断为**客户端渲染(CSR)**模式。页面初始加载后,由JavaScript动态请求接口并渲染内容,需爬虫直接处理API或模拟浏览器执行环境。
二、爬虫核心策略
请求模拟
-
基础请求 :使用
httpx维持会话,自动管理Cookies:session = httpx.Client(headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Referer": "https://libvio.link" }) -
动态请求 :逆向接口参数:
- 时间戳
t:通常为当前毫秒时间 - 签名
sign:需逆向JS加密逻辑(详见第三节)
- 时间戳
-
分页处理 :识别分页参数(如
page、offset),构造循环请求。
页面解析
-
静态解析 :基础页面元素(如标题)可用
parsel提取:selector = Selector(html) title = selector.css("h1::text").get() -
动态内容获取 :
-
高效方案 :直接调用接口解析JSON(首选)
resp = session.get("/api/movie/detail?id=123") data = resp.json() # 直接提取JSON字段 -
备选方案 :使用
Playwright模拟浏览器渲染(应对复杂JS逻辑)with sync_playwright() as p: browser = p.chromium.launch() page = browser.new_page() page.goto(url) page.wait_for_selector(".player-section") # 等待动态加载 html = page.content() # 获取完整HTML
-
数据提取
- JSON路径提取:
data['movie']['title'] - 清洗处理:正则过滤无效字符
re.sub(r"\s+", " ", text)
三、核心挑战与应对策略
动态接口逆向
-
参数签名分析 :通过Chrome开发者工具(Sources面板)定位加密函数:
- 搜索关键词:
sign、encrypt、token - 调试关键函数:设置断点追踪参数生成过程
- 搜索关键词:
-
JS代码复现 :使用
PyExecJS执行加密逻辑:import execjs ctx = execjs.compile(open("crypto.js").read()) sign = ctx.call("generateSign", "params=123")
反爬机制突破
-
请求头防御 :完整模拟浏览器Headers,包括:
headers = { "Accept": "application/json", "X-Requested-With": "XMLHttpRequest", "Cookie": "session_id=xxx" } -
IP封禁应对 :
- 代理IP池轮换:
httpx通过proxies参数集成 - 请求频率控制:随机延迟
time.sleep(random.uniform(1, 3))
- 代理IP池轮换:
-
验证码处理 :
-
识别触发阈值(如每小时请求>50次触发)
-
接入打码平台自动识别(示例伪代码):
captcha = download_captcha() code = dama2.decode(captcha) # 第三方打码接口
-
播放源解密 真实播放地址常经过二次加密:
- 提取
data-player属性中的Base64编码数据 - 多层JSON解析:
json.loads(base64.b64decode(encoded_str)) - 定位最终URL:
result['url']['src']
四、爬虫架构优化
-
异步并发 :
aiohttp提升吞吐量async with aiohttp.ClientSession() as session: tasks = [fetch(session, url) for url in urls] await asyncio.gather(*tasks) -
代理管理:自建代理中间件验证IP可用性
-
存储设计 :MongoDB存储非结构化数据
db.movies.insert_one({ "title": "电影名", "sources": ["url1", "url2"] })
五、工具与技术栈
| 类别 | 推荐工具 |
|---|---|
| 请求库 | httpx(支持HTTP/2)、requests |
| 解析库 | parsel(兼容XPath/CSS)、json |
| 无头浏览器 | Playwright(隐藏指纹) |
| 异步框架 | aiohttp、asyncio |
| JS逆向 | PyExecJS、Chrome DevTools |
| 代理方案 | 付费代理服务(如Luminati) |
六、伦理与法律边界
- 严格检查
robots.txt,如存在禁止爬取目录则规避 - 数据限于技术研究,避免商业侵权
- 请求频率限制在
<5req/s,减少服务器压力
七、总结 Libvio.link爬虫的核心挑战在于动态参数签名与客户端渲染。解决方案需结合:
- 接口逆向:通过JS调试还原加密逻辑
- 多模式抓取:优先直击API,次选无头浏览器
- 对抗系统:代理池+请求控制突破IP限制 未来需关注WebAssembly加密、行为验证码等新型反爬手段,持续优化动态对抗能力。
附录A:接口请求示例
import httpx
import hashlib
def get_sign(params: str) -> str:
salt = "libvio_salt" # 通过JS逆向获得
return hashlib.md5(f"{params}{salt}".encode()).hexdigest()
params = "id=123&t=1680000000"
url = f"https://libvio.link/api/movie/detail?{params}&sign={get_sign(params)}"
resp = httpx.get(url, headers=headers)
附录B:反爬策略速查表
| 反爬类型 | 应对工具 | 关键步骤 |
|---|---|---|
| 参数签名 | PyExecJS | 定位JS加密函数 |
| IP限制 | 代理池 | 自动切换IP地址 |
| 验证码 | 打码平台 | 触发后人工介入 |
| 动态渲染 | Playwright | 等待元素加载 |
文章说明
- 文中代码为技术演示片段,需根据实际接口调整
- 加密逻辑
get_sign()为简化示例,真实场景需完整逆向JS - 法律风险提示:爬取行为需遵守目标站点条款及当地法律法规