Open o0HalfLife0o opened 11 months ago
是的,我也遇见同样问题
但是经过尝试,加了也还是有可能会有 -352 的报错,这三个字段似乎不是风控的关键内容
等待大佬
需要加User-Agent
需要加User-Agent
我添加过一下Header:
并添加了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呢?
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次均成功。
填入对应的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
,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)
我目前是每次都随机数并base64加密来作为dm_img_str和dm_cover_img_str值,可以不用sleep,立刻获取数据
实测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)
增大测试次数发现在cookie中添加SESSDATA能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
mode 1 is okay 2days
thank U a lot
什么意思,加 cookie 只能生效两天吗?
实测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)
增大测试次数发现在cookie中添加SESSDATA能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(
好像跟你们说的都没关系啊,直接复制完整cookie就能正常访问,浏览器邮件复制链接的到nodejs中直接用fetch跑,可以直接获得数据,不用这三个新参数,只用一个 https://api.bilibili.com/x/space/wbi/arc/search?mid=2 这个链接就有数据,没cookie的话怎么试都没用。我试了加了你们这三个参数,还是访问不了啊
实测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)
增大测试次数发现在cookie中添加SESSDATA能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(
好像跟你们说的都没关系啊,直接复制完整cookie就能正常访问,浏览器邮件复制链接的到nodejs中直接用fetch跑,可以直接获得数据,不用这三个新参数,只用一个 https://api.bilibili.com/x/space/wbi/arc/search?mid=2 这个链接就有数据,没cookie的话怎么试都没用。我试了加了你们这三个参数,还是访问不了啊
上面复现的不是基于cookie的, 要完整的url参数才可以, 参考encrypt_string
以及后面重新拼接url的部份, 这个复现方案是不需要cookie的,只需要mid。需要cookie的话要考虑cookie的维护复杂度吧,这个没测试过,直接复制cookie能访问的话可能是阿B的策略允许
我目前是每次都随机数并base64加密来作为dm_img_str和dm_cover_img_str值,可以不用sleep,立刻获取数据
不知道你们用的是什么随机数,至少我无论是base64随机数还是随机字符还是352。是不是我请求的参数有问题。
curl -s -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" -e "https://space.bilibili.com/" -H "Content-Type: application/json" -H "accept-language: zh-CN,zh;q=0.9" "https://api.bilibili.com/x/space/wbi/arc/search?mid=2&tid=0&order=pubdate&order_avoided=true&platform=web&web_location=1550101&dm_img_list=[]&dm_img_str=ODQ5NDgwND&dm_cover_img_str=NDg0OTM0MD&ps=30&pn=1&w_rid=7d327b25554dde6e27c8d65775288811&wts=1702221586" -b "buvid3=055AC15E-C41A-E796-602B-95A5E80CAA7F18734infoc; buvid4=3B796197-5865-F7B6-EC4C-32F618CA502A18734-023121015-"
我目前是每次都随机数并base64加密来作为dm_img_str和dm_cover_img_str值,可以不用sleep,立刻获取数据
不知道你们用的是什么随机数,至少我无论是base64随机数还是随机字符还是352。是不是我请求的参数有问题。
curl -s -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" -e "https://space.bilibili.com/" -H "Content-Type: application/json" -H "accept-language: zh-CN,zh;q=0.9" "https://api.bilibili.com/x/space/wbi/arc/search?mid=2&tid=0&order=pubdate&order_avoided=true&platform=web&web_location=1550101&dm_img_list=[]&dm_img_str=ODQ5NDgwND&dm_cover_img_str=NDg0OTM0MD&ps=30&pn=1&w_rid=7d327b25554dde6e27c8d65775288811&wts=1702221586" -b "buvid3=055AC15E-C41A-E796-602B-95A5E80CAA7F18734infoc; buvid4=3B796197-5865-F7B6-EC4C-32F618CA502A18734-023121015-"
params["dm_img_list"] = []
dm_rand = ['QQ','Qg','Qw','RA','RQ']
params["dm_img_str"] = random.choice(dm_rand)
params["dm_cover_img_str"] = random.choice(dm_rand)
实测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)
增大测试次数发现在cookie中添加SESSDATA能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(
好像跟你们说的都没关系啊,直接复制完整cookie就能正常访问,浏览器邮件复制链接的到nodejs中直接用fetch跑,可以直接获得数据,不用这三个新参数,只用一个 https://api.bilibili.com/x/space/wbi/arc/search?mid=2 这个链接就有数据,没cookie的话怎么试都没用。我试了加了你们这三个参数,还是访问不了啊
上面复现的不是基于cookie的, 要完整的url参数才可以, 参考
encrypt_string
以及后面重新拼接url的部份, 这个复现方案是不需要cookie的,只需要mid。需要cookie的话要考虑cookie的维护复杂度吧,这个没测试过,直接复制cookie能访问的话可能是阿B的策略允许
@iiicebearrr 你的意思是这两种情况都可以实现访问吗?两种都可以访问?一种用cookie,另外一种用wbi,还有现在新加的dm_img_list、dm_img_str、dm_cover_img_str 这几个参数吗
实测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)
增大测试次数发现在cookie中添加SESSDATA能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(
好像跟你们说的都没关系啊,直接复制完整cookie就能正常访问,浏览器邮件复制链接的到nodejs中直接用fetch跑,可以直接获得数据,不用这三个新参数,只用一个 https://api.bilibili.com/x/space/wbi/arc/search?mid=2 这个链接就有数据,没cookie的话怎么试都没用。我试了加了你们这三个参数,还是访问不了啊
上面复现的不是基于cookie的, 要完整的url参数才可以, 参考
encrypt_string
以及后面重新拼接url的部份, 这个复现方案是不需要cookie的,只需要mid。需要cookie的话要考虑cookie的维护复杂度吧,这个没测试过,直接复制cookie能访问的话可能是阿B的策略允许@iiicebearrr 你的意思是这两种情况都可以实现访问吗?两种都可以访问?一种用cookie,另外一种用wbi,还有现在新加的dm_img_list、dm_img_str、dm_cover_img_str 这几个参数吗
我给出的复现方案是不需要cookie的,只需要提供mid就能访问到接口数据。
而且我上面给出的复现方案是专门针对主页接口的(https://api.bilibili.com/x/space/wbi/arc/search), 具体可以看下我的个人仓库spiders_for_all中的spiders_for_all.bilibili.spiders.AuthorSpider
的实现细节, 这里我不贴具体链接了。
至于其他方案(cookie/wbi等)我没有测试过,你可以参考一下其他用户的回复。
虽然感觉楼上都跑题了, wbi 鉴权错误只会导致返回个 v_voucher, 错误码还是 0. 出现 -412 之类的错误考虑 Cookie 没有或者不合法
ts实现,无需cookie
,dm_img_str
等参数
你也可以在这里看源码:https://github.com/renmu123/biliAPI/blob/master/src/user/index.ts#L82
实现来源:https://www.52pojie.cn/thread-1862056-1-1.html
/**
* 用户投稿列表
*/
async getVideos(params: {
mid: number;
ps?: number;
pn?: number;
tid?: number;
keyword?: string;
order?: "pubdate" | "click" | "stow";
}) {
const defaultParams = {
ps: "30",
tid: "0",
pn: "1",
keyword: "",
order: "pubdate",
platform: "web",
web_location: "1550101",
order_avoided: "true",
};
const cookie =
"buvid3=57ADE427-90A8-6E7D-F341-02E62CA23E1B39631infoc;b_nut=1701088795";
const signParams = await this.client.WbiSign({
...defaultParams,
...params,
});
return this.request.get(
`https://api.bilibili.com/x/space/wbi/arc/search?${signParams}`,
{
headers: {
cookie: cookie,
"User-Agent": "Mozilla/5.0",
origin: "https://space.bilibili.com",
"accept-language": "en,zh-CN;q=0.9,zh;q=0.8",
},
}
);
}
加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?
mode 1 is okay 2days
thank U a lot
什么意思,加 cookie 只能生效两天吗?
大佬的意思是登录状态下的cookies两天内有效,未登陆的cookies永久有效。我照这个方法试了下到现在还很稳定。
实测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)
增大测试次数发现在cookie中添加SESSDATA能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(
好像跟你们说的都没关系啊,直接复制完整cookie就能正常访问,浏览器邮件复制链接的到nodejs中直接用fetch跑,可以直接获得数据,不用这三个新参数,只用一个 https://api.bilibili.com/x/space/wbi/arc/search?mid=2 这个链接就有数据,没cookie的话怎么试都没用。我试了加了你们这三个参数,还是访问不了啊
上面复现的不是基于cookie的, 要完整的url参数才可以, 参考
encrypt_string
以及后面重新拼接url的部份, 这个复现方案是不需要cookie的,只需要mid。需要cookie的话要考虑cookie的维护复杂度吧,这个没测试过,直接复制cookie能访问的话可能是阿B的策略允许@iiicebearrr 你的意思是这两种情况都可以实现访问吗?两种都可以访问?一种用cookie,另外一种用wbi,还有现在新加的dm_img_list、dm_img_str、dm_cover_img_str 这几个参数吗
我给出的复现方案是不需要cookie的,只需要提供mid就能访问到接口数据。 而且我上面给出的复现方案是专门针对主页接口的(https://api.bilibili.com/x/space/wbi/arc/search), 具体可以看下我的个人仓库spiders_for_all中的
spiders_for_all.bilibili.spiders.AuthorSpider
的实现细节, 这里我不贴具体链接了。至于其他方案(cookie/wbi等)我没有测试过,你可以参考一下其他用户的回复。
请求头中有你的登录信息, 如果在无痕模式下就会出现352
实测dm_img_str
, dm_cover_img_str
可为随机长度的可打印字符再base64, 且user-agent
会对校验造成显著影响.
对于某个ip, 一般会有多个ua是免校验的, 即使不sleep异步请求99个mid也不会出现-352
(特殊的, Mozilla/5.0
似乎每个ip都是免校验的), 这种ua到了另一个ip不一定免校验, 这种ua和版本号有关, 即便只把版本号改为上/下个版本, 也会丢失该效果, 但修改操作系统不会产生影响. 暂不确定这种ua会不会因为大量请求重新被拉黑
对于由python的fake_useragent
库所生成的ua, 在不sleep异步请求99个mid时大约\frac{1}{3}的请求会出现-352
如果使用非免校验的ua, 不sleep异步请求99个mid, 大约只有\frac{1}{5}不出现-352
错误, 且短时间内使用该ua请求任意mid都是-352
未测试cookie
, buvid3
对其的影响, 有没有referer
和accept-language
对其没有影响
测试(sign函数自行实现):
ua = fake_useragent.FakeUserAgent()
async def req(client, mid):
params = {
'mid': str(mid),
'ps': '30',
'pn': '1',
'order': 'pubdate',
'dm_img_list': '[]',
'dm_img_str': base64.b64encode("".join(random.choices(string.printable, k=random.randint(16, 64))).encode())[:-2].decode(),
'dm_cover_img_str': base64.b64encode("".join(random.choices(string.printable, k=random.randint(32, 128))).encode())[:-2].decode(),
'wts': str(int(time.time()))
}
response = await client.get(
'https://api.bilibili.com/x/space/wbi/arc/search',
headers={'user-agent': ua.random},
params=sign(params)
)
code = response.json()['code']
return code
async def main():
client = httpx.AsyncClient(transport=httpx.AsyncHTTPTransport(retries=2, http2=True))
codes = await asyncio.gather(*(
req(client, mid)
for mid in range(1, 100)
))
print(Counter(codes))
asyncio.run(main())
emm,我这边也观察到有 -352 相关的 issue...
这边有大佬做个总结吗,看迷糊了,具体原因是新参数 dm_img_list
dm_img_str
dm_cover_img_str
吗?
直接拷贝 WEB 上生成的链接,然后加上 HEADERS={'Referer': 'https://www.bilibili.com/', 'User-Agent': 'Mozilla/5.0'}
我这就能不限速请求 700+ 次数,姑且是看作只有三个参数的改动
近几天感觉风控没有那么严格了。如果是一个星期前,连Chrome无痕模式正常浏览用户投稿页面都有概率出现
-352
。
那是因为 dm_img_list
缺失吧
这个就不太理解了...accept-language
算什么鬼
但是在请求头中加入
accept-language: en,zh-CN;q=0.9,zh;q=0.8
就可以连续请求了。
https://www.52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=1862056&pid=48739723
emm,我这边也观察到有 -352 相关的 issue...
这边有大佬做个总结吗,看迷糊了,具体原因是新参数
dm_img_list
dm_img_str
dm_cover_img_str
吗?直接拷贝 WEB 上生成的链接,然后加上
HEADERS={'Referer': 'https://www.bilibili.com/', 'User-Agent': 'Mozilla/5.0'}
我这就能不限速请求 700+ 次数,姑且是看作只有三个参数的改动
Mozilla/5.0
这个ua好像有点特殊, 其他会出现-352
的链接都可以用这个ua不限量高并发请求
emm,我这边也观察到有 -352 相关的 issue... 这边有大佬做个总结吗,看迷糊了,具体原因是新参数
dm_img_list
dm_img_str
dm_cover_img_str
吗? 直接拷贝 WEB 上生成的链接,然后加上HEADERS={'Referer': 'https://www.bilibili.com/', 'User-Agent': 'Mozilla/5.0'}
我这就能不限速请求 700+ 次数,姑且是看作只有三个参数的改动
Mozilla/5.0
这个ua好像有点特殊, 其他会出现-352
的链接都可以用这个ua不限量高并发请求
这样吗?那我再测试下别的
这个就不太理解了...
accept-language
算什么鬼但是在请求头中加入
accept-language: en,zh-CN;q=0.9,zh;q=0.8
就可以连续请求了。52pojie.cn/forum.php?mod=redirect&goto=findpost&ptid=1862056&pid=48739723
这边测试加上accept-language: en,zh-CN;q=0.9,zh;q=0.8
并没有明显减少-352
出现次数, 这边测试开100并发只有18个成功, 不加也有16个成功, 但是UA用Mozilla/5.0
100并发也可以100%成功
呆滞.jpg 虽然这个 headers
很诱人,但还有别的接口是这个太假的 header
过不了的吧
是不是后端正则偶然写炸了...
不同的 event 会产生不同的 type,观察 dm_img_list
当前无论输入什么值都不会影响访问,即使 json 格式错误,有待后续,估计B站没做好就上线了
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from datetime import datetime
# 提供的数据
data = []
# 解析时间戳并按时间排序
data.sort(key=lambda x: x["timestamp"])
timestamps = [datetime.utcfromtimestamp(entry["timestamp"]) for entry in data]
# 提取坐标
x_values = [entry["x"] for entry in data]
y_values = [entry["y"] for entry in data]
z_values = [entry["z"] for entry in data]
# 创建3D图表
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# 连线绘制
ax.plot(x_values, y_values, z_values, label='Trajectory', marker='o')
# 添加标题和标签
ax.set_title('3D Trajectory Visualization')
ax.set_xlabel('X Coordinate')
ax.set_ylabel('Y Coordinate')
ax.set_zlabel('Z Coordinate')
# 显示图例
ax.legend()
# 显示图表
plt.show()
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校验值都可以正常获取数据