前言:

  在当今信息化社会,网络数据分析越来越受到重视。而作为开发人员,掌握一门能够抓取网页内容的语言显得尤为重要。在此篇文章中,将分享如何使用 .NET构建网络抓取工具。详细了解如何执行 HTTP 请求来下载要抓取的网页,然后从其 DOM 树中选择 HTML 元素,进行匹配需要的字段信息,从中提取数据。

一、准备工作:

创建项目:

​ 创建一个简单的Winfrom客户端程序,我使用的是.NET 5.0框架。为使项目显得条理清晰,此处进行了项目分层搭建项目,也就是多建立几个几个类库罢了,然后进行引用。

项目结构:

客户端界面设计:

NuGet添加引用类库HtmlAgilityPack:

HtmlAgilityPack是一个开源的C#库,它允许你解析HTML文档,从公DOM中选择元素并提取数据。该工具基本上提供了抓取静态内容网站所需要的一切。这是一个敏捷的HTML解析器,它构建了一个读和写DOM,并支持普通的XPATH或XSLT,你实际上不必了解XPATH也不必了解XSLT就可以使用它。它是一个.NET代码库,允许你解析“Web外”的HTML文件。解析器对“真实世界”中格式错误的HTML非常宽容。对象模型与System.Xml非常相似,但适用于HTML文档或流。

NuGet安装引用:

dotnet add package HtmlAgilityPack --version 1.11.51

二、实现核心代码:

设计定义实体:

网站爬取信息:

爬取信息实体定义:根据美图的首页展示的信息分析,进行定义爬取字段的信息,定义如下:

#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 创建者:码农阿亮
* 创建时间:2023/8/4 9:58:03
* 版本:V1.0.0
* 描述:
*
* ----------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.1
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >> using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace CrawlerModel.Meitu
{ /// <summary>
/// 爬取的专区字段实体
/// </summary>
public class BeautyZone
{ /// <summary>
/// 专区标题
/// </summary>
public string Tittle { get; set; }
/// <summary>
/// 专区每种类型美女排行榜
/// </summary>
public List<EveryCategoryBeautyTop> categoryBeauties { get; set; } } /// <summary>
/// 每分类美女排行榜
/// </summary>
public class EveryCategoryBeautyTop
{
/// <summary>
/// 类别
/// </summary>
public string Category { get; set; }
/// <summary>
/// 每种类型排行榜
/// </summary>
public List<Beauty> beauties { get; set; } } /// <summary>
/// 美女排行信息
/// </summary>
public class Beauty
{
/// <summary>
/// 排行
/// </summary>
public string No { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 热度
/// </summary>
public string Popularity { get; set; }
/// <summary>
/// 图片地址
/// </summary>
public string ImageUrl { get; set; }
}
}

更新UI界面实体定义:根据客户端需要展示的界面,定义如下:

#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 创建者:码农阿亮
* 创建时间:2023/8/04 16:42:12
* 版本:V1.0.0
* 描述:
*
* ----------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.1
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >> using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace CrawlerModel.Meitu
{
/// <summary>
/// UpdateUIModel 更新UI界面需要的字段
/// </summary>
public class UpdateUIModel
{
/// <summary>
/// 下载的数量
/// </summary>
public int DownloadNumber { get; set; }
/// <summary>
/// 分类
/// </summary>
public string Category { get; set; }
/// <summary>
/// 美女写真实体
/// </summary>
public Beauty beauty =new Beauty(); }
}

匹配DOM标签常量实体: 定义如下:

#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 创建者:码农阿亮
* 创建时间:2023/8/4 10:08:06
* 版本:V1.0.0
* 描述:
*
* ----------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.1
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >> using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace CrawlerModel.Meitu
{
/// <summary>
/// MeituConfig DOM标签常量
/// </summary>
public class MeituConfig
{
/// <summary>
/// 存放数据地址
/// </summary>
public const string JsonDataPath = "meitu/data";
/// <summary>
/// 爬取美图首页地址
/// </summary>
public const string Url = "https://www.meitu131.com";
/// <summary>
/// 专区XPath
/// </summary>
public const string ZoneXPath = @"/html/body/div[10]/div[2]/div";
/// <summary>
/// 专区名称XPath
/// </summary>
public const string ZoneNameXPath = @"/html/body/div[10]/div[1]/ul/li";
/// <summary>
/// 排行榜
/// </summary>
public const string TopXPath = @"/html/body/div[10]/div[2]/div[{0}]/dl";
/// <summary>
/// 人员隶属种类
/// </summary>
public const string PersonCategoryXPath = @"/html/body/div[10]/div[2]/div[{0}]/dl/dt";
/// <summary>
/// 人员
/// </summary>
public const string PersonXPath = @"/html/body/div[10]/div[2]/div[{0}]/dl/dd";
/// <summary>
/// 排行
/// </summary>
public const string NoXPath = @"/html/body/div[3]/div[1]/ul/li";
/// <summary>
/// 姓名
/// </summary>
public const string NameXPath = @"/html/body/div[3]/div[1]/ul/li";
/// <summary>
/// 热度
/// </summary>
public const string PopularityXPath = @"/html/body/div[3]/div[1]/ul/li";
/// <summary>
/// 图片地址
/// </summary>
public const string ImageUrlXPath = @"/html/body/div[3]/div[1]/ul/li"; }
}

业务实现代码:

帮助类:Web请求和下载资源帮助方法,定义义如下:

#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 创建者:码农阿亮
* 创建时间:2023/8/4 10:04:16
* 版本:V1.0.0
* 描述:
*
* ----------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.1
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using HtmlAgilityPack;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks; namespace CrawlerService.Helper
{ /// <summary>
/// 创建一个Web请求
/// </summary>
public class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
return request;
}
}
/// <summary>
/// 下载HTML帮助类
/// </summary>
public static class LoadHtmlHelper
{
/// <summary>
/// 从Url地址下载页面
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public async static ValueTask<HtmlDocument> LoadHtmlFromUrlAsync(string url)
{
var data = new MyWebClient()?.DownloadString(url);
var doc = new HtmlDocument();
doc.LoadHtml(data);
return doc;
} /// <summary>
/// 获取单个节点扩展方法
/// </summary>
/// <param name="htmlDocument">文档对象</param>
/// <param name="xPath">xPath路径</param>
/// <returns></returns>
public static HtmlNode GetSingleNode(this HtmlDocument htmlDocument, string xPath)
{
return htmlDocument?.DocumentNode?.SelectSingleNode(xPath);
} /// <summary>
/// 获取多个节点扩展方法
/// </summary>
/// <param name="htmlDocument">文档对象</param>
/// <param name="xPath">xPath路径</param>
/// <returns></returns>
public static HtmlNodeCollection GetNodes(this HtmlDocument htmlDocument, string xPath)
{
return htmlDocument?.DocumentNode?.SelectNodes(xPath);
} /// <summary>
/// 获取多个节点扩展方法
/// </summary>
/// <param name="htmlDocument">文档对象</param>
/// <param name="xPath">xPath路径</param>
/// <returns></returns>
public static HtmlNodeCollection GetNodes(this HtmlNode htmlNode, string xPath)
{
return htmlNode?.SelectNodes(xPath);
} /// <summary>
/// 获取单个节点扩展方法
/// </summary>
/// <param name="htmlDocument">文档对象</param>
/// <param name="xPath">xPath路径</param>
/// <returns></returns>
public static HtmlNode GetSingleNode(this HtmlNode htmlNode, string xPath)
{
return htmlNode?.SelectSingleNode(xPath);
} /// <summary>
/// 下载图片
/// </summary>
/// <param name="url">地址</param>
/// <param name="filpath">文件路径</param>
/// <returns></returns>
public async static ValueTask<bool> DownloadImg(string url ,string filpath)
{
HttpClient httpClient = new HttpClient();
try
{
var bytes = await httpClient.GetByteArrayAsync(url);
using (FileStream fs = File.Create(filpath))
{
fs.Write(bytes, 0, bytes.Length);
}
return File.Exists(filpath);
}
catch (Exception ex)
{ throw new Exception("下载图片异常", ex);
} }
}
}

主要业务实现方法:定义如下:

#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 创建者:码农阿亮
* 创建时间:2023/8/4 10:07:17
* 版本:V1.0.0
* 描述:
*
* ----------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.1
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >> using CrawlerComm.Handler;
using CrawlerModel.Meitu;
using CrawlerService.Helper;
using HtmlAgilityPack;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace CrawlerService.Meitu
{
/// <summary>
/// MeituParseHtml 的摘要说明
/// </summary>
public class MeituParseHtmService
{ /// <summary>
/// json数据文件夹存放文件夹位置
/// </summary>
private static string _dataDirectoryPath = Path.Combine(Directory.GetCurrentDirectory(), MeituConfig.JsonDataPath); /// <summary>
/// 爬取json数据文件
/// </summary>
private static string _CrawlerData = Path.Combine(_dataDirectoryPath, "categories.json"); /// <summary>
/// 开始爬取
/// </summary>
/// <returns></returns>
public async Task StartAsync()
{
//专区集合
List<BeautyZone> beautyZones = new List<BeautyZone>();
//获取首页Html文档
HtmlDocument htmlDocument = await LoadHtmlHelper.LoadHtmlFromUrlAsync(MeituConfig.Url); //创建存放数据的文件
FileInfo fileInfo = new FileInfo(_CrawlerData); //获取到专区标签
HtmlNodeCollection zoneHtmlNodes = htmlDocument.GetNodes(MeituConfig.ZoneXPath);
//专区名称
HtmlNodeCollection zoneNameHtmlNodes = htmlDocument.GetNodes(MeituConfig.ZoneNameXPath); if (zoneHtmlNodes != null && zoneHtmlNodes.Count> 0)
{
//专区个数
var zoneCount = zoneHtmlNodes.Count;
for (int i = 0; i < zoneCount; i++)
{
//每个专区
BeautyZone beautyZone = new BeautyZone()
{
Tittle = zoneNameHtmlNodes[i].InnerText,
categoryBeauties = new List<EveryCategoryBeautyTop>()
}; HtmlNodeCollection topHtmlNodes = htmlDocument.GetNodes(string.Format( MeituConfig.TopXPath,i+1));
if (topHtmlNodes != null && topHtmlNodes.Count > 0)
{
//每个专区下所有分类
HtmlNodeCollection personCategoryHtmlNodes = htmlDocument.GetNodes(string.Format(MeituConfig.PersonCategoryXPath, i + 1));
//爬取所有人员的标签内容
HtmlNodeCollection personHtmlNodes = htmlDocument.GetNodes(string.Format(MeituConfig.PersonXPath, i + 1)); if (personCategoryHtmlNodes !=null && personHtmlNodes!=null && personCategoryHtmlNodes.Count() > 0)
{ for (int j = 0; j < personCategoryHtmlNodes.Count(); j++)
{
//根据每个专区-分类下,进行遍历人气值人员排名
EveryCategoryBeautyTop everyCategoryBeautyTop = new EveryCategoryBeautyTop();
everyCategoryBeautyTop.Category = personCategoryHtmlNodes[j].InnerText;
everyCategoryBeautyTop.beauties = new List<Beauty>();
for (int k = 8*j; k < personHtmlNodes.Count(); k++)
{
var child = personHtmlNodes[k];//每个美女对应的节点信息 var i1 = child.GetSingleNode(child.XPath + "/i");//排名节点
var img = child.GetSingleNode(child.XPath + "/a[1]/div[1]/img[1]");//姓名和图片地址
var span2 = child.GetSingleNode(child.XPath + "/a[1]/div[2]/span[2]");//热度值
//同一类别添加美女到集合
everyCategoryBeautyTop.beauties.Add(new Beauty
{
No = i1.InnerText,
Name = img.GetAttributeValue("alt", "未找到"),
Popularity = span2.InnerText,
ImageUrl = img.GetAttributeValue("data-echo", "未找到")
}
);
}
//将在同一分区内Top分类添加到集合
beautyZone.categoryBeauties.Add(everyCategoryBeautyTop);
} } }
beautyZones.Add(beautyZone);
}
if (beautyZones.Count()> 0)
{
//爬取数据转Json
string beautiesJsonData = JsonConvert.SerializeObject(beautyZones); ;
//写入爬取数据数据
string jsonFile = "beauties.json";
WriteData(jsonFile, beautiesJsonData);
//下载图片
DownloadImage(beautyZones); }
}
} /// <summary>
/// 写入文件数据
/// </summary>
/// <param name="fileName"></param>
/// <param name="data"></param>
private void WriteData(string fileName, string data)
{ FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
try
{
sw.Write(data);
}
finally
{
if (sw != null)
{
sw.Close();
}
}
} /// <summary>
/// 下载图片
/// </summary>
/// <param name="beautyZones"></param>
private async void DownloadImage(List<BeautyZone> beautyZones)
{
int count = 0;
foreach (var beautyZone in beautyZones)
{
string rootPath = System.IO.Directory.GetCurrentDirectory() +"\\DownloadImg\\"+ beautyZone.Tittle;
foreach (var category in beautyZone.categoryBeauties)
{
string downloadPath = rootPath + "\\" + category.Category;
foreach (var beauty in category.beauties)
{
count += 1;//下载数量累加
string filePath = downloadPath + "\\" + beauty.Name+".jpg";
if (!Directory.Exists(downloadPath))
{
Directory.CreateDirectory(downloadPath);
}
UpdateUIModel updateUIModel = new UpdateUIModel()
{
DownloadNumber =count,
Category = category.Category,
beauty = beauty };
//更新UI
UpdateFrmHandler.OnUpdateUI(updateUIModel);
//异步下载
await LoadHtmlHelper.DownloadImg(beauty.ImageUrl,filePath);
}
}
}
}
}
}

定义委托代码:

更新UI界面的委托事件:定义如下:

#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 创建者:码农阿亮
* 创建时间:2023/8/04 11:28:24
* 版本:V1.0.0
* 描述:
*
* ----------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.1
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >> using CrawlerModel.Meitu;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace CrawlerComm.Handler
{
/// <summary>
/// UpdateFrmHandler 更新UI事件委托
/// </summary>
public class UpdateFrmHandler
{
/// <summary>
/// 更新下载界面事件
/// </summary>
public static event EventHandler<UpdateUIModel> UpdateUI;
public static void OnUpdateUI(UpdateUIModel updateUIModel)
{
UpdateUI?.Invoke(null, updateUIModel);
}
}
}

客户端执行代码:

点击触发事件:定义如下:

#region << 版 本 注 释 >>
/*----------------------------------------------------------------
* 创建者:码农阿亮
* 创建时间:2023/8/4 08:07:17
* 版本:V1.0.0
* 描述:
*
* ----------------------------------------------------------------
* 修改人:
* 时间:
* 修改说明:
*
* 版本:V1.0.1
*----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using CrawlerComm.Handler;
using CrawlerModel.Meitu;
using CrawlerService.Meitu;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace CrawlerData
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
//订阅委托
UpdateFrmHandler.UpdateUI += UpdateUIFuc;
} /// <summary>
/// 更新界面委托方法
/// </summary>
/// <param name="sender"></param>
/// <param name="updateUIModel"></param>
private void UpdateUIFuc(object sender, UpdateUIModel updateUIModel )
{
try
{ //改变界面UI中的值
this.Invoke((Action)delegate
{
UpdateUIBiz(updateUIModel);
}); }
catch (Exception ex)
{ }
}
/// <summary>
/// 更新UI界面业务
/// </summary>
/// <param name="updateUIModel"></param>
private void UpdateUIBiz(UpdateUIModel updateUIModel)
{
try
{
//分类
tbCategory.Text = updateUIModel.Category;
//排名
tbNo.Text = updateUIModel.beauty.No;
//姓名
tbName.Text = updateUIModel.beauty.Name;
//人气值
tbPopularity.Text = updateUIModel.beauty.Popularity;
//图片地址
tbUrl.Text = updateUIModel.beauty.ImageUrl;
//图片
WebClient client = new WebClient();
string imageUrl = updateUIModel.beauty.ImageUrl;// 要显示的网络图片的URL
byte[] imageBytes = client.DownloadData(imageUrl);
Image img = Image.FromStream(new MemoryStream(imageBytes));
picBox.Image = img;
//爬取数量
lbNumber.Text = updateUIModel.DownloadNumber.ToString(); }
catch (Exception ex)
{ }
}
/// <summary>
/// 开始执行按钮点击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btStart_Click(object sender, EventArgs e)
{
StartCrawler();
} /// <summary>
/// 开始爬取
/// </summary>
public async void StartCrawler()
{
try
{
MeituParseHtmService meituParseHtml = new MeituParseHtmService();
await meituParseHtml.StartAsync();
}
catch (Exception ex )
{ } }
}
}

三、爬取验证:

启动客户端:

文章上传图片大小有限制,只截取了部分gif:

爬取的Json数据结果:

下载的图片资源:

分目录层级存放:

源码链接地址:

Gitee完整实例地址:

https://gitee.com/mingliang_it/CrawlerDataClient

建群声明:本着技术在于分享,方便大家交流学习的初心,特此建立【编程内功修炼交流群】,热烈欢迎各位爱交流学习的程序员进群,也希望进群的大佬能不吝分享自己遇到的技术问题和学习心得

.NET爬取美图官网首页数据实战的更多相关文章

  1. 手把手教大家如何用scrapy爬虫框架爬取王者荣耀官网英雄资料

    之前被两个关系很好的朋友拉入了王者荣耀的大坑,奈何技术太差,就想着做一个英雄的随查手册,这样就可以边打边查了.菜归菜,至少得说明咱打王者的态度是没得说的,对吧?大神不喜勿喷!!!感谢!!废话不多说,开 ...

  2. python多线程爬取斗图啦数据

    python多线程爬取斗图啦网的表情数据 使用到的技术点 requests请求库 re 正则表达式 pyquery解析库,python实现的jquery threading 线程 queue 队列 ' ...

  3. 一款仿PBA官网首页jQuery焦点图的切换特效

    一款仿PBA官网首页jQuery焦点图的切换特效,非常的简单大方, 在对浏览器兼容性的方面做了不少的功夫.IE6也勉强能过去. 还是一款全屏的焦点图切换特效.大气而清新.很适合简介大方的网站. 下图还 ...

  4. 爬取斗图网图片,使用xpath格式来匹配内容,对请求伪装成浏览器, Referer 防跨域请求

    6.21自我总结 一.爬取斗图网 1.摘要 使用xpath匹配规则查找对应信息文件 将请求伪装成浏览器 Referer 防跨域请求 2.爬取代码 #导入模块 import requests #爬取网址 ...

  5. Axure实现vcg官网首页原型图

    W240第二天第三天 Axure的简单使用: 作业实现:vcg官网首页原型图 帮助文档基础篇:原型图基础之axure线框图设计 导航栏设计: 添加通用母版header 导航栏设计注意: 鼠标移动到下面 ...

  6. Python3爬取人人网(校内网)个人照片及朋友照片,并一键下载到本地~~~附源代码

    题记: 11月14日早晨8点,人人网发布公告,宣布人人公司将人人网社交平台业务相关资产以2000万美元的现金加4000万美元的股票对价出售予北京多牛传媒,自此,人人公司将专注于境内的二手车业务和在美国 ...

  7. Java爬虫系列之实战:爬取酷狗音乐网 TOP500 的歌曲(附源码)

    在前面分享的两篇随笔中分别介绍了HttpClient和Jsoup以及简单的代码案例: Java爬虫系列二:使用HttpClient抓取页面HTML Java爬虫系列三:使用Jsoup解析HTML 今天 ...

  8. Python协程爬取妹子图(内有福利,你懂得~)

    项目说明: 1.项目介绍   本项目使用Python提供的协程+scrapy中的选择器的使用(相当好用)实现爬取妹子图的(福利图)图片,这个学会了,某榴什么的.pow(2, 10)是吧! 2.用到的知 ...

  9. Python3爬虫系列:理论+实验+爬取妹子图实战

    Github: https://github.com/wangy8961/python3-concurrency-pics-02 ,欢迎star 爬虫系列: (1) 理论 Python3爬虫系列01 ...

  10. 针对石家庄铁道大学官网首页的UI分析

    身为一名光荣的铁大铮铮学子,我对铁大的网站首页非常的情有独钟,下面我就石家庄铁道大学的官网首页进行UI分析: 1.在首页最醒目的地方赫然写着石家庄铁道大学七个大字,让人一眼就豁然开朗. 2.网站有EN ...

随机推荐

  1. MySql的数据存储之B+树(浅谈)

    一.MySql的实际存储位置 B+树是MySql数据结构的主流存储方式,包括InnoDB和MYISAM引擎,它们的默认存储结构都是B+树 了解B+树前,我们先要知道MySql 的实际存储位置在哪? 有 ...

  2. Rust如何引入源码作为依赖

    问题描述 通常我们在rust项目中引入第三方依赖包时,会直接指定包的版本,这种方式指定后,Cargo在编译时会从crates.io这个源中下载这些依赖包. [package] name = " ...

  3. Vue 打包后报 Uncaught SyntaxError: Unexpected token ‘<‘

    根本原因在于你的vue.config.js里的publishPath设置的路径是相对路径还是绝对路径 大家都是看别人设置成 process.env.NODE_ENV==='production' ? ...

  4. LC19. 删除链表的倒数第 N 个结点

    删除链表的倒数第N个结点(中等) Q:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点. 示例: 示例一:输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3, ...

  5. Structured Streaming 的异常处理 【Concurrent update to the log. Multiple streaming jobs detected】

    目录 异常信息 一.异常表象原因 1.异常源码: 2.打个断点 二.解决方案 1.可以通过代码指定各分区的开始offset 2.不删除而是更改checkpoint offset下的批次文件 三.异常背 ...

  6. OpenAI 官宣首个 ChatGPT iOS 应用

    最近,OpenAI 宣布推出官方 iOS 应用,允许用户随时随地访问其高人气 AI 聊天机器人,此举也打破了近几个月内苹果 App Store 上充斥似是而非的山寨服务的窘境. 该应用程序是 Chat ...

  7. 探索JS中this的最终指向

    js 中的this 指向 一直是前端开发人员的一个痛点难点,项目中有很多bug往往是因为this指向不明确(this指向在函数定义时无法确定,只有在函数被调用时,才确定该this的指向为最终调用它的对 ...

  8. go语言中如何实现同步操作呢

    1. 简介 本文探讨了并发编程中的同步操作,讲述了为何需要同步以及两种常见的实现方式:sync.Cond和通道.通过比较它们的适用场景,读者可以更好地了解何时选择使用不同的同步方式.本文旨在帮助读者理 ...

  9. nas盒子内网穿透

    2023年5月27日星期六 -------------------------------------------------------------------------------------- ...

  10. 使用containerd从0搭建k8s(kubernetes)集群

    准备环境 准备两台服务器节点,如果需要安装虚拟机,可以参考<wmware和centos安装过程> 机器名 IP 角色 CPU 内存 centos01 192.168.109.130 mas ...