Python:抓取 Bilibili(B站)评论、弹幕、字幕等

        个人学习需求,需要获取一些 UGCuser generated content),包括 UP 的内容、弹幕、评论等。于是从 哔哩哔哩 (゜-゜)つロ 干杯~-bilibili 抓取了一些数据,以下内容仅供学习参考。

目录

1. Python 包:bilibili-api

1.1 bilibili-api

1.1.1 安装

1.1.2 示例

1.1.3 Credential

1.1.4 config.ini

2 自定义 Video 类

2.1 bvid

2.2 代码

2.2.1 get_video()

2.2.2 get_info()

2.2.3 get_comments()

2.2.4 get_sub_comments()

2.2.5 get_danmakus()

2.2.6 get_subtitle()

3 示例


1. Python 包:bilibili-api

        API 文档:bilibili-api 开发文档

        B站讲解视频,UP主:w海底捞不动w,【bilibili-api】爬取某个视频的所有评论 | python开发b站常用功能

1.1 bilibili-api

        引用开发文档中的简介。

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

        这里简单说明一些重要的内容,详细的内容可查看开发文档。

1.1.1 安装
pip3 install bilibili-api-python
1.1.2 示例

        粘贴开发文档中提供的代码。

import asyncio
from pprint import pprintfrom bilibili_api import videoasync def main() -> None:# 实例化 Video 类v = video.Video(bvid="BV1uv411q7Mv")# 获取信息info = await v.get_info()# 打印信息pprint(info)if __name__ == "__main__":asyncio.get_event_loop().run_until_complete(main())

        注:这里修改 print pprint,目的是更优雅的查看结果。结果如下,部分省略。

DeprecationWarning: There is no current event loopasyncio.get_event_loop().run_until_complete(main())
{'aid': 243922477,'argue_info': {'argue_link': '', 'argue_msg': '', 'argue_type': 0},'bvid': 'BV1uv411q7Mv','cid': 214334689,'copyright': 1,'ctime': 1595168654,'desc': '相关游戏:\n''----Minecraft、しゅがてん!-sugarfull tempering\n''====================\n''制作名单:\n''----Minecraft 游戏内建筑:-落忆-\n''----程序:-落忆-\n''----游戏内摄影:-落忆-、Passkou\n''----视频后期:Passkou\n''----音乐编曲:Passkou\n'
...and more

        注意,这里报 DeprecationWarning,可能是开发文档长期未维护的原因吧。正确(不报异常)的代码如下:

# coding=utf-8
# @Author: Fulai Cui (cuifulai@mail.hfut.edu.cn)
# @Time: 2024/9/15 15:22
from pprint import pprintfrom bilibili_api import video, syncdef main() -> None:# 实例化 Video 类v = video.Video(bvid="BV1uv411q7Mv")# 获取信息info = sync(v.get_info())# 打印信息pprint(info)if __name__ == "__main__":main()
1.1.3 Credential

        正如开发文档所讲,

如何给这个视频点赞?我们需要登录自己的账号。

这里设计是传入一个 Credential 类,获取所需的信息参照:获取 Credential 类所需信息

        bilibili-api 提供了一个 Credential 类,用于处理用户的“专属信息”。

        主要的内容就是开发文档的第二章:获取 Credential 类所需信息。具体内容:

  • SESSDATA

        用于一般在获取对应用户信息时提供,通常是 GET 操作下提供,此类操作一般不会进行操作,仅读取信息。如获取个人简介、获取个人空间信息等情况下需要提供。

  • BILI_JCT

        用于进行操作用户数据时提供,通常是 POST 操作下提供,此类操作会修改用户数据。如发送评论、点赞三连、上传视频等等情况下需要提供。

  • BUVID3 / BUVID4我只找到BUVID3

        设备验证码。通常不需要提供,但如放映室内部分接口需要提供,同时与风控有关。

  • DEDEUSERID

        通常为用户 UID几乎不需要提供。

  • AC_TIME_VALUE这个我没找到,没有对我来说没有影响

        在登录时获取,登录状态过期后用于刷新 Cookies,没有此值则只能重新登录,如不需要凭据刷新则不需要提供。

1.1.4 config.ini

        将上诉关键信息保存在 config.ini,以免意外泄露个人账号相关信息。以下为 config.ini 内容。

[Credential]
SESSDATA = XXX
BILI_JCT = XXX
BUVID3 = XXX
DEDEUSERID = XXX

        读取 config 可以使用 import configparser 包来完成。        

import configparserdef get_configs():parser = configparser.RawConfigParser()parser.read("../config.ini")configs = {'SESSDATA': parser.get('Credential', 'SESSDATA'),'BILI_JCT': parser.get('Credential', 'BILI_JCT'),'BUVID3': parser.get('Credential', 'BUVID3'),'DEDEUSERID': parser.get('Credential', 'DEDEUSERID')}return configs

        然后, bilibili_api.Credential 类的对象可以通过检索 configs 的值来定义。

configs = get_configs()credential = Credential(sessdata=configs['SESSDATA'],bili_jct=configs['BILI_JCT'],buvid3=configs['BUVID3'],dedeuserid=configs['DEDEUSERID']
)

         需要注意的是,这里的 credential 在后续频繁被使用。

2 自定义 Video 类

2.1 bvid

        BV 号(bvid),比如 URL https://www.bilibili.com/video/BV1Bx4y1s7n3 中,bvid 是连同 BV 在内的 BV1Bx4y1s7n3。获取某视频相关的内容都需要该 BV 号。

2.2 代码

       这里先直接 post 我自定义的 Video 类的 全部代码,后续再详细挑重点进行解释。

# coding=utf-8
# @Author: Fulai Cui (cuifulai@mail.hfut.edu.cn)
# @Time: 2024/7/12 15:14
import jsonfrom time import sleep
from random import randint
from tqdm import trange, tqdmfrom bilibili_api import comment
from bilibili_api import Credential
from bilibili_api import video
from bilibili_api import sync
from bilibili_api import Danmaku
from bilibili_api import assimport requestsHEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',"Referer": "https://www.bilibili.com",
}class Video:def __init__(self, credential: Credential, bv_id: str):self.credential = credentialself.bv_id = bv_idself.video: video.Video = self.get_video()self.aid = self.video.get_aid()self.info = self.get_info()def get_video(self):return video.Video(bvid=self.bv_id, credential=self.credential)def get_info(self):return sync(self.video.get_info())def get_comments(self, page_index: int = 1):num = 0comments: dict = sync(comment.get_comments(oid=self.aid,type_=comment.CommentResourceType.VIDEO,page_index=page_index,order=comment.OrderType.TIME,credential=self.credential,))all_comments = commentswhile True:sleep(randint(1, 3))page_index += 1num += comments['page']['size']if num >= comments['page']['count']:breakcomments: dict = sync(comment.get_comments(oid=self.aid,type_=comment.CommentResourceType.VIDEO,page_index=page_index,order=comment.OrderType.TIME,credential=self.credential,))all_comments['replies'].extend(comments['replies'])return all_commentsdef get_upper(self, page_index: int = 1):comments: dict = sync(comment.get_comments(oid=self.aid,type_=comment.CommentResourceType.VIDEO,page_index=page_index,order=comment.OrderType.TIME,credential=self.credential,))upper = comments['upper']if self.check_ad(upper):replies = self.get_sub_comments(upper)upper['replies'] = repliesreturn upperelse:return Nonedef get_sub_comments(self, upper):replies = []for pn in trange((upper['top']['rcount'] // 10) + 1, desc=f'Get sub comments of upper 【{self.bv_id}】'):url = ''.join(['https://api.bilibili.com/x/v2/reply/reply'f'?oid={self.aid}''&type=1'f'&root={upper['top']['rpid']}''&ps=10'f'&pn={pn + 1}''&web_location=333.788'])response = requests.get(url, headers=HEADERS).textresponse = json.loads(response)sleep(randint(1, 3))replies.extend(response['data']['replies'])return repliesdef get_danmakus(self):danmakus: list[Danmaku] = sync(self.video.get_danmakus(page_index=0,date=None,cid=None,from_seg=0,to_seg=self.info['duration'] // 360))def to_json(danmaku: Danmaku):txt = danmaku.text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")return {"dm_time": danmaku.dm_time,"send_time": danmaku.send_time,"crc32_id": danmaku.crc32_id,"color": danmaku.color,"weight": danmaku.weight,"id_": danmaku.id_,"id_str": danmaku.id_str,"action": danmaku.action,"mode": danmaku.mode,"font_size": danmaku.font_size,"is_sub": danmaku.is_sub,"pool": danmaku.pool,"attr": danmaku.attr,"content": txt}xmls = {'danmakus': []}for _ in tqdm(danmakus, desc=f'Get danmakus【{self.bv_id}】'):xmls['danmakus'].append(to_json(_))return xmlsdef get_subtitle(self, root_dir):sync(ass.make_ass_file_subtitle(obj=self.video,page_index=0,cid=self.info['cid'],out=f"{root_dir}/{self.bv_id}.ass",lan_name="中文(自动生成)",lan_code="ai-zh",credential=self.credential))@staticmethoddef check_ad(upper):if upper['top']:if 'https://b23.tv/mall' in str(upper['top']['content']['jump_url']):return Trueelse:return False
2.2.1 get_video()

        调用 bilibili_api.video.Video 类来获取 video 对象。

def get_video(self):return video.Video(bvid=self.bv_id, credential=self.credential)

bilibili_api.video.Video
def __init__(self,
             bvid: str | None = None,
             aid: int | None = None,
             credential: Credential | None = None) -> Any
 
Args:

bvid (str | None, optional) : BV 号. bvid 和 aid 必须提供其中之一。  

aid (int | None, optional) : AV 号. bvid 和 aid 必须提供其中之一。  

credential (Credential | None, optional): Credential 类. Defaults to None.

2.2.2 get_info()

        获取视频信息。

def get_info(self):return sync(self.video.get_info())

        需要注意到,bilibili_api.sync 多次使用,其目的是“同步执行异步函数”。

2.2.3 get_comments()

        获取评论信息。

def get_comments(self, page_index: int = 1):num = 0comments: dict = sync(comment.get_comments(oid=self.aid,type_=comment.CommentResourceType.VIDEO,page_index=page_index,order=comment.OrderType.TIME,credential=self.credential,))all_comments = comments
...more code

bilibili_api.comment
async def get_comments(oid: int,
                       type_: CommentResourceType,
                       page_index: int = 1,
                       order: OrderType = OrderType. TIME,
                       credential: Credential | None = None) -> Coroutine[Any, Any, dict]
 
获取资源评论列表。  

第二页以及往后需要提供 `credential` 参数。  

Args:

oid (int) : 资源 ID。  

type_ (CommentsResourceType) : 资源类枚举。  

page_index (int, optional) : 页码. Defaults to 1.  

order (OrderType, optional) : 排序方式枚举. Defaults to OrderType. TIME.  

credential (Credential, optional): 凭据。Defaults to None.  

Returns:

dict: 调用 API 返回的结果

         为了获取全部评论,自然需要递增 page_index,直到全部获取。也就自然而然的有了接着的代码。

def get_comments(self, page_index: int = 1):num = 0comments: dict = sync(comment.get_comments(oid=self.aid,type_=comment.CommentResourceType.VIDEO,page_index=page_index,order=comment.OrderType.TIME,credential=self.credential,))all_comments = commentswhile True:sleep(randint(1, 3))page_index += 1num += comments['page']['size']if num >= comments['page']['count']:breakcomments: dict = sync(comment.get_comments(oid=self.aid,type_=comment.CommentResourceType.VIDEO,page_index=page_index,order=comment.OrderType.TIME,credential=self.credential,))all_comments['replies'].extend(comments['replies'])return all_comments
2.2.4 get_sub_comments()

        我这里额外的关注置顶评论的子评论,但是发现 bilibili_api 并没有提供这样的 API 接口。由此定义了一个获取评论的子评论的方法。

        这里采用的是 requests.get() 的方法。

def get_sub_comments(self, upper):replies = []for pn in trange((upper['top']['rcount'] // 10) + 1, desc=f'Get sub comments of upper 【{self.bv_id}】'):url = ''.join(['https://api.bilibili.com/x/v2/reply/reply'f'?oid={self.aid}''&type=1'f'&root={upper['top']['rpid']}''&ps=10'f'&pn={pn + 1}''&web_location=333.788'])response = requests.get(url, headers=HEADERS).textresponse = json.loads(response)sleep(randint(1, 3))replies.extend(response['data']['replies'])return replies

         这样能获取的原因是 Bilibili 对该 api 的反爬比较“松”。

2.2.5 get_danmakus()

        获取弹幕信息。

def get_danmakus(self):danmakus: list[Danmaku] = sync(self.video.get_danmakus(page_index=0,date=None,cid=None,from_seg=0,to_seg=self.info['duration'] // 360))
...more code

bilibili_api.video.Video
async def get_danmakus(self,
                       page_index: int = 0,
                       date: date | None = None,
                       cid: int | None = None,
                       from_seg: int | None = None,
                       to_seg: int | None = None) -> Coroutine[Any, Any, list[Danmaku]]
 
获取弹幕。  

Args:

page_index (int, optional): 分 P 号,从 0 开始。Defaults to None  

date (datetime. Date | None, optional): 指定日期后为获取历史弹幕,精确到年月日。Defaults to None.  

cid (int | None, optional): 分 P 的 ID。Defaults to None  

from_seg (int, optional): 从第几段开始(0 开始编号,None 为从第一段开始,一段 6 分钟). Defaults to None.  

to_seg (int, optional): 到第几段结束(0 开始编号,None 为到最后一段,包含编号的段,一段 6 分钟). Defaults to None.  

注意

- 1. 段数可以使用 `get_danmaku_view()["dm_seg"]["total"]` 查询。

- 2. `from_seg` 和 `to_seg` 仅对 `date == None` 的时候有效果。

- 3. 例:取前 `12` 分钟的弹幕:`from_seg=0, to_seg=1`  

Returns:

List[Danmaku]: Danmaku 类的列表

2.2.6 get_subtitle()

        获取字幕信息。

def get_subtitle(self, root_dir):sync(ass.make_ass_file_subtitle(obj=self.video,page_index=0,cid=self.info['cid'],out=f"{root_dir}/{self.bv_id}.ass",lan_name="中文(自动生成)",lan_code="ai-zh",credential=self.credential))

bilibili_api.ass
async def make_ass_file_subtitle(obj: Video | Episode,
                                 page_index: int | None = 0,
                                 cid: int | None = None,
                                 out: str | None = "test. ass",
                                 lan_name: str | None = "中文(自动生成)",
                                 lan_code: str | None = "ai-zh",
                                 credential: Credential = Credential()) -> Coroutine[Any, Any, None]
 
生成视频字幕文件  

Args:

obj (Union[Video,Episode]): 对象  

page_index (int, optional) : 分 P 索引  

cid (int, optional) : cid  

out (str, optional) : 输出位置. Defaults to "test. ass".  

lan_name (str, optional) : 字幕名,如”中文(自动生成)“,是简介的 subtitle 项的'list'项中的弹幕的'lan_doc'属性。Defaults to "中文(自动生成)".  

lan_code (str, optional) : 字幕语言代码,如 ”中文(自动翻译)” 和 ”中文(自动生成)“ 为 "ai-zh"  

credential (Credential) : Credential 类. 必须在此处或传入的视频 obj 中传入凭据,两者均存在则优先此处

3 示例

        使用代码如下。

# coding=utf-8
# @Author: Fulai Cui (cuifulai@mail.hfut.edu.cn)
# @Time: 2024/7/12 15:19
import configparserfrom bilibili_api import Credential
from video import Videoimport jsondef get_configs():parser = configparser.RawConfigParser()parser.read("../config.ini")configs = {'SESSDATA': parser.get('Credential', 'SESSDATA'),'BILI_JCT': parser.get('Credential', 'BILI_JCT'),'BUVID3': parser.get('Credential', 'BUVID3'),'DEDEUSERID': parser.get('Credential', 'DEDEUSERID')}return configsdef json_write(json_filename: str, json_dict: dict):if json_dict:with open(json_filename, 'w', encoding='utf-8') as f:json.dump(json_dict, f, indent=4, ensure_ascii=False)def main():bv_id = 'BV1iC4y177Sb'root_dir = '../Data'configs = get_configs()credential = Credential(sessdata=configs['SESSDATA'],bili_jct=configs['BILI_JCT'],buvid3=configs['BUVID3'],dedeuserid=configs['DEDEUSERID'])video = Video(credential=credential, bv_id=bv_id)# comments = video.get_comments()upper = video.get_upper()if upper:danmakus = video.get_danmakus()json_write(f'{root_dir}/Info/{bv_id}.json', video.info)# json_write(f'{root_dir}/Comment/{bv_id}.json', comments)json_write(f'{root_dir}/Upper/{bv_id}.json', upper)json_write(f'{root_dir}/Danmaku/{bv_id}.json', danmakus)if __name__ == '__main__':main()

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

transformer模型进行英译汉,汉译英

上面是在测试集上的表现 下面是在训练集上的表现 上面是在训练集上的评估效果 这是在测试集上的评估效果,模型是transformer模型,模型应该没问题,以上的是一个源序列没加结束符和加了结束符的情况。 transformer源序列做遮挡填充的自注意力,这就让编码器的输出中每个token的语…

第312题|二重积分求旋转体体积(二)|武忠祥老师每日一题

解题思路&#xff1a;先画出图像&#xff0c;再利用旋转体体积计算公式进行解题。 1. 旋转体体积计算公式&#xff1a; 2.点到直线计算公式&#xff1a; 有了上面两条知识储备之后我们开始计算。 第一步&#xff1a;先计算出点到直线的距离&#xff1a; ymx&#xff0c;y-mx…

web开发 之 HTML、CSS、JavaScript、以及JavaScript的高级框架Vue(学习版2)

一、前言 接下来就是来解决这些问题 二、 Ajax 1.ajax javscript是网页三剑客之一&#xff0c;空用来控制网页的行为的 xml是一种标记语言&#xff0c;是用来存储数据的 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-…

JVM字节码与局部变量表

文章目录 局部变量表javap字节码指令分类 指令指令数据类型前缀加载和存储指令加载常量算术指令其他指令 字节码示例说明 局部变量表 每个线程的帧栈是独立的&#xff0c;每个线程中的方法调用会产生栈帧&#xff0c;栈帧中保存着方法执行的信息&#xff0c;例如局部变量表。 …

单硬盘安装Win10和麒麟V10双系统指导建议

随着信创电脑的普及,国产操作系统也逐渐走进了大家的视野,许多人选择了国产操作系统来体验其开源、安全、高效的特性,而Windows系统也是大多数人习惯使用的操作系统。一台电脑上同时安装银河麒麟V10和Windiows10双系统也成为了非常常见的需求。那么,如何在一台电脑上安装银…

外网(公网)访问VMware workstation 虚拟机内web网站的配置方法---端口转发总是不成功的原因

问题背景&#xff1a;客户提供的服务器操作系统配置web程序时&#xff0c;总是显示莫名其妙的问题&#xff0c;发现是高版本操作系统的.net库已经对低版本.net库进行了大范围修订&#xff0c;导致在安全检测上、软件代码规范上更加苛刻&#xff0c;最终导致部署不成功。于是想到…

TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错

目录 1&#xff0c;前言2&#xff0c;二者关系2.1&#xff0c;使用 3&#xff0c;遇到的问题3.1&#xff0c;TS 中使用 JS 1&#xff0c;前言 通过 Vite 创建的 Vue3 TS 项目&#xff0c;根目录下会有 tsconfig.json 和 tsconfig.node.json 文件&#xff0c;并且存在引用关系…

【网络】TCP/IP 五层网络模型:数据链路层

文章目录 认识以太网mac 地址mac 地址和 IP 地址的区别 类型ARP 协议 MTU 日常开发主要是应用层&#xff0c;传输层和应用层密切交互&#xff0c;传输层用到的也不少。网络层以及再往下&#xff0c;日常开发就涉及到的非常少了 认识以太网 插网线的上网方式 80211 是无线 WiF…

指纹与指甲检测系统源码分享

指纹与指甲检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

[网络]TCP/IP协议 之 网络层IP协议(3)

文章目录 一. IP协议报头二. NAT机制三. IP地址管理的基本规则1. 网段划分2. 特殊的IP地址 四. IP路由选择 网络层主要做的事情: 1.路径规划(路由器选择) 2.地址管理 一. IP协议报头 1)4位版本 指定IP协议的版本, 4 > ipv4 , 6 > ipv6 2)4位首部长度 4位bit能表示0-15, …

Linux bash脚本本地开发环境(Git Bash)配置

参考资料 VSCode: Windows 下配置 VSCode运行shellVSCodeを使用したシェルスクリプトの開発環境作成 目录 一. 必备VSCode插件二. 插件配置说明2.1 Bash IDE2.2 Code Runner2.3 shell-format 一. 必备VSCode插件 Bash IDE 该插件为 Bash 脚本提供了一些实用的开发工具和功能&…

如何设置xshell关闭最后一个选项卡标签时不退出软件?

不知道你是否遇到这个问题&#xff0c;就是在使用xshell的时候&#xff0c;每次关闭最后一个选项卡标签的时候&#xff0c;xshell软件默认就退出了&#xff0c;好多次我都只是想要关闭&#xff0c;而非退出&#xff0c;所以该如何设置&#xff0c;才能到我们的预期的效果呢&…

人工智能GPT____豆包使用的一些初步探索步骤 体验不一样的工作

豆包工具是我使用比较频繁的一款软件&#xff0c;其集合了很多功能。对话 图像 AI搜索 伴读等等使用都非常不错。电脑端安装集合了很多功能。 官网直达&#xff1a;豆包 使用我的文案创作能力&#xff0c;您可以注意以下几个技巧&#xff1a; 明确需求&#xff1a; 尽可能具…

云计算和虚拟化技术 背诵

https://zhuanlan.zhihu.com/p/612215164 https://zhuanlan.zhihu.com/p/612215164 云计算是指把计算资源、存储资源、网络资源、应用软件等集合起来&#xff0c;采用虚拟化技术 &#xff0c;将这些资源池化&#xff0c;组成资源共享池&#xff0c;共享池即是“云”。 云计算…

supermap iclient3d for cesium中entity使用

目标将西南石油大学部分区域围起来&#xff0c;然后引个标签显示名称&#xff0c;最后弄个飞机绕学校飞&#xff08;这个时间有点晚了&#xff0c;明天弄) 围墙: wall:{positions:Cesium.Cartesian3.fromDegreesArrayHeights([104.173,30.822,500,104.178,30.837,500,104.19,3…

Qt-QPushButton按钮类控件(22)

目录 描述 使用 给按钮添加图片 给按钮添加快捷键 添加槽函数 添加快捷键 添加组合键 开启鼠标的连发功能 描述 经过上面的一些介绍&#xff0c;我们也尝试的使用过了这个控件&#xff0c;接下来我们就要详细介绍这些比较重要的控件了 使用 给按钮添加图片 我们创建…

局域网windows下使用Git

windows下如何使用局域网进行git部署 准备工作第一步 &#xff0c;ip设置设置远程电脑的ip设置&#xff0c;如果不会设置请点击[这里](https://blog.csdn.net/Black_Friend/article/details/142170705?spm1001.2014.3001.5501)设置本地电脑的ip&#xff1a;验证 第二步&#x…

下载chromedriver驱动

首先进入关于ChromeDriver最新下载地址&#xff1a;Chrome for Testing availability 进入之后找到与自己所匹配的&#xff0c;在浏览器中查看版本号&#xff0c;下载版本号需要一致。 下载即可&#xff0c;解压&#xff0c;找到 直接放在pycharm下即可 因为在环境变量中早已配…

两个人群填充参考(CHN100K和NARD)

分别是中国人群和东北亚人群的填充参考&#xff0c;测试了下&#xff0c;中国人群的参考注册还是相对友好的&#xff0c;没有像有些网站一样严格限制。东北亚的没有测试&#xff0c;两个数据库的特点都是包含了少数民族&#xff0c;研究朝鲜或蒙古族或其他民族的同学&#xff0…

9.12 TFTP通信

客户端设计&#xff08;仅供参考&#xff09;&#xff1a; 下载本质&#xff1a;读取服务器发送的数据包&#xff0c;写入到本地文件 上传本质&#xff1a;读取本地文件内容&#xff0c;发送给服务器。 1、建立菜单选项&#xff0c;上传和下载。 2、上传功能函数&#xff1a; …