0101B站学习视频发留言找小伙伴-实用小工具系列

文章目录

    • 1 起因
    • 2 找方法
    • 3 bilibili_api
    • 4 实现
    • 5 知识点
    • 结语

1 起因

经常在B站看学习视频,但是一个人学习,偶尔在想,我学的怎么样?有没有用?有没有谁可以一起交流下?好在现在有互联网,可以极大的拉进彼此的“距离”。

那么怎么找到一些一起学习的小伙伴呢?想到“笨方法”就是在视频下面留言,留下联系方式。虽然有些大海捞针的感觉,但是总算有了方向。

2 找方法

因为之前学过爬虫的知识,想着这不是很简单吗?爬取下历史记录,获取视频下方留言框,模拟按钮发送留言,这不就完成了?

使用scrapy框架,创建工程-> 生成spider 省略,不熟悉的可以自行查阅相关文档或者看下之前的文章。

spiders/commonets.py代码如下

import scrapy


class CommentsSpider(scrapy.Spider):
    name = "comments"
    allowed_domains = ["bilibili.com"]
    start_urls = ["https://api.bilibili.com/x/web-interface/history/cursor"]
    headers = {
        'User-Agent': 'Baiduspider',
        'Cookie': "xxxx",
        'Referer': 'https://www.bilibili.com/account/history'
    }

    def parse(self, response):
        print(response.text)
        # histories = response.css('#history-list>li>.r-info>.r-txt>a::attr(href)').getall()
        # for history in histories:
        #     print(history)
        # pass

上来就遇到问题了,

{"code":-101,"message":"账号未登录","ttl":1}

直接添加cookie没有效果,上网找找有没有其他方法。

3 bilibili_api

网上搜索一番,找到一个不错的python库,地址在下面链接1。

这是一个用 Python 写的调用 Bilibili 各种 API 的库, 范围涵盖视频、音频、直播、动态、专栏、用户、番剧等[1]。

源码目录结构简介:

  • data

    • api:目录下为各种.json文件,存储要访问的url地址,示例

      {
          "info": {
            "url": "https://api.bilibili.com/x/space/wbi/acc/info",
            "method": "GET",
            "verify": false,
            "wbi": true,
            "params": {
              "mid": "int: uid"
            },
            "comment": "用户基本信息"
          },
       }
      
    • geetest:极验验证相关

  • excepitons:包内为封装的各种异常类

  • tools:各种工具

  • utils:封装各种工具方法或者类

  • *.py:封装各种对象和方法,比如user(用户),comment(评论),artile(文章)等等

4 实现

第一步:获取历史记录

既然要获取记录,那么肯定需要身份信息,这里封装为Credential对象,源代码如下3-1所示:

"""
bilibili_api.utils.Credential

凭据类,用于各种请求操作的验证。
"""

import json
from ..exceptions import (
    CredentialNoBiliJctException,
    CredentialNoSessdataException,
    CredentialNoBuvid3Exception,
    CredentialNoDedeUserIDException,
)
from .utils import get_api
import httpx
import uuid
from typing import Union

API = get_api("credential")


class Credential:
    """
    凭据类,用于各种请求操作的验证。
    """

    def __init__(
        self,
        sessdata: Union[str, None] = None,
        bili_jct: Union[str, None] = None,
        buvid3: Union[str, None] = None,
        dedeuserid: Union[str, None] = None,
    ):
        """
        各字段获取方式查看:https://nemo2011.github.io/bilibili-api/#/get-credential.md

        Args:
            sessdata   (str | None, optional): 浏览器 Cookies 中的 SESSDATA 字段值. Defaults to None.
            bili_jct   (str | None, optional): 浏览器 Cookies 中的 bili_jct 字段值. Defaults to None.
            buvid3     (str | None, optional): 浏览器 Cookies 中的 BUVID3 字段值. Defaults to None.
            dedeuserid (str | None, optional): 浏览器 Cookies 中的 DedeUserID 字段值. Defaults to None.
        """
        self.sessdata = sessdata
        self.bili_jct = bili_jct
        self.buvid3 = buvid3
        self.dedeuserid = dedeuserid

    def get_cookies(self):
        """
        获取请求 Cookies 字典

        Returns:
            dict: 请求 Cookies 字典
        """
        return {
            "SESSDATA": self.sessdata,
            "buvid3": self.buvid3 if self.buvid3 else str(uuid.uuid1()) + "infoc",
            "bili_jct": self.bili_jct,
            "DedeUserID": self.dedeuserid,
        }

    def has_dedeuserid(self):
        """
        是否提供 dedeuserid。

        Returns:
            bool。
        """
        return self.dedeuserid is not None

    def has_sessdata(self):
        """
        是否提供 sessdata。

        Returns:
            bool。
        """
        return self.sessdata is not None

    def has_bili_jct(self):
        """
        是否提供 bili_jct。

        Returns:
            bool。
        """
        return self.bili_jct is not None

    def has_buvid3(self):
        """
        是否提供 buvid3

        Returns:
            bool.
        """
        return self.buvid3 is not None

    def raise_for_no_sessdata(self):
        """
        没有提供 sessdata 则抛出异常。
        """
        if not self.has_sessdata():
            raise CredentialNoSessdataException()

    def raise_for_no_bili_jct(self):
        """
        没有提供 bili_jct 则抛出异常。
        """
        if not self.has_bili_jct():
            raise CredentialNoBiliJctException()

    def raise_for_no_buvid3(self):
        """
        没有提供 buvid3 时抛出异常。
        """
        if not self.has_buvid3():
            raise CredentialNoBuvid3Exception()

    def raise_for_no_dedeuserid(self):
        """
        没有提供 DedeUserID 时抛出异常。
        """
        if not self.has_dedeuserid():
            raise CredentialNoDedeUserIDException()

    async def check_valid(self):
        """
        检查 cookies 是否有效

        Returns:
            bool: cookies 是否有效
        """

        data = await get_nav(self)
        return data["isLogin"]

    def generate_buvid3(self):
        """
        生成 buvid3
        """
        self.buvid3 = str(uuid.uuid1()) + "infoc"


async def get_nav(credential: Union[Credential, None] = None, headers = None):
    """
    获取导航

    Returns:
        dict: 账号相关信息
    """

    api = API["valid"]
    try:
        cookies = None
        if credential is not None:
            cookies = credential.get_cookies()
        resp = httpx.request("GET", api["url"], cookies=cookies, headers=headers)
    except Exception as e:
        raise e
    return resp.json()["data"]
  • 主要是关于4个字段sessdata、bili_jct、buvid3、dedeuserid设置和获取。

  • 这几个信息,自动获取通过第三方库。手动获取需要我们登录B站后,在Application->Cookie中查找,如下图所示:

    0101B站学习视频发留言找小伙伴-实用小工具系列_第1张图片

第二步:在每个视频下面发一条评论

测试小代码如下所示:

import asyncio

import browser_cookie3
from bilibili_api import Credential, user, comment
from bilibili_api.comment import CommentResourceType


async def main() -> None:
    # 获取用户历史记录
    # 获取cookie
    cookies = browser_cookie3.chrome(domain_name='bilibili.com')
    # 创建凭据
    credential = Credential(sessdata=cookies['SESSDATA'], bili_jct=cookies['bili_jct'], buvid3=cookies['buvid3'], dedeuserid=cookies['DedeUserID'])
    # 创建用户
    # me = user.User(uid=17142789, credential=credential);
    info = await user.get_self_history(1, 100, credential)
    # print(len(info))
    # lists = await me.get_self_history()
    text = '欢迎小伙伴一起学习交流,有做笔记和代码练习,头像有联系方式和地址,一起加油啊[脱单doge][脱单doge][脱单doge]'
    for v in info:
        print(type(v['aid']))

        await comment.send_comment(text=text, oid=(v['aid']), type_=CommentResourceType.VIDEO, credential=credential)


if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())


示例效果,随便点开历史记录中一个视频,去下面评论留言查看,如下图所示:在这里插入图片描述

5 知识点

  • Credential:凭据(凭证类)
  • user.get_self_history():获取历史记录api
  • comment.send_commend():发送评论
  • CommentResourceType:评论资源类型枚举类
  • asyncio:异步IO

问题:

  1. 能正常发送评论了,但是有限制,报错提示验证码未通过。目前不确定它的校验机制,等以后慢慢探索下。

结语

欢迎小伙伴一起学习交流,需要啥工具或者有啥问题随时联系我。

❓QQ:806797785

⭐️源代码地址:https://gitee.com/gaogzhen/smart-utilities.git

[1]Nemo2011/bilibili-api[CP/OL]

你可能感兴趣的:(工具,python,实用小工具)