【2024年最新】BilibiliB站视频动态评论爬虫

news2024/12/29 3:14:50

废话不多说,直接先放git仓库:GitHub - linyuye/Bilibili_crawler: bilibili爬虫,基于selenium获取oid与cookie,request获取api内容

〇:概念简述

oid:视频/动态的uuid,b站对于发布内容的通用唯一识别码

cookie:内含个人登录信息,爬虫头必需

其余内容请看该文档含义:

bilibili-API-collect/docs/comment/list.md at master · SocialSisterYi/bilibili-API-collect · GitHub哔哩哔哩-API收集整理【不断更新中…】. Contribute to SocialSisterYi/bilibili-API-collect development by creating an account on GitHub.[这里是图片001]https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/list.md

一:前言

首先,让我们了解,动态网站/静态网站的区别:

动态网站除了要设计网页外,还要通过数据库和编程序来使网站具有更多自动的和高级的功能。动态网站体现在网页一般是以asp,jsp,php,aspx等技术,而静态网页一般是HTML(标准通用标记语言的子集)结尾,动态网站服务器空间配置要比静态的网页要求高,费用也相应的高,不过动态网页利于网站内容的更新,适合企业建站。动态是相对于静态网站而言。——百度百科

通俗来说,就是网页内容是否写在网站源代码里面的区别。

以编写日期时,bilibili每周必看视频榜一为例:https://www.bilibili.com/video/BV1ay411h74i/

对于第一条评论:在网页源代码中不存在,所以数据是从后端/数据库返回的,那么我们就可以通过查看网络请求。发现数据在mainoid这里面返回得到,至此,我们知道了评论是从哪里返回的。

二:API详解

api分析来源:GitHub - SocialSisterYi/bilibili-API-collect: 哔哩哔哩-API收集整理【不断更新中…】哔哩哔哩-API收集整理【不断更新中…】. Contribute to SocialSisterYi/bilibili-API-collect development by creating an account on GitHub.[这里是图片006]https://github.com/SocialSisterYi/bilibili-API-collect

https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/list.md

通过翻阅上述API文档,我们得知,使用正常API获取评论,在页数到达400页之后无法返回内容,好在b站提供了一个懒加载api能够爬取所有内容。

https://api.bilibili.com/x/v2/reply/main懒加载api,无需wbi签名

https://api.bilibili.com/x/v2/reply/reply获取子评论的api

对评论区请求需要以下data数据:(1为评论,2为子评论)

参数名

类型

内容

必要性

备注

access_key

str

APP 登录 Token

APP 方式必要

type

num

评论区类型代码

必要

类型代码见表

oid

num

目标评论区 id

必要

mode

num

排序方式

非必要

默认为 3
0 3:仅按热度
1:按热度+按时间
2:仅按时间

next

num

评论页选择

非必要

按热度时:热度顺序页码(0 为第一页)
按时间时:时间倒序楼层号
默认为 0

ps

num

每页项数

非必要

默认为 20
定义域:1-30

access_key

str

APP登录 Token

APP 方式必要

type

num

评论区类型代码

必要

类型代码见表

oid

num

目标评论区 id

必要

root

num

根回复 rpid

必要

ps

num

每页项数

非必要

默认为20
定义域:1-49
但 data_replies 的最大内容数为20,因此设置为49其实也只会有20条回复被返回

pn

num

页码

非必要

默认为1

data_2 = {
 二级评论的data
'type': type,  # 类型
'oid': oid,  # 原视频/动态oid
'ps': ps,  # 每页含有条数,不能大于20
'pn': str(page_pn),  # 二级评论页数,需要转换为字符串
'root': rpid  # 一级评论的rpid
}

三:爬虫

使用了request库,对api访问,解析返回数据

for comment in json_data['data']['replies']:
    count = comment['rcount']
    rpid = str(comment['rpid'])
    name = comment['member']['uname']
    sex = comment['member']['sex']
    ctime = comment['ctime']
    dt_object = datetime.datetime.fromtimestamp(ctime, datetime.timezone.utc)
    formatted_time = dt_object.strftime('%Y-%m-%d %H:%M:%S') + ' 北京时间'  # 可以加上时区信息,但通常不需要
    like = comment['like']
    message = comment['content']['message'].replace('
', ',')
    # 检查是否存在 location 字段
    location = comment['reply_control'].get('location', '未知')  # 如果不存在,使用 '未知'
    location = location.replace('IP属地:', '')  if location else location
    current_level = comment['member']['level_info']['current_level']
    mid = str(comment['member']['mid'])

四:小白化处理

因为对于小白来说,获取cookie和oid比较困难,所以使用了selenium库,自动抓包自己的cookie和视频/动态oid

last_request = None

# 遍历所有请求
for request in driver.requests:
    if "main?oid=" in request.url and request.response:
        # 更新last_request为当前请求
        last_request = request

# 检查是否找到了符合条件的请求
if last_request:
    print("URL:", last_request.url)
    # 从URL中提取oid
    parsed_url = urlparse(last_request.url)
    query_params = parse_qs(parsed_url.query)
    oid = query_params.get("oid", [None])[0]
    type = query_params.get("type", [None])[0]
    print("OID:", oid)
    print("type:", type)

五:完整代码

from seleniumwire import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
from urllib.parse import urlparse, parse_qs
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
import csv
import pytz
import datetime
from fake_useragent import UserAgent
import random

options = {
    'ignore_http_methods': ['GET', 'POST'],  # 提取XHR请求,通常为GET或POST。如果你不希望忽略任何方法,可以忽略此选项或设置为空数组
    'custom_headers': {
        'X-Requested-With': 'XMLHttpRequest'  # 筛选XHR请求
    }
}

# 配置Selenium
chrome_options = Options()
chrome_service = Service("前面是你这个文件夹的绝对路径\venv\chrome-win64\chromedriver.exe")
driver = webdriver.Chrome(service=chrome_service, options=chrome_options)

# 打开目标网页,改成你想爬的网页,直接是网址就行
driver.get("https://www.bilibili.com/video/BV1WM4m1Q75H/")

login_div = driver.find_element(By.XPATH, "//div[contains(@class, 'right-entry__outside') and contains(@class, 'go-login-btn')]")
login_div.click()
time.sleep(5)
# 注意替换下面的选择器以匹配你要自动登录的网站
username_input = driver.find_element(By.XPATH, "//input[@placeholder='请输入账号']")
password_input = driver.find_element(By.XPATH, "//input[@placeholder='请输入密码']")
login_button = driver.find_element(By.XPATH, "//div[contains(@class,'btn_primary') and contains(text(),'登录')]")
#第一个写账号,第二个写密码
username_input.send_keys("")
password_input.send_keys("")
# 点击登录按钮
time.sleep(5)
# login_button.click()
# 等待几秒确保登录成功
driver.implicitly_wait(10)  # 替换为你需要的等待时间
# 等待页面加载完成(根据实际情况调整时间或使用更智能的等待方式)
time.sleep(5)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 获取捕获的网络请求
# 初始化一个变量,用来保存最后一个符合条件的请求
last_request = None

# 遍历所有请求
for request in driver.requests:
    if "main?oid=" in request.url and request.response:
        # 更新last_request为当前请求
        last_request = request

# 检查是否找到了符合条件的请求
if last_request:
    print("URL:", last_request.url)
    # 从URL中提取oid
    parsed_url = urlparse(last_request.url)
    query_params = parse_qs(parsed_url.query)
    oid = query_params.get("oid", [None])[0]
    type = query_params.get("type", [None])[0]
    print("OID:", oid)
    print("type:", type)



    # 从WebDriver中获取所有cookies
    all_cookies = driver.get_cookies()
    cookies_dict = {cookie['name']: cookie['value'] for cookie in all_cookies}
    cookies_str = '; '.join([f"{name}={value}" for name, value in cookies_dict.items()])


    # 从cookies中获取bili_jct的值
    bili_jct = cookies_dict.get('bili_jct', '')
    print("bili_jct:", bili_jct)
    sessdata = cookies_dict.get('SESSDATA', '')
    print("SESSDATA:", sessdata)
    # 打印请求头
    response = last_request.response



driver.quit()


# 重试次数限制
MAX_RETRIES = 5
# 重试间隔(秒)
RETRY_INTERVAL = 10

file_path_1 = 'comments/主评论_1.1.csv'
file_path_2 = 'comments/二级评论_1.2.csv'

beijing_tz = pytz.timezone('Asia/Shanghai')#时间戳转换为北京时间
ua=UserAgent()#创立随机请求头

ps= 20

down = 1 #开始爬的页数a
up = 30#结束爬的页数

one_comments = []
all_comments = []#构造数据放在一起的容器  总共评论,如果只希望含有一级评论,请注释 line 144
all_2_comments = []#构造数据放在一起的容器 二级评论
comments_current = []
comments_current_2 = []

        # 将所有评论数据写入CSV文件
with open(file_path_1, mode='a', newline='', encoding='utf-8-sig') as file:
    writer = csv.writer(file)
    writer.writerow(['昵称', '性别', '时间', '点赞', '评论', 'IP属地','二级评论条数','等级','uid','rpid'])
    writer.writerows(all_comments)
with open(file_path_2, mode='a', newline='', encoding='utf-8-sig') as file:#二级评论条数
    writer = csv.writer(file)
    writer.writerow(['昵称', '性别', '时间', '点赞', '评论', 'IP属地','二级评论条数,条数相同说明在同一个人下面','等级','uid','rpid'])
    writer.writerows(all_2_comments)

with requests.Session() as session:
    retries = Retry(total=3,  # 最大重试次数,好像没有这个函数
                    backoff_factor=0.1,  # 间隔时间会乘以这个数
                    status_forcelist=[500, 502, 503, 504])

    for page in range(down, up + 1):
        for retry in range(MAX_RETRIES):
            try:
                headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',#'ua.random',#随机请求头,b站爸爸别杀我,赛博佛祖保佑
                'Cookie': cookies_str,
                'SESSDATA': sessdata,
                'csrf' : bili_jct,
                }
                url =      'https://api.bilibili.com/x/v2/reply?'#正常api,只能爬8k
                url_long = 'https://api.bilibili.com/x/v2/reply/main'#懒加载api,理论无上限
                url_reply = 'https://api.bilibili.com/x/v2/reply/reply'#评论区回复api
                #示例:https://api.bilibili.com/x/v2/reply/main?next=1&type=1&oid=544588138&mode=3(可访问网站)
                data = {
                'next':str(page),  # 页数,需要转换为字符串,与pn同理,使用懒加载api
                'type': type,  # 类型 11个人动态 17转发动态 视频1)
                'oid': oid,  #id,视频为av,文字动态地址栏id,可自查
                'ps':ps, #(每页含有条数,不能大于20)用long的话不能大于30
                'mode': '3'  #3为热度       0 3:仅按热度      1:按热度+按时间 2:仅按时间 使用懒加载api
                }
                proxies = {
                     #"http": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": tunnel},
                     #"https": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": tunnel}
                      #代理ip来源:https://www.kuaidaili.com/free/inha/
                }
                prep = session.prepare_request(requests.Request('GET', url_long, params=data, headers=headers))
                print(prep.url)
                response = session.get(url_long, params=data, headers=headers)
                # 检查响应状态码是否为200,即成功
                if response.status_code == 200:
                    json_data = response.json()#获得json数据
                    if 'data' in json_data and 'replies' in json_data['data']: #以下为核心内容,爬取的数据
                                for comment in json_data['data']['replies']:
                                    #one_comments.clear()
                                    count = comment['rcount']
                                    rpid = str(comment['rpid'])
                                    name = comment['member']['uname']
                                    sex = comment['member']['sex']
                                    ctime = comment['ctime']
                                    dt_object = datetime.datetime.fromtimestamp(ctime, datetime.timezone.utc)
                                    formatted_time = dt_object.strftime('%Y-%m-%d %H:%M:%S') + ' 北京时间'  # 可以加上时区信息,但通常不需要
                                    like = comment['like']
                                    message = comment['content']['message'].replace('
', ',')
                                    # 检查是否存在 location 字段
                                    location = comment['reply_control'].get('location', '未知')  # 如果不存在,使用 '未知'
                                    location = location.replace('IP属地:', '') if location else location
                                    # 将提取的信息追加到列表中
                                    current_level = comment['member']['level_info']['current_level']
                                    mid = str(comment['member']['mid'])
                                    all_comments.append([name, sex, formatted_time, like, message, location,count,current_level,mid,rpid])
                                    comments_current.append([name, sex, formatted_time, like, message, location, count, current_level,mid,rpid])

                                    with open(file_path_1, mode='a', newline='', encoding='utf-8-sig') as file:
                                        writer = csv.writer(file)
                                        writer.writerows(all_comments)
                                    all_comments.clear()

                                    #每次结束,重置计数器
                                    if(count != 0):
                                        print(f"在第{page}页中含有二级评论,该条回复下面总共含有{count}个二级评论")
                                        total_pages = ((count // 20 ) +2) if count > 0 else 0
                                        for page_pn in range(total_pages):
                                            data_2 = {
                                                # 二级评论的data
                                                'type': type,  # 类型
                                                'oid': oid,  # id
                                                'ps': ps,  # 每页含有条数,不能大于20
                                                'pn': str(page_pn),  # 二级评论页数,需要转换为字符串
                                                'root': rpid  # 一级评论的rpid
                                            }
                                            if page_pn == 0:
                                                continue
                                            response = session.get(url_reply, params=data_2, headers=headers, proxies=proxies)
                                            prep = session.prepare_request(requests.Request('GET', url_reply, params=data_2, headers=headers))
                                            print(prep.url)

                                            if response.status_code == 200:
                                                json_data = response.json()  # 获得json数据
                                                if 'data' in json_data and 'replies' in json_data['data']:
                                                    if not json_data['data']['replies']:  # 检查replies是否为空,如果为空,跳过这一页
                                                        print(f"该页replies为空,没有评论")
                                                        continue
                                                    for comment in json_data['data']['replies']:
                                                        rpid = str(comment['rpid'])
                                                        name = comment['member']['uname']
                                                        sex = comment['member']['sex']
                                                        ctime = comment['ctime']
                                                        dt_object = datetime.datetime.fromtimestamp(ctime,datetime.timezone.utc)
                                                        formatted_time = dt_object.strftime('%Y-%m-%d %H:%M:%S') + ' 北京时间'  # 可以加上时区信息,但通常不需要
                                                        like = comment['like']
                                                        message = comment['content']['message'].replace('
', ',')
                                                        # 检查是否存在 location 字段
                                                        location = comment['reply_control'].get('location','未知')  # 如果不存在,使用 '未知'
                                                        location = location.replace('IP属地:', '') if location else location
                                                        current_level = comment['member']['level_info']['current_level']
                                                        mid = str(comment['member']['mid'])
                                                        all_2_comments.append([name, sex, formatted_time, like, message, location, count,current_level,mid,rpid])
                                                        comments_current_2.append([name, sex, formatted_time, like, message, location, count,current_level,mid,rpid])
                                                        with open(file_path_2, mode='a', newline='',encoding='utf-8-sig') as file:  # 二级评论条数
                                                            writer = csv.writer(file)
                                                            writer.writerows(all_2_comments)
                                                        all_2_comments.clear()
                                                else:
                                                    #print(f"在第{page_pn + 1}页的JSON响应中缺少 'data' 或 'replies' 键。跳过此页。")
                                                        print(f"在页面{page}下第{page_pn + 1}条评论没有子评论。")
                                            else:
                                                print(f"获取第{page_pn + 1}页失败。状态码: {response.status_code}")
                                        random_number = random.uniform(0.2, 0.3)
                                        time.sleep(random_number)
                                print(f"已经爬取第{page}页. 状态码: {response.status_code} ")
                    else:
                        print(f"在页面 {page} 的JSON响应中缺少 'data' 或 'replies' 键。跳过此页。")
                else:
                    print(f"获取页面 {page} 失败。状态码: {response.status_code} 即为失败,请分析原因并尝试重试")

                random_number = random.uniform(0.2, 0.3)
                print(random_number)
                time.sleep(random_number)
                break
            except requests.exceptions.RequestException as e:
                print(f"连接失败: {e}")
                if retry < MAX_RETRIES - 1:
                    print(f"正在重试(剩余尝试次数:{MAX_RETRIES - retry - 1})...")
                    time.sleep(RETRY_INTERVAL)  # 等待一段时间后重试
                else:
                    raise  # 如果达到最大重试次数,则抛出原始异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267219.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

汽车IVI中控开发入门及进阶(46):FFmpeg

概述: FFmpeg 是领先的多媒体框架,能够解码、编码、 转码、复用、解复用、流、过滤和播放 几乎所有人类和机器创建的东西。它支持最模糊的古老格式,直到最前沿。无论它们是由某个标准委员会、社区还是公司设计的。它还具有高度的可移植性:FFmpeg 在各种构建环境、机器架构…

计算属性 简写和 完整写法

计算属性渲染不加上括号 methods方法和computed属性区别&#xff1a; computed只计算一次&#xff0c;然后缓存&#xff0c;后续直接拿出来使用&#xff0c;而methods每次使用每次计算&#xff0c;不会缓存 计算属性完整写法&#xff1a; 既获取又设置 slice 截取 成绩案例 …

WebRTC Simulcast 大小流介绍与优化实践

Simulcast 是 WebRTC 中的一种标准化技术 &#xff0c;简称大小流。通过 Simulcast&#xff0c;客户端可以同时发送同一视频的多个版本。每个版本都以不同的分辨率和帧率独立编码&#xff0c;带宽较多的拉流端可以接收较高质量的视频流&#xff0c;带宽有限的拉流端则可以接收较…

kong网关使用pre-function插件,改写接口的返回数据

一、背景 kong作为api网关&#xff0c;除了反向代理后端服务外&#xff0c;还可对接口进行预处理。 比如本文提及的一个小功能&#xff0c;根据http header某个字段的值&#xff0c;等于多少的时候&#xff0c;返回一个固定的报文。 使用到的kong插件是pre-function。 除了上…

轮播图带详情插件、uniApp插件

超级好用的轮播图 介绍访问地址参数介绍使用方法&#xff08;简单使用&#xff0c;参数结构点击链接查看详情&#xff09;图片展示 介绍 带有底部物品介绍以及价格的轮播图组件&#xff0c;持续维护&#xff0c;uniApp插件&#xff0c;直接下载填充数据就可以在项目里面使用 …

Vite内网ip访问,两种配置方式和修改端口号教程

目录 问题 两种解决方式 结果 总结 preview.host preview.port 问题 使用vite运行项目的时候&#xff0c;控制台会只出现127.0.0.1&#xff08;localhost&#xff09;本地地址访问项目。不可以通过公司内网ip访问&#xff0c;其他团队成员无法访问&#xff0c;这是因为没…

老旧小区用电安全保护装置#限流式防火保护器参数介绍#

摘要 随着居民住宅区用电负荷的增加&#xff0c;用电安全问题日益突出&#xff0c;火灾隐患频繁发生。防火限流式保护器作为一种新型电气安全设备&#xff0c;能够有效预防因电气故障引发的火灾事故。本文介绍了防火限流式保护器的工作原理、技术特点及其在居民住宅区用电系统…

Ftrans数据摆渡系统 搭建安全便捷跨网文件传输通道

一、专业数据摆渡系统对企业的意义 专业的数据摆渡系统对企业具有重要意义&#xff0c;主要体现在以下几个方面‌&#xff1a; 1、‌数据安全性‌&#xff1a;数据摆渡系统通过加密传输、访问控制和审计日志等功能&#xff0c;确保数据在传输和存储过程中的安全性。 2、‌高…

LabVIEW生物医学信号虚拟实验平台

介绍了一款基于LabVIEW的多功能生物医学信号处理实验平台的设计和实现。平台通过实践活动加强学生对理论的理解和应用能力&#xff0c;特别是在心电图(ECG)和脑电图(EEG)的信号处理方面。实验平台包括信号的滤波、特征提取和频谱分析等功能&#xff0c;能直观体验和掌握生物医学…

大数据实验三

Python and anaconda 实验三数据预处理和轨迹聚类参考地址&#xff1a; https://www.hifleet.com/wp/communities/data/hangyundashujujishukechengshiyanzhinanshujuyuchulijiguijijuleichixugengxinzhong#post-2212https://www.hifleet.com/wp/communities/data/hangyundas…

【python因果库实战14】因果生存分析3

标准化生存分析 参见《因果推断》一书第17.5节&#xff08;“参数化的g公式”&#xff09;。 在参数化标准化中&#xff0c;也称为“参数化g公式”&#xff0c;时间步k处的生存率是对协变量X水平和处理分配a条件下的条件生存率的加权平均&#xff0c;权重为每个分层中个体的比…

云边端一体化架构

云边端一体化架构是一种将云计算、边缘计算和终端设备相结合的分布式计算模型。该架构旨在通过优化资源分配和数据处理流程&#xff0c;提供更高效、更低延迟的服务体验。 下面是对这个架构的简要说明&#xff1a; 01云计算&#xff08;Cloud Computing&#xff09; — 作为中心…

C/C++ 数据结构与算法【哈夫曼树】 哈夫曼树详细解析【日常学习,考研必备】带图+详细代码

哈夫曼树&#xff08;最优二叉树&#xff09; 1&#xff09;基础概念 **路径&#xff1a;**从树中一个结点到另一个结点之间的分支构成这两个结点间的路径。 **结点的路径长度&#xff1a;**两结点间路径上的分支数。 **树的路径长度&#xff1a;**从树根到每一个结点的路径…

2、C#基于.net framework的应用开发实战编程 - 设计(二、三) - 编程手把手系列文章...

二、设计&#xff1b; 二&#xff0e;三、构建数据库&#xff1b; 此例子使用的是SQLite数据库&#xff0c;所以数据库工具用的SQLiteStudio x64&#xff0c;这个是SQLite专用的数据库设计管理工具&#xff0c;其它的数据库管理工具比如DBeaver的使用请见实战工具系列文章。 1、…

Edge SCDN酷盾安全重塑高效安全内容分发新生态

在数字化浪潮不断推进的今天&#xff0c;互联网内容的分发效率与安全性已成为企业业务发展的关键要素。酷盾安全推出的Edge Secure Content Delivery Network&#xff08;Edge SCDN&#xff09;&#xff0c;不仅集成了分布式DDoS防护、CC防护、WAF防护及BOT行为智能分析等安全加…

JAVA HTTP压缩数据

/*** 压缩数据包** param code* param data* param resp* throws IOException*/protected void writeZipResult(int code, Object data, HttpServletResponse resp) throws IOException {resp.setHeader("Content-Encoding", "gzip");// write到客户端resp…

工厂+策略模式之最佳实践(疾病报卡维护模块API设计)

目录 &#x1f4bb;业务场景 &#x1f527;应用技术 ⚙概要流程 ❗开发注意 服务类上标注了 自定义注解 却无法直接利用getDeclaredAnnotation 获取 *Spring代理机制 代理机制的工作原理 代理的工作机制 代理的使用场景 已获取EmrXXXServiceImpl 的Class&#xff0c;如…

帧缓存的分配

帧缓存实际上就是一块内存。在 Android 系统中分配与回收帧缓存&#xff0c;使用的是一个叫 ION 的内核模块&#xff0c;App 使用 ioctl 系统调用后&#xff0c;会在内核内存中分配一块符合要求的内存&#xff0c;用户态会拿到一个 fd&#xff08;有的地方也称之为 handle&…

StarRocks元数据无法合并

一、先说结论 如果您的StarRocks版本在3.1.4及以下&#xff0c;并且使用了metadata_journal_skip_bad_journal_ids来跳过某个异常的journal&#xff0c;结果之后就出现了FE的元数据无法进行Checkpoint的现象&#xff0c;那么选择升级版本到3.1.4以上&#xff0c;就可以解决。 …

图像处理-Ch2-空间域的图像增强

Ch2 空间域的图像增强 文章目录 Ch2 空间域的图像增强Background灰度变换函数(Gray-level Transformation)对数变换(Logarithmic)幂律变换(Power-Law)分段线性变换函数(Piecewise-Linear)对比度拉伸(Contrast-Stretching)灰度级分层(Gray-level Slicing) 直方图处理(Histogram …