bilibili-API-collect
bilibili-API-collect copied to clipboard
用户主页获取投稿列表 -352 新增校验
https://api.bilibili.com/x/space/wbi/arc/search?mid=2&ps=30&tid=0&pn=1&keyword=&order=pubdate&platform=web&web_location=1550101&order_avoided=true&dm_img_list=[]&dm_img_str=V2ViR0wgMS&dm_cover_img_str=QU5HTEUgKEludGVsLCBJbnRlbChSKSBIRCBHcmFwaGljcyBEaXJlY3QzRDExIHZzXzVfMCBwc181XzApR29vZ2xlIEluYy4gKEludGVsKQ&w_rid=e8319e347dca849eadcdd27f1a8a5a79&wts=1700567648
用户投稿多了dm_img_list、dm_img_str、dm_cover_img_str这3个值,缺少这3个值会报352错误,加上这3个值,wbi接口不添加wbi校验值都可以正常获取数据
{
'code': -352,
'message': '风控校验失败',
'ttl': 1,
'data': {
'v_voucher': 'voucher_605d9ef3-9ca5-4498-ace1-8613ecf7a24f'
}
}
是的,我也遇见同样问题
但是经过尝试,加了也还是有可能会有 -352 的报错,这三个字段似乎不是风控的关键内容
等待大佬
需要加User-Agent
需要加User-Agent
我添加过一下Header:
- Origin
- Referer
- Authority
- Accept
- Accept-Language
- Dnt
并添加了Chrome(v106)的浏览器指纹,但是依然风控,应该是别的原因
同样发现这个问题,关键是 dm_cover_img_str 这个参数,一旦缺省,直接352错误。
晚上计划研究一下
dm_img_str 和 dm_cover_img_str 的值似乎可以这样得到。
let version;
let rendererAndVendor;
const gl = document.createElement("canvas").getContext("webgl");
if (gl) {
version = gl.getParameter(gl.VERSION);
const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
if (debugInfo) {
rendererAndVendor = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) +
gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
}
}
if (version === undefined) { // 禁用了 WebGL
console.log("dm_img_str", "bm8gd2ViZ2");
console.log("dm_cover_img_str", "bm8gd2ViZ2");
} else {
console.log("dm_img_str", btoa(version).slice(0, -2));
if (rendererAndVendor === undefined) { // 禁用了 WEBGL_debug_renderer_info 扩展
console.log("dm_cover_img_str", "bm8gd2ViZ2wgZXh0ZW5zaW");
} else {
console.log("dm_cover_img_str", btoa(rendererAndVendor).slice(0, -2));
}
}
- Referer
不能加Referer。 加User-Agent和cookie
- Referer
不能加Referer。 加User-Agent和cookie
headers中加上cookie已暂时解决
经测试,cookie里必须要添加buvid3和buvid4。而请求url中的dm_cover_img_str为必须项,经解码后发现是GPU渲染信息,因此它为固定值,可以随便填
https://www.52pojie.cn/thread-1861424-1-1.html 这个参数已经可以解决了
不能加Referer。
Referer信息应该不是影响因素,我尝试过添加和移除的场景,被风控的时间是差不多的
这个我试了下,最后加了Headers加了个ua可以访问了,但是我并不确定是否频率高了仍会触发封控,需要观察。
HEADERS = { 'Referer': 'https://www.bilibili.com/', 'Connection': 'close', 'User-Agent': 'Mozilla/5.0' }
根据这几天的实验,cookie(如:buvid3, buvid4)、header(如:Referer,'User-Agent)、以及请求参数(如:dm_cover_img_str)并没有和风控有强关联,不管是否存在,风控的触发基本相同,目前观察到的,似乎会用请求内容(包括上述的cookir。header、请求参数)作为为请求限频的参数。如果每次请求随机生成并尽可能不重复可以极大的降低风控概率。
另外根据上述行为猜测风控可能会有一些其他参数、行为控制,比如cookie中的bili_ticket,buvid_fp,或者一些上报用户行为的接口相关
不知道大家是什么情况,这是我测试时的情况。简化过的参数如下,偶尔失败。
import requests headers = { # "authority": "api.bilibili.com", # "accept": "*/*", # "accept-language": "en,zh-CN;q=0.9,zh;q=0.8", # 这行代码之后会被取消注释 # "cache-control": "no-cache", "origin": "https://space.bilibili.com", # "pragma": "no-cache", "referer": "https://space.bilibili.com/2142762/video", # "sec-ch-ua": "^\\^Chromium^^;v=^\\^118^^, ^\\^Microsoft", # "sec-ch-ua-mobile": "?0", # "sec-ch-ua-platform": "^\\^Windows^^", # "sec-fetch-dest": "empty", # "sec-fetch-mode": "cors", # "sec-fetch-site": "same-site", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76", } cookies = { "buvid3": "58CBD4ED-4D82-666C-8EFE-337ABCED53DB95963infoc", "b_nut": "1701088795", # "_uuid": "65342583-1E84-E6105-F872-1A9C6FE2E38797168infoc", # "buvid4": "99832353-6338-2D1C-7AB7-F89A1A5DA21297090-023112712-", # "bili_ticket": "eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDEzNDc5OTcsImlhdCI6MTcwMTA4ODczNywicGx0IjotMX0.UcheAgY8MK1JqO6yqWO9vm0fJKjI06-F5BMUVucj2fk", # "bili_ticket_expires": "1701347937", # "buvid_fp": "094f1315a3795ae7695094f66ba4518e", # "b_lsid": "D810BE96C_18C1193F406", # "PVID": "1", # "innersign": "0", # "enable_web_push": "DISABLE", # "header_theme_version": "CLOSE", # "home_feed_column": "4", # "browser_resolution": "945-671" } url = "https://api.bilibili.com/x/space/wbi/arc/search" params = { "mid": "2142762", "ps": "30", "tid": "0", "pn": "1", "keyword": "", "order": "pubdate", "platform": "web", "web_location": "1550101", "order_avoided": "true", # "dm_img_list": "^\\[^\\]", # "dm_img_str": "V2ViR0wgMS4wIChPcGVuR0wgRVMgMi4wIENocm9taXVtKQ", # "dm_cover_img_str": "QU5HTEUgKEludGVsLCBJbnRlbChSKSBIRCBHcmFwaGljcyA2MzAgKDB4MDAwMDU5MUIpIERpcmVjdDNEMTEgdnNfNV8wIHBzXzVfMCwgRDNEMTEpR29vZ2xlIEluYy4gKEludGVsKQ", "w_rid": "0ea56ea45305ee113a85d1742ff3be12", "wts": "1701105288", } for i in range(20): response = requests.get( url, headers=headers, cookies=cookies, params=params ) print(response.text[:50])
如果请求头中使用
"accept-language": "en,zh-CN;q=0.9,zh;q=0.8",这样就没报错了,甚至不需要那 3 个dm开头的参数。
如 https://github.com/SocialSisterYi/bilibili-API-collect/issues/868#issuecomment-1827706741 所言,你可能需要更多的实验来排除,因为单纯添加或修改某一个header或产生类似重置限频的行为
需要在headers中手动加入cookies 但是问题来了,我都手动添加cookies了,还需要爬虫再跑一次就有点徒劳无功了,请问有什么方式可以获取新的cookies呢?
需要在headers中手动加入cookies 但是问题来了,我都手动添加cookies了,还需要爬虫再跑一次就有点徒劳无功了,请问有什么方式可以获取新的cookies呢?
https://api.bilibili.com/x/frontend/finger/spi
1 use chrome privacy mode , get ua && url's dm_img_str && dm_cover_img_str ,without time testing
2 login mode use ua , cookie's buvid3 && SESSDATA ,2day live
经测试,cookie里必须要添加buvid3和buvid4。而请求url中的dm_cover_img_str为必须项,经解码后发现是GPU渲染信息,因此它为固定值,可以随便填
11.29最新补充:dm_cover_img_str现在不能随便填了,经测试后面几个字符并不是标准的base64编码,但整体依然为固定值。可以直接从浏览器里复制出来用
经测试,cookie里必须要添加buvid3和buvid4。而请求url中的dm_cover_img_str为必须项,经解码后发现是GPU渲染信息,因此它为固定值,可以随便填
11.29最新补充:dm_cover_img_str现在不能随便填了,经测试后面几个字符并不是标准的base64编码,但整体依然为固定值。可以直接从浏览器里复制出来用
我就是直接复制的浏览器的值,这几天一直正常
dm_img_str解密后WebGL 1
dm_cover_img_str解密后ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0)Google Inc. (Intel)
所以其实没必要随便填,直接用现成的值就行了
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
mode 1 is okay 2days
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
mode 1 is okay 2days
thank U a lot
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
我也是,今天不行了
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
我也是,今天不行了
看上面ncdn大佬有解决办法
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
我也是,今天不行了
看上面ncdn大佬有解决办法
~是ua和那俩个值要对应,对吗~
我刚试了下,和ua无关,补上dm_img_list=[] 这个参数,加上dm_img_str和dm_cover_img_str就可以了
经测试,cookie里必须要添加buvid3和buvid4。而请求url中的dm_cover_img_str为必须项,经解码后发现是GPU渲染信息,因此它为固定值,可以随便填
11.29最新补充:dm_cover_img_str现在不能随便填了,经测试后面几个字符并不是标准的base64编码,但整体依然为固定值。可以直接从浏览器里复制出来用
应该是显卡和浏览器信息经过base64之后去掉最后两位,但是经过测试在dm_img_list置空的前提下,显卡信息加密出来的值本身并不校验【但是如果没有dm_img_list的轨迹的话,单个dm_cover_img_str请求多了之后有概率失败】。所以个人的解决方法是直接随机一个小数,并且用base64加密一下去掉最后两位,测了一下还是相对稳定的。
实测5次均成功。
- w_rid按照这个方式计算(字段顺序不对貌似有影响, 建议别改,下面的顺序是devtools里debug扣出来的, 并不是参数升序, 有一定区别):
填入对应的dm_img_str, dm_cover_img_str(这两个看起来是固定值), 以及mid, pn, ps
encrypt_string = "dm_cover_img_str={dm_cover_img_str}&dm_img_list=%5B%5D&dm_img_str={dm_img_str}&keyword=&mid={mid}&order=pubdate&order_avoided=true&platform=web&pn={pn}&ps={ps}&tid=&web_location="
计算w_rid时用上面的fmt出来的string + f"&wts={wts}" + 根据img_key和sub_key计算出来的key做一次md5得到
-
请求时的实际url需要用
encrypt_string+&w_rid={w_rid}+&wts={wts}这个顺序 -
分页查询的时候需要sleep 2-5s
这里只贴一下部份伪代码:
def get_wrid(self, params: str) -> str:
md5 = hashlib.md5()
md5.update(
(params + self.key).encode(), # self.key 就是img_key和sub_key计算的,我是直接从js里扣出来转python的这里就不贴了
)
return md5.hexdigest()
def request(self) -> dict:
wts = round(time.time())
params = self.encrypt_string_fmt.format(
mid=self.mid,
ps=self.page_size,
pn=self.page_number,
tid="",
web_location="",
dm_img_str=settings.BILIBILI_PARAM_DM_IMG_STR,
dm_cover_img_str=settings.BILIBILI_PARAM_DM_COVER_IMG_STR,
)
wrid = self.get_wrid(params + f"&wts={wts}")
params = "&".join([params, f"w_rid={wrid}", f"&wts={wts}"])
return requests.get(self.api, headers={"User-Agent": 这里用库换成随机的ua}, params=params)
实测5次均成功。
- w_rid按照这个方式计算(字段顺序不对貌似有影响, 建议别改,下面的顺序是devtools里debug扣出来的, 并不是参数升序, 有一定区别):
填入对应的
dm_img_str,dm_cover_img_str(这两个看起来是固定值), 以及mid,pn,psencrypt_string = "dm_cover_img_str={dm_cover_img_str}&dm_img_list=%5B%5D&dm_img_str={dm_img_str}&keyword=&mid={mid}&order=pubdate&order_avoided=true&platform=web&pn={pn}&ps={ps}&tid=&web_location="计算w_rid时用上面的fmt出来的string + f"&wts={wts}" + 根据
img_key和sub_key计算出来的key做一次md5得到
- 请求时的实际url需要用
encrypt_string+&w_rid={w_rid}+&wts={wts}这个顺序- 分页查询的时候需要sleep 2-5s
这里只贴一下部份伪代码:
def get_wrid(self, params: str) -> str: md5 = hashlib.md5() md5.update( (params + self.key).encode(), # self.key 就是img_key和sub_key计算的,我是直接从js里扣出来转python的这里就不贴了 ) return md5.hexdigest() def request(self) -> dict: wts = round(time.time()) params = self.encrypt_string_fmt.format( mid=self.mid, ps=self.page_size, pn=self.page_number, tid="", web_location="", dm_img_str=settings.BILIBILI_PARAM_DM_IMG_STR, dm_cover_img_str=settings.BILIBILI_PARAM_DM_COVER_IMG_STR, ) wrid = self.get_wrid(params + f"&wts={wts}") params = "&".join([params, f"w_rid={wrid}", f"&wts={wts}"]) return requests.get(self.api, headers={"User-Agent": 这里用库换成随机的ua}, params=params)
我目前是每次都随机数并base64加密来作为dm_img_str和dm_cover_img_str值,可以不用sleep,立刻获取数据
实测5次均成功。
- w_rid按照这个方式计算(字段顺序不对貌似有影响, 建议别改,下面的顺序是devtools里debug扣出来的, 并不是参数升序, 有一定区别):
填入对应的
dm_img_str,dm_cover_img_str(这两个看起来是固定值), 以及mid,pn,psencrypt_string = "dm_cover_img_str={dm_cover_img_str}&dm_img_list=%5B%5D&dm_img_str={dm_img_str}&keyword=&mid={mid}&order=pubdate&order_avoided=true&platform=web&pn={pn}&ps={ps}&tid=&web_location="计算w_rid时用上面的fmt出来的string + f"&wts={wts}" + 根据
img_key和sub_key计算出来的key做一次md5得到
- 请求时的实际url需要用
encrypt_string+&w_rid={w_rid}+&wts={wts}这个顺序- 分页查询的时候需要sleep 2-5s
这里只贴一下部份伪代码:
def get_wrid(self, params: str) -> str: md5 = hashlib.md5() md5.update( (params + self.key).encode(), # self.key 就是img_key和sub_key计算的,我是直接从js里扣出来转python的这里就不贴了 ) return md5.hexdigest() def request(self) -> dict: wts = round(time.time()) params = self.encrypt_string_fmt.format( mid=self.mid, ps=self.page_size, pn=self.page_number, tid="", web_location="", dm_img_str=settings.BILIBILI_PARAM_DM_IMG_STR, dm_cover_img_str=settings.BILIBILI_PARAM_DM_COVER_IMG_STR, ) wrid = self.get_wrid(params + f"&wts={wts}") params = "&".join([params, f"w_rid={wrid}", f"&wts={wts}"]) return requests.get(self.api, headers={"User-Agent": 这里用库换成随机的ua}, params=params)
增大测试次数发现在cookie中添加SESSDATA能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(

