Traitor 发表于 2022-3-27 18:29

一个获取B站视频封面的小工具

本帖最后由 Traitor 于 2022-3-28 14:04 编辑

刚入门Python的小菜鸡,用的是面向过程写的,代码有点乱,有什么问题还望指出,代码有点长。
最下面有开源地址和附件


说明:
1.如果视频的分p则直接输出每个视频的封面信息,不是则输出一个视频的封面信息。
2.每集番剧封面也就是带有ep号的表示某一集,电影封面也是带ep号。
3.md链接则是直接获取该番剧的全部封面,一般点击b站番剧下面的番剧标题,就可以进入到该番剧的md链接下了。
链接样式:
https://www.bilibili.com/video/BV1wu411B7rA?spm_id_from=333.851.b_7265636f6d6d656e64.1
【warframe 新披饰 哪吒同款战损版 这次就原谅你了 奸商导购-哔哩哔哩】
https://b23.tv/pkXCmvnhttps://www.bilibili.com/bangumi/play/ep426702from_spmid=666.25.titbit.0
【《Re:从零开始的异世界生活 第二季 后半》 NCOP-哔哩哔哩番剧】
https://b23.tv/ep400067https://www.bilibili.com/bangumi/play/ss40260from_spmid=666.4.0.0
https://www.bilibili.com/video/av679711482


注意:
1.还有一种视频是分p但是不能获取全部分p的封面,也算是一个小bug吧
2.如果该番剧是即将上线的情况下,md号只能获取到该番剧的海报图和相关信息,同样ss号不能获取到内容
3.如果输入了错误的信息则返回空


支持: bv号、av号、ep号、ss号、md号、带有bv号链接、av号链接、ep链接、ss号链接、md号链接、手机端分享链接直接粘贴即可


更新:2022年3月28日14:02 修改了输出内容的逻辑让代码看起来不是那么复杂


#!/usr/bin/python
# -- coding: utf-8 --
# @Author : Small_tred
# @Time : 2022/3/28 13:11
# !/usr/bin/python
# -- coding: utf-8 --
# @Author : Small_tred
# @Time : 2022/3/25 13:54
import requests
import re
import biliBV


def handleUrl(in_url):
    """判断链接是否为跳转 获取真实链接"""
    b_url = re.search(r"+://[^\s]*", in_url)
    if b_url is not None:
      response = requests.get(b_url.group(0), allow_redirects=False)
      if response.status_code == 302:
            t_url = requests.get(b_url.group(0)).url
            return t_url
      elif response.status_code == 301:
            t_url = requests.get(b_url.group(0)).url
            return t_url
      else:
            return b_url.group(0)


def regexBv(true_url):
    """匹配BV号"""
    bv_id = re.search(r'(BV.*?).{10}', true_url)
    if bv_id is not None:
      return bv_id.group(0)


def regexAv(true_url):
    """匹配av号"""
    av_id = re.search(r"(av.*?)\d+", true_url)
    if av_id is not None:
      bv_id = biliBV.encode(av_id.group(0))
      return bv_id


def regexEp(true_url):
    """匹配ep号"""
    ep_id = re.search(r"(ep.*?)\d+", true_url)
    if ep_id is not None:
      return ep_id.group(0)


def regexSs(true_url):
    """匹配SS号"""
    ss_id = re.search(r"(ss.*?)\d+", true_url)
    if ss_id is not None:
      return ss_id.group(0)
    else:
      return None


def regexMd(true_url):
    """匹配Med号"""
    med_id = re.search(r"(md.*?)\d+", true_url)
    if med_id is not None:
      return med_id.group(0)
    else:
      return None


# 请求API
def requestsBvVideoApi(bvid):
    api = "https://api.bilibili.com/x/web-interface/view?bvid="
    response = requests.get(api + bvid).json()
    if response["code"] == 0:
      return response


def requestsEpVideoApi(epid):
    api = "https://api.bilibili.com/pgc/view/web/season?ep_id="
    response = requests.get(api + epid).json()
    if response["code"] == 0:
      return response


def requestsSsVideoApi(ssid):
    api = "https://api.bilibili.com/pgc/view/web/season?season_id="
    response = requests.get(api + ssid).json()
    if response["code"] == 0:
      return response


def requestsMdVideoApi(mdid):
    api = "https://api.bilibili.com/pgc/review/user?media_id="
    response = requests.get(api + mdid).json()
    if response["code"] == 0:
      return response


def requestsAllVideoApi(ssid):
    api = "https://api.bilibili.com/pgc/web/season/section?season_id="
    response = requests.get(api + ssid).json()
    if response["code"] == 0:
      return response


def handleVideoBvResult(response_result):
    """根据BV号 判断是否有分P 是返回全部分P的信息 否返回该视频的封面"""
    av = "av"
    bilibili = "https://www.bilibili.com/"
    ls = []
    if response_result is not None:
      if response_result.get("data").get("ugc_season") is not None:
            if len(response_result.get("data").get("ugc_season").get("sections")) != 0:
                for vds in response_result.get("data").get("ugc_season").get("sections"):
                  for vd in vds.get("episodes"):
                        vd_title = vd.get("title")
                        vd_cover = vd.get("arc").get("pic")
                        vd_bvid = vd.get("bvid")
                        vd_avid = vd.get("aid")
                        data = {
                            "title": vd_title,
                            "image": vd_cover,
                            "bvid": vd_bvid,
                            "avid": av + str(vd_avid),
                            "url": bilibili + vd_bvid,
                        }
                        ls.append(data)
                  return ls
      else:
            vd_data = response_result.get("data")
            vd_title = vd_data.get("title")
            vd_cover = vd_data.get("pic")
            vd_bvid = vd_data.get("bvid")
            vd_avid = vd_data.get("aid")
            data = {
                "title": vd_title,
                "image": vd_cover,
                "bvid": vd_bvid,
                "avid": av + str(vd_avid),
                "url": bilibili + vd_bvid,
            }
            return data
    else:
      return "Not"


def handleEpisodeResult(response_result, epid):
    """1.判断请求内容是否存在 2.判断番剧是否上线是继续判断是pv/小剧场还是番剧 否 判断是否为pv/小剧场"""
    av = "av"
    if response_result is not None:
      if len(response_result.get("result").get("episodes")) != 0:
            for eps in response_result.get("result").get("episodes"):
                if eps.get("id") == int(epid):
                  ep_title = eps.get("share_copy")
                  ep_cover = eps.get("cover")
                  ep_bvid = eps.get("bvid")
                  ep_avid = eps.get("aid")
                  ep_url = eps.get("share_url")
                  data = {
                        "title": ep_title,
                        "image": ep_cover,
                        "bvid": ep_bvid,
                        "avid": av + str(ep_avid),
                        "url": ep_url,
                  }
                  return data
                else:
                  if response_result.get("result").get("section") is not None:
                        if len(response_result.get("result").get("section")) != 0:
                            for pvs in response_result.get("result").get("section"):
                              for pv in (pvs.get("episodes")):
                                    if pv.get("id") == int(epid):
                                        ep_pv_title = pv.get("share_copy")
                                        ep_pv_cover = pv.get("cover")
                                        ep_pv_bvid = pv.get("bvid")
                                        ep_pv_avid = pv.get("aid")
                                        ep_pv_url = pv.get("share_url")
                                        data = {
                                          "title": ep_pv_title,
                                          "image": ep_pv_cover,
                                          "bvid": ep_pv_bvid,
                                          "avid": av + str(ep_pv_avid),
                                          "url": ep_pv_url,
                                        }
                                        return data
      else:
            for pvs in response_result.get("result").get("section"):
                for pv in pvs.get("episodes"):
                  if pv.get("id") == int(epid):
                        ep_pv_title = pv.get("share_copy")
                        ep_pv_cover = pv.get("cover")
                        ep_pv_bvid = pv.get("bvid")
                        ep_pv_avid = pv.get("aid")
                        ep_pv_url = pv.get("share_url")
                        data = {
                            "title": ep_pv_title,
                            "image": ep_pv_cover,
                            "bvid": ep_pv_bvid,
                            "avid": av + str(ep_pv_avid),
                            "url": ep_pv_url,
                        }
                        return data


def handleSsResult(response_result, ssid):
    av = "av"
    if response_result is not None:
      if len(response_result.get("result").get("episodes")) != 0:
            if len(response_result.get("result").get("seasons")) != 0:
                for sss in response_result.get("result").get("seasons"):
                  if sss.get("season_id") == int(ssid):
                        for eps in response_result.get("result").get("episodes"):
                            if sss.get("new_ep").get("id") == eps.get("id"):
                              ep_title = eps.get("share_copy")
                              ep_cover = eps.get("cover")
                              ep_bvid = eps.get("bvid")
                              ep_avid = eps.get("aid")
                              ep_url = eps.get("share_url")
                              data = {
                                    "title": ep_title,
                                    "image": ep_cover,
                                    "bvid": ep_bvid,
                                    "avid": av + str(ep_avid),
                                    "url": ep_url,
                              }
                              return data
      else:
            return 404


def handleMdResult(response_result):
    av = "av"
    ep_ls = []
    ep_pv_ls = []
    if response_result is not None:
      ssid = response_result.get("result").get("media").get("season_id")
      title = response_result.get("result").get("media").get("title")
      md_cover = response_result.get("result").get("media").get("cover")
      md_url = response_result.get("result").get("media").get("share_url")
      if requestsAllVideoApi(str(ssid)) is not None:
            eps_data = requestsAllVideoApi(str(ssid))
            if eps_data.get("result").get("main_section") is not None:
                episodes_data = eps_data.get("result").get("main_section").get("episodes")
                episodes_pv_data = eps_data.get("result").get("section")
                if len(episodes_pv_data) != 0:
                  for eps_pv_data in episodes_pv_data:
                        for ep_pv_data in eps_pv_data.get("episodes"):
                            ep_pv_title = ep_pv_data.get("long_title")
                            if ep_pv_title == "":
                              ep_pv_title = ep_pv_data.get("title")
                            ep_pv_cover = ep_pv_data.get("cover")
                            ep_pv_url = ep_pv_data.get("share_url")
                            ep_pv_avid = ep_pv_data.get("aid")
                            ep_pv_bvid = biliBV.encode(ep_pv_avid)
                            ep_pv_dt = {
                              "title": ep_pv_title,
                              "image": ep_pv_cover,
                              "url": ep_pv_url,
                              "bvid": ep_pv_bvid,
                              "avid": av + str(ep_pv_avid),
                            }
                            ep_pv_ls.append(ep_pv_dt)
                        for ep_data in episodes_data:
                            ep_title = ep_data.get("long_title")
                            ep_cover = ep_data.get("cover")
                            ep_url = ep_data.get("share_url")
                            ep_avid = ep_data.get("aid")
                            ep_bvid = biliBV.encode(ep_avid)
                            ep_volume = ep_data.get("title")
                            ep_dt = {
                              "title": ep_title,
                              "image": ep_cover,
                              "url": ep_url,
                              "bvid": ep_bvid,
                              "avid": av + str(ep_avid),
                              "volume": ep_volume,
                            }

                            ep_ls.append(ep_dt)
                        data = {"title": title, "cover": md_cover, "url": md_url, "states": 1, "ep": ep_ls,
                              "pv": ep_pv_ls, }
                        return data
                else:
                  for ep_data in episodes_data:
                        ep_title = ep_data.get("long_title")
                        ep_cover = ep_data.get("cover")
                        ep_url = ep_data.get("share_url")
                        ep_avid = ep_data.get("aid")
                        ep_bvid = biliBV.encode(ep_avid)
                        ep_volume = ep_data.get("title")
                        ep_dt = {
                            "title": ep_title,
                            "image": ep_cover,
                            "url": ep_url,
                            "bvid": ep_bvid,
                            "avid": av + str(ep_avid),
                            "volume": ep_volume,
                        }
                        ep_ls.append(ep_dt)
                  data = {"title": title, "cover": md_cover, "url": md_url, "states": 1, "ep": ep_ls}
                  return data
            else:
                episodes_pv_data = eps_data.get("result").get("section")
                if len(episodes_pv_data) != 0:
                  for eps_pv_data in episodes_pv_data:
                        for ep_pv_data in eps_pv_data.get("episodes"):
                            ep_pv_title = ep_pv_data.get("long_title")
                            if ep_pv_title == "":
                              ep_pv_title = ep_pv_data.get("title")
                            ep_pv_cover = ep_pv_data.get("cover")
                            ep_pv_url = ep_pv_data.get("share_url")
                            ep_pv_avid = ep_pv_data.get("aid")
                            ep_pv_bvid = biliBV.encode(ep_pv_avid)
                            ep_pv_dt = {
                              "title": ep_pv_title,
                              "image": ep_pv_cover,
                              "url": ep_pv_url,
                              "bvid": ep_pv_bvid,
                              "avid": av + str(ep_pv_avid),
                            }
                            ep_pv_ls.append(ep_pv_dt)
                        data = {"title": title, "cover": md_cover, "url": md_url, "states": 0, "pv": ep_pv_ls}
                        return data


def main(content):
    """入口"""
    data = handleUrl(content)
    if data is not None:
      if regexBv(data) is not None:
            bvid = regexBv(data)
            if requestsBvVideoApi(bvid) is not None:
                result = requestsBvVideoApi(bvid)
                print(f"获取成功.bv号: {bvid}")
                return handleVideoBvResult(result)
      elif regexAv(data) is not None:
            bvid = regexAv(data)
            if requestsBvVideoApi(bvid) is not None:
                result = requestsBvVideoApi(bvid)
                av = biliBV.decode(bvid)
                print(f"获取成功.av号: {av}")
                return handleVideoBvResult(result)
      elif regexEp(data) is not None:
            epid = regexEp(data)
            if requestsEpVideoApi(epid) is not None:
                result = requestsEpVideoApi(epid)
                print(f"获取成功.ep号: {epid}")
                return handleEpisodeResult(result, epid)
      elif regexSs(data) is not None:
            ssid = regexSs(data)
            result = requestsSsVideoApi(ssid)
            print(f"获取成功.ss号: {ssid}")
            return handleSsResult(result, ssid)
      elif regexMd(data) is not None:
            mdid = regexMd(data)
            result = requestsMdVideoApi(mdid)
            print(f"获取成功.md号: {mdid}")
            return handleMdResult(result)

    else:
      if regexBv(content) is not None:
            bvid = regexBv(content)
            if requestsBvVideoApi(bvid) is not None:
                result = requestsBvVideoApi(bvid)
                print(f"获取成功.bv号: {bvid}")
                return handleVideoBvResult(result)
      elif regexAv(content) is not None:
            bvid = regexAv(content)
            if requestsBvVideoApi(bvid) is not None:
                result = requestsBvVideoApi(bvid)
                av = biliBV.decode(bvid)
                print(f"获取成功.av号: {av}")
                return handleVideoBvResult(result)
      elif regexEp(content) is not None:
            epid = regexEp(content)
            if requestsEpVideoApi(epid) is not None:
                result = requestsEpVideoApi(epid)
                print(f"获取成功.ep号: {epid}")
                return handleEpisodeResult(result, epid)
      elif regexSs(content) is not None:
            ssid = regexSs(content)
            if requestsSsVideoApi(ssid) is not None:
                result = requestsSsVideoApi(ssid)
                print(f"获取成功.ss号: {ssid}")
                return handleSsResult(result, ssid)
      elif regexMd(content) is not None:
            mdid = regexMd(content)
            if requestsMdVideoApi(mdid) is not None:
                result = requestsMdVideoApi(mdid)
                print(f"获取成功.md号: {mdid}")
                return handleMdResult(result)


if __name__ == '__main__':
    bv1 = "https://www.bilibili.com/video/BV1wu411B7rA?spm_id_from=333.851.b_7265636f6d6d656e64.1"# bv 多p
    result = main(bv1)
    # 视频多P
    if isinstance(result, list):
      for vd in result:
            print(f"标题: {vd['title']} 封面: {vd['image']} av号: {vd['avid']} bv号: {vd['bvid']} 视频地址: {vd['url']}")
    elif isinstance(result, dict):
      # states = 1 上线 states = 0 没上线
      if result.get("states") == 1:
            # 番剧上线了 有ep 有pv
            if result.get("ep") is not None and result.get("pv") is not None:
                print(f"番剧名: {result['title']} 海报: {result['cover']} 番剧地址: {result['url']}")
                for ep in result.get("ep"):
                  print(
                        f"剧集: 第{ep['volume']}话 标题: {ep['title']} 封面: {ep['image']} av号: {ep['avid']} bv号: {ep['bvid']} 剧集地址: {ep['url']}")
                for pv in result.get("pv"):
                  print(f"标题: {pv['title']} 封面: {pv['image']} av号: {pv['avid']} bv号: {pv['bvid']} 剧集地址: {pv['url']}")
            # 番剧上线了 有ep 没有pv
            else:
                print(f"番剧名: {result['title']} 海报: {result['cover']} 番剧地址: {result['url']}")
                for ep in result.get("ep"):
                  print(
                        f"剧集: 第{ep['volume']}话 标题: {ep['title']} 封面: {ep['image']} av号: {ep['avid']} bv号: {ep['bvid']} 剧集地址: {ep['url']}")
      # 番剧没上线 只有pv
      elif result.get("states") == 0:
            print(f"番剧名: {result['title']} 海报: {result['cover']} 番剧地址: {result['url']}")
            for pv in result.get("pv"):
                print(f"标题: {pv['title']} 封面: {pv['image']} av号: {pv['avid']} bv号: {pv['bvid']} 剧集地址: {pv['url']}")
      else:
            # 视频单P
            print(
                f"标题: {result['title']} 封面: {result['image']} av号: {result['avid']} bv号: {result['bvid']} 视频地址: {result['url']}")
    else:
      print("请检查是否输错了呀, 注意:没上线的番 用ss链接无法获取哦")


https://github.com/Smalltred/BilibiliCover

附件:


ACTEN20645 发表于 2022-3-27 18:44

大佬NB,我收下了{:1_893:}

雾都孤尔 发表于 2022-3-27 19:04

学习下,感谢分享。

i2080 发表于 2022-3-27 19:27

感谢分享,收藏啦

iooioox 发表于 2022-3-27 19:34


感谢分享

haihua301 发表于 2022-3-27 20:15

学习一下,感谢分享

xiadongming 发表于 2022-3-27 20:25

1024A1024 发表于 2022-3-27 20:48

主要是抓包后分析链接麻烦啊,楼主好有耐心

imeh 发表于 2022-3-27 21:28

感谢分享

p1142619270 发表于 2022-3-28 08:38

楼主nb。之前一直用的一个是链接。你这个更方便。
页: [1] 2
查看完整版本: 一个获取B站视频封面的小工具