bilibili-API-collect icon indicating copy to clipboard operation
bilibili-API-collect copied to clipboard

用户主页获取投稿列表 -352 新增校验

Open o0HalfLife0o opened this issue 2 years ago • 150 comments

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_listdm_img_strdm_cover_img_str这3个值,缺少这3个值会报352错误,加上这3个值,wbi接口不添加wbi校验值都可以正常获取数据

{
    'code': -352,
    'message': '风控校验失败',
    'ttl': 1,
    'data': {
        'v_voucher': 'voucher_605d9ef3-9ca5-4498-ace1-8613ecf7a24f'
    }
}

o0HalfLife0o avatar Nov 21 '23 12:11 o0HalfLife0o

是的,我也遇见同样问题

zzhjiyin avatar Nov 21 '23 14:11 zzhjiyin

但是经过尝试,加了也还是有可能会有 -352 的报错,这三个字段似乎不是风控的关键内容

Luoxin avatar Nov 22 '23 02:11 Luoxin

等待大佬

power721 avatar Nov 22 '23 08:11 power721

需要加User-Agent

power721 avatar Nov 22 '23 09:11 power721

需要加User-Agent

我添加过一下Header:

  • Origin
  • Referer
  • Authority
  • Accept
  • Accept-Language
  • Dnt

并添加了Chrome(v106)的浏览器指纹,但是依然风控,应该是别的原因

Luoxin avatar Nov 22 '23 09:11 Luoxin

同样发现这个问题,关键是 dm_cover_img_str 这个参数,一旦缺省,直接352错误。 晚上计划研究一下

nethunter787 avatar Nov 23 '23 02:11 nethunter787

dm_img_strdm_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));
  }
}

0f-0b avatar Nov 23 '23 04:11 0f-0b

  • Referer

不能加Referer。 加User-Agent和cookie

power721 avatar Nov 23 '23 13:11 power721

  • Referer

不能加Referer。 加User-Agent和cookie

headers中加上cookie已暂时解决

zzhjiyin avatar Nov 23 '23 16:11 zzhjiyin

经测试,cookie里必须要添加buvid3和buvid4。而请求url中的dm_cover_img_str为必须项,经解码后发现是GPU渲染信息,因此它为固定值,可以随便填

CzJam avatar Nov 24 '23 05:11 CzJam

https://www.52pojie.cn/thread-1861424-1-1.html 这个参数已经可以解决了

linix999 avatar Nov 24 '23 13:11 linix999

不能加Referer。

Referer信息应该不是影响因素,我尝试过添加和移除的场景,被风控的时间是差不多的

Luoxin avatar Nov 25 '23 00:11 Luoxin

这个我试了下,最后加了Headers加了个ua可以访问了,但是我并不确定是否频率高了仍会触发封控,需要观察。 HEADERS = { 'Referer': 'https://www.bilibili.com/', 'Connection': 'close', 'User-Agent': 'Mozilla/5.0' }

WolveStorm avatar Nov 27 '23 07:11 WolveStorm

根据这几天的实验,cookie(如:buvid3, buvid4)、header(如:Referer'User-Agent)、以及请求参数(如:dm_cover_img_str)并没有和风控有强关联,不管是否存在,风控的触发基本相同,目前观察到的,似乎会用请求内容(包括上述的cookir。header、请求参数)作为为请求限频的参数。如果每次请求随机生成并尽可能不重复可以极大的降低风控概率。 另外根据上述行为猜测风控可能会有一些其他参数、行为控制,比如cookie中的bili_ticket,buvid_fp,或者一些上报用户行为的接口相关

Luoxin avatar Nov 27 '23 12:11 Luoxin

不知道大家是什么情况,这是我测试时的情况。简化过的参数如下,偶尔失败。

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])

Snipaste_2023-11-28_02-10-25

如果请求头中使用 "accept-language": "en,zh-CN;q=0.9,zh;q=0.8",这样就没报错了,甚至不需要那 3 个 dm 开头的参数。

Snipaste_2023-11-28_02-10-57

如 https://github.com/SocialSisterYi/bilibili-API-collect/issues/868#issuecomment-1827706741 所言,你可能需要更多的实验来排除,因为单纯添加或修改某一个header或产生类似重置限频的行为

Luoxin avatar Nov 27 '23 23:11 Luoxin

需要在headers中手动加入cookies 但是问题来了,我都手动添加cookies了,还需要爬虫再跑一次就有点徒劳无功了,请问有什么方式可以获取新的cookies呢?

zzhjiyin avatar Nov 28 '23 13:11 zzhjiyin

需要在headers中手动加入cookies 但是问题来了,我都手动添加cookies了,还需要爬虫再跑一次就有点徒劳无功了,请问有什么方式可以获取新的cookies呢?

https://api.bilibili.com/x/frontend/finger/spi

Allenyep avatar Nov 29 '23 04:11 Allenyep

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

ncdn avatar Nov 29 '23 09:11 ncdn

经测试,cookie里必须要添加buvid3和buvid4。而请求url中的dm_cover_img_str为必须项,经解码后发现是GPU渲染信息,因此它为固定值,可以随便填

11.29最新补充:dm_cover_img_str现在不能随便填了,经测试后面几个字符并不是标准的base64编码,但整体依然为固定值。可以直接从浏览器里复制出来用

CzJam avatar Nov 29 '23 14:11 CzJam

经测试,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) 所以其实没必要随便填,直接用现成的值就行了

o0HalfLife0o avatar Nov 29 '23 15:11 o0HalfLife0o

加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?

TommyLee9527 avatar Dec 01 '23 09:12 TommyLee9527

加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?

mode 1 is okay 2days

ncdn avatar Dec 01 '23 09:12 ncdn

加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?

mode 1 is okay 2days

thank U a lot

TommyLee9527 avatar Dec 01 '23 09:12 TommyLee9527

加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?

我也是,今天不行了

o0HalfLife0o avatar Dec 01 '23 11:12 o0HalfLife0o

加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?

我也是,今天不行了

看上面ncdn大佬有解决办法

TommyLee9527 avatar Dec 01 '23 15:12 TommyLee9527

加了cookies和dm_cover_img_str后前几天都很正常,但是今天突然发现又报-352了,又有什么规则变了吗?

我也是,今天不行了

看上面ncdn大佬有解决办法

~是ua和那俩个值要对应,对吗~ 我刚试了下,和ua无关,补上dm_img_list=[] 这个参数,加上dm_img_strdm_cover_img_str就可以了

o0HalfLife0o avatar Dec 01 '23 15:12 o0HalfLife0o

经测试,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加密一下去掉最后两位,测了一下还是相对稳定的。

srx-2000 avatar Dec 06 '23 06:12 srx-2000

实测5次均成功。

  1. 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_keysub_key计算出来的key做一次md5得到

  1. 请求时的实际url需要用 encrypt_string + &w_rid={w_rid} + &wts={wts}这个顺序

  2. 分页查询的时候需要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)

iiicebearrr avatar Dec 10 '23 04:12 iiicebearrr

实测5次均成功。

  1. 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_keysub_key计算出来的key做一次md5得到

  1. 请求时的实际url需要用 encrypt_string + &w_rid={w_rid} + &wts={wts}这个顺序
  2. 分页查询的时候需要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,立刻获取数据

o0HalfLife0o avatar Dec 10 '23 04:12 o0HalfLife0o

实测5次均成功。

  1. 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_keysub_key计算出来的key做一次md5得到

  1. 请求时的实际url需要用 encrypt_string + &w_rid={w_rid} + &wts={wts}这个顺序
  2. 分页查询的时候需要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能一定程度上提高成功率, 但是分页多了以后仍然有可能会触发风控:(

iiicebearrr avatar Dec 10 '23 04:12 iiicebearrr