本文将深入讲解两大主流短视频平台(抖音、B站)的爬虫实战技术,提供可直接运行的代码解决方案,并分享突破反爬机制的核心技巧。
一、平台特性与爬虫难点对比
平台 | 数据价值 | 主要反爬措施 | 推荐抓取方式 |
---|---|---|---|
抖音 | 视频数据、用户画像、热榜 | 签名验证、TLS指纹、滑块验证 | Web接口+签名破解 |
B站 | 弹幕、评论、视频元数据 | Referer校验、Cookie验证、频率限制 | API接口+模拟登录 |
二、抖音爬虫实战:获取用户视频数据
核心原理:破解X-Bogus签名
抖音通过X-Bogus参数保护接口,需使用JavaScript逆向技术生成签名。
python
import requests import execjs # 执行JS代码 import json # 加载本地JS签名生成脚本(需提前保存) with open('douyin_xbogus.js', 'r') as f: js_code = f.read() ctx = execjs.compile(js_code) def get_douyin_user_videos(user_id): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Cookie': '你的抖音Cookie' # 通过浏览器获取 } # 构造原始URL base_url = f"https://www.douyin.com/aweme/v1/web/aweme/post/?device_platform=webapp&user_id={user_id}" # 通过JS生成X-Bogus签名 xbogus = ctx.call('generateXbogus', base_url) signed_url = base_url + "&X-Bogus=" + xbogus try: response = requests.get(signed_url, headers=headers) data = response.json() # 解析视频数据 videos = [] for aweme in data['aweme_list']: video_info = { 'id': aweme['aweme_id'], 'desc': aweme['desc'], 'create_time': aweme['create_time'], 'duration': aweme['duration'] // 1000, # 转为秒 'likes': aweme['statistics']['digg_count'], 'comments': aweme['statistics']['comment_count'], 'url': aweme['video']['play_addr']['url_list'][0] } videos.append(video_info) return videos except Exception as e: print(f"抓取失败: {str(e)}") return [] # 使用示例 if __name__ == "__main__": user_id = "123456789" # 替换为目标用户ID video_data = get_douyin_user_videos(user_id) print(f"获取到{len(video_data)}个视频") for video in video_data[:3]: print(video['desc'])
关键技术点:
-
X-Bogus签名生成:
-
需要逆向抖音官方JavaScript生成算法
-
使用PyExecJS执行JS代码生成有效签名
-
-
关键参数获取:
-
user_id
:通过分享链接获取(需URL解码) -
Cookie
:登录后从浏览器开发者工具获取
-
-
数据解析技巧:
-
视频真实地址在
play_addr.url_list
-
时间戳需要转换格式
-
注:完整X-Bogus生成JS代码需单独获取(因篇幅限制未展示)
三、B站爬虫实战:获取视频弹幕与评论
方案1:直接获取弹幕数据(无需登录)
python
import requests import re import xml.etree.ElementTree as ET def get_bilibili_danmaku(cid): """ 通过视频CID获取弹幕 """ url = f"https://api.bilibili.com/x/v1/dm/list.so?oid={cid}" response = requests.get(url) response.encoding = 'utf-8' # 解析XML弹幕数据 danmaku = [] root = ET.fromstring(response.text) for d in root.findall('d'): attrs = d.attrib['p'].split(',') danmaku.append({ 'time': float(attrs[0]), 'type': int(attrs[1]), 'size': int(attrs[2]), 'color': f"#{int(attrs[3]):06X}", 'timestamp': int(attrs[4]), 'text': d.text }) return danmaku # 使用示例 cid = "45678901" # 通过视频API获取 danmaku_data = get_bilibili_danmaku(cid) print(f"获取到{len(danmaku_data)}条弹幕")
方案2:获取视频评论(需模拟登录)
python
import requests import time import random def get_bilibili_comments(bvid): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Referer': f'https://www.bilibili.com/video/{bvid}', 'Cookie': '你的B站Cookie' } comments = [] page = 1 while True: url = f"https://api.bilibili.com/x/v2/reply?jsonp=jsonp&pn={page}&type=1&oid={get_aid(bvid)}&sort=2" try: response = requests.get(url, headers=headers) data = response.json() if data['code'] != 0: print(f"错误: {data['message']}") break # 解析评论数据 for reply in data['data']['replies']: comments.append({ 'user': reply['member']['uname'], 'content': reply['content']['message'], 'like': reply['like'], 'time': time.strftime("%Y-%m-%d %H:%M", time.localtime(reply['ctime'])) }) print(f"已获取第{page}页评论") page += 1 # 随机延迟防止封禁 time.sleep(random.uniform(1.5, 3)) # 检查是否还有下一页 if page > data['data']['page']['count'] // 20: break except Exception as e: print(f"抓取出错: {str(e)}") break return comments def get_aid(bvid): """ 将BV号转换为AV号 """ table = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF' tr = {table[i]: i for i in range(58)} s = [11, 10, 3, 8, 4, 6] xor = 177451812 add = 8728348608 r = 0 for i in range(6): r += tr[bvid[s[i]]] * 58 ** i return (r - add) ^ xor # 使用示例 if __name__ == "__main__": bvid = "BV1gK4y1N7Jb" # 替换为目标视频BV号 comment_data = get_bilibili_comments(bvid) print(f"获取到{len(comment_data)}条评论")
关键技术点:
-
CID/AID获取:
-
弹幕需要CID参数(通过视频API获取)
-
评论需要AID(BV号需转换为AV号)
-
-
反爬突破技巧:
-
必须携带Referer请求头
-
Cookie需定期更新(有效期约1天)
-
请求间隔需随机化(1-3秒)
-
-
数据解析:
-
弹幕为XML格式,属性包含位置/颜色/时间
-
评论API返回分页JSON数据
-
四、高级反爬对抗方案
反爬类型 | 解决方案 | 工具推荐 |
---|---|---|
签名验证 | JavaScript逆向 | PyExecJS/Frida |
TLS指纹 | 修改客户端指纹 | curl_cffi/requests_toolbelt |
滑块验证 | 打码平台/OCR识别 | ddddocr/第三方打码API |
IP限制 | 代理IP轮换 | 快代理/站大爷 |
代理IP示例代码:
python
from itertools import cycle proxies = cycle([ 'http://user:pass@192.168.1.1:8080', 'http://user:pass@192.168.1.2:8080' ]) def make_request(url): proxy = next(proxies) try: return requests.get(url, proxies={"http": proxy}, timeout=10) except: return make_request(url) # 自动切换下一个代理
五、法律合规边界
-
允许操作:
-
抓取公开视频信息(非隐私内容)
-
个人学习研究目的
-
遵守robots.txt限制
-
-
禁止行为:
-
破解付费内容
-
抓取用户私信/手机号等隐私
-
商业用途未经授权
-
高频请求影响服务(>1次/秒)
-
建议:商业项目使用官方API(抖音开放平台/B站开放接口),个人学习控制请求频率
六、最佳实践建议
-
数据存储优化:
-
使用消息队列(RabbitMQ)缓冲请求
-
分布式存储(MongoDB分片集群)
-
-
错误处理机制:
python
# 重试装饰器示例 from tenacity import retry, stop_after_attempt, wait_random @retry(stop=stop_after_attempt(3), wait=wait_random(min=2, max=5)) def safe_request(url): response = requests.get(url) response.raise_for_status() return response
-
监控体系:
-
成功率监控(Prometheus)
-
代理IP可用性检测
-
自动切换签名算法版本
-
通过本指南,你可快速构建抖音/B站数据采集系统。随着平台反爬策略升级,需要持续关注接口变化并更新破解方案。建议优先考虑官方API方案,复杂场景可结合Selenium模拟真人操作。