c++编写网络爬虫

news2024/11/26 23:17:05

c++爬虫项目

实现图形化界面UI

在这里插入图片描述

安装easyX(需要用的graphisc.h) 我之前的文章详细写到过如何安装。是这篇文章提到的:传送门

easyx官网

创建图形化界面

#define WINDOW_WIDTH 482
#define WINDOW_HEIGHT 300
void initUI() {
	initgraph(WINDOW_WIDTH, WINDOW_HEIGHT,EX_SHOWCONSOLE);
	setbkmode(TRANSPARENT);
}

移动窗口位置

int screenWidth;
int screenHeight;//屏幕分辨率数据
//获取屏幕分辨率
	screenWidth = GetSystemMetrics(SM_CXSCREEN);
	screenHeight = GetSystemMetrics(SM_CYSCREEN);
	hwnd = GetHWnd(); //获取当前窗口句柄
	//减去原有上方白色标题栏
	SetWindowLong( //设置窗口属性说
		hwnd,
		GWL_STYLE, //设定一个新的窗口风格。
		//GetWindowLong 获取指定串口的属性
		GetWindowLong(hwnd, GWL_STYLE) - WS_CAPTION);//WS_CAPTION 带标题栏的窗口风格

MoveWindow(hwnd, screenWidth * 0.7, 100, WINDOW_WIDTH, WINDOW_HEIGHT, false);

绘制UI界面

	MoveWindow(hwnd, screenWidth * 0.7, 100, WINDOW_WIDTH, WINDOW_HEIGHT, false);
	loadimage(&imgBg, "");
	putimage(0, 0, &imgBg);

编译 运行

在这里插入图片描述

更改代码

MoveWindow(hwnd, screenWidth*0.5, 100, WINDOW_WIDTH, WINDOW_HEIGHT, true);

完美绘制 true参数表示是否重新绘制
在这里插入图片描述

初始化按钮

制作按钮

我们需要从背景图上扣出两个按钮 一个是原本的标题栏(可以拖动程序的),另一个是程序的关闭按钮。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

制作的比较随意。。。

最后一个按钮是进入按钮 (方案放弃)

[ 在这里插入图片描述

再次DIY

在这里插入图片描述

对按钮进行初始化

先创建按钮的类

struct Button {
	IMAGE imgNormal;
	IMAGE imgPress;
	int width, highth;
	int x, y;
	int flag; // 按钮的int类型标记
	bool pressed;
};

写一个初始化按钮的函数

void initButton(Button* btn, const char* normalFile, const char* pressFile,
	int width, int highth, int flag) {
	if (!btn) return;
	loadimage(&btn->imgNormal, normalFile, width, highth, true);
	loadimage(&btn->imgPress, pressFile, width, highth, true);

	btn->width = width;
	btn->highth = highth;

	btn->pressed = false;
	btn->flag = flag;
}

定义三个按钮

//定义按钮
Button btnClose;
Button btnTitle;
Button btnEnter;

载入函数

	loadimage(&imgBg, "./UI.jpg");
	putimage(0, 0, &imgBg);
	//初始化关闭按钮
	initButton(&btnClose, "./normal.bmp", "./press.bmp", 37, 29, 0);
	btnClose.x = WINDOW_WIDTH - 37;
	btnClose.y = 0;
	//初始化标题按钮
	initButton(&btnTitle, "./title_normal.jpg", "./title_press.jpg", 445, 29, 0);
	btnTitle.x = 0;
	btnTitle.y = 0;
//初始化进入按钮

	//初始化进入按钮
	initButton(&btnEnter, "./enter_normal.bmp", "./enter_press.bmp", 165, 53, 0);
	btnEnter.x = 145;
	btnEnter.y = 172;

初始化完毕(累死我了 大部份时间都在绘图);

绘制按钮

写一个绘制按钮的函数

在写一个绘制透明图片的函数(easyx默认是不可以使用透明图片的 贝叶斯定理)

void drawButton(Button* btn) {
	if (!btn) return;
	if (btn->pressed) {
		drawPNG(btn->x, btn->y, &btn->imgPress);
	}
	else {
		drawPNG(btn->x, btn->y, &btn->imgNormal);
	}
}

void drawPNG(int  picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{

	// 变量初始化
	DWORD* dst = GetImageBuffer();    // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
	DWORD* draw = GetImageBuffer();
	DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
	int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
	int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
	int graphWidth = getwidth();       //获取绘图区的宽度,EASYX自带
	int graphHeight = getheight();     //获取绘图区的高度,EASYX自带
	int dstX = 0;    //在显存里像素的角标

	// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
	for (int iy = 0; iy < picture_height; iy++)
	{
		for (int ix = 0; ix < picture_width; ix++)
		{
			int srcX = ix + iy * picture_width; //在显存里像素的角标
			int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
			int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
			int sg = ((src[srcX] & 0xff00) >> 8);   //G
			int sb = src[srcX] & 0xff;              //B
			if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
			{
				dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标
				int dr = ((dst[dstX] & 0xff0000) >> 16);
				int dg = ((dst[dstX] & 0xff00) >> 8);
				int db = dst[dstX] & 0xff;
				draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)  //公式: Cp=αp*FP+(1-αp)*BP  ; αp=sa/255 , FP=sr , BP=dr
					| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)         //αp=sa/255 , FP=sg , BP=dg
					| (sb * sa / 255 + db * (255 - sa) / 255);              //αp=sa/255 , FP=sb , BP=db
			}
		}
	}
}

先对一些变量进行初始化

	bool titleDrag = false; //表示“标题栏”是否被单击拖动
	int titleLastX; //窗口的上一次位置(X 坐标位置)
	int titleLastY; //窗口的上一次位置(X 坐标位置)

然后写一个函数判断此时鼠标的位置是否在button上

bool checkButtonSelect(Button* btn, MOUSEMSG* msg) {
	float margin = 0.01;
	if (msg->x >= btn->x + btn->width * margin &&
		msg->x <= btn->x + btn->width * (1 - margin) &&
		msg->y >= btn->y + btn->highth * margin &&
		msg->y <= btn->y + btn->highth * (1 - margin)) {
		return true;
	}
	else {
		return false;
	}
}

实现鼠标的读写 UI界面的综合逻辑代码 Talking is cheap,show me the code;

while (1) {
		MOUSEMSG m = GetMouseMsg();
		FlushMouseMsgBuffer(); //不能少,后缀快速拖动顶部的标题按钮,将导致鼠标消息太多,
		//出现混乱!
		switch (m.uMsg) {
		case WM_MOUSEMOVE:
			if (checkButtonSelect(&btnTitle, &m)) {
				if (btnTitle.pressed == true) {
					if (titleDrag == false) { // 此时标题栏已经被点击按下,正准备拖动
						titleLastX = m.x; // 记录初始坐标
						titleLastY = m.y;
						titleDrag = true;
					}
					else { // 此时标题栏已经被点击按下,正在拖动
						// 计算拖动偏移量
						int offX = m.x - titleLastX;
						int offY = m.y - titleLastY;
						moveWindow(hwnd, offX, offY); // 根据拖动偏移量,移动窗口
					}
				}
			}
			else if (checkButtonSelect(&btnEnter, &m)) {
				btnEnter.pressed = true;
				drawButton(&btnEnter);
			}
			else if (checkButtonSelect(&btnClose, &m)) {
				btnClose.pressed = true;
				drawButton(&btnClose);
			}
			else {
				// 检查鼠标是否从按钮内移动到按钮之外
				if (btnClose.pressed == true) { // 鼠标从关闭按钮移出
					btnClose.pressed = false;
					drawButton(&btnClose);
				}
				if (btnEnter.pressed == true) { // 鼠标从发送按钮移出
					btnEnter.pressed = false;
					drawButton(&btnEnter);
				}
			}
			break;
		case WM_LBUTTONDOWN:
			if (checkButtonSelect(&btnTitle, &m)) {
				btnTitle.pressed = true; // 单击按下标题栏
			}
			else if (checkButtonSelect(&btnClose, &m)) {
				btnClose.pressed = true;
				drawButton(&btnClose);
			}
			else if (checkButtonSelect(&btnEnter, &m)) {
				btnEnter.pressed = true;
				drawButton(&btnEnter);
			}
			break;
		case WM_LBUTTONUP:
			if (checkButtonSelect(&btnClose, &m)) {
				closegraph();
				exit(0);
			}
			else if (checkButtonSelect(&btnEnter, &m)) {
			//to do
			}
			else if (checkButtonSelect(&btnTitle, &m))
			{
				// 松开标题栏按钮(左键抬起)
				btnTitle.pressed = false;
				titleDrag = false;
			}
			break;
		}
	}

绘制按钮

	drawButton(&btnEnter);
	drawButton(&btnClose);
	drawButton(&btnTitle);

这样差不多UI就设计完成

run一下
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

获取url地址(主角登场)

//URL
wchar_t url[1024];
.....
else if (checkButtonSelect(&btnEnter, &m)) {
			//to do
		
			//输入URL 正戏开始
			InputBox((LPTSTR)url, 1024, "请输入URL地址");//easyX提供的函数进行数据的读入
			 
		}

InputBox函数

bool InputBox(
	LPTSTR	pString,
	int		nMaxCount,
	LPCTSTR	pPrompt = NULL,
	LPCTSTR	pTitle = NULL,
	LPCTSTR	pDefault = NULL,
	int		width = 0,
	int		height = 0,
	bool	bHideCancelBtn = true
);

参数

pString

指定接收用户输入字符串的指针。

nMaxCount

指定 pString 指向的缓冲区的大小,该值会限制用户输入内容的长度。缓冲区的大小包括表示字符串结尾的 ‘\0’ 字符。当允许多行输入时,用户键入的回车占两个字符位置。

pPrompt

指定显示在对话框中的提示信息。提示信息中可以用“\n”分行。InputBox 的高度会随着提示信息内容的多少自动扩充。如果该值为 NULL,则不显示提示信息。

pTitle

指定 InputBox 的标题栏。如果为 NULL,将显示应用程序的名称。

pDefault

指定显示在用户输入区的默认值。

width

指定 InputBox 的宽度(不包括边框),最小为 200 像素。如果为 0,则使用默认宽度。

height

指定 InputBox 的高度(不包括边框)。如果为 0,表示自动计算高度,用户输入框只允许输入一行内容,按“回车”确认输入信息;如果大于 0,用户输入框的高度会自动拓展,同时允许输入多行内容,按“Ctrl+回车”确认输入信息。

bHideCancelBtn

指定是否隐藏取消按钮禁止用户取消输入。如果为 true(默认),InputBox 只有一个“确定”按钮,没有“X”关闭按钮,按 ESC 无效;如果为 false,InputBox 有“确定”和“取消”按钮,允许点“X”和按 ESC 关闭窗口。

更新代码

string url;
char *  URL;

InputBox(URL,1024,NULL,NULL,"请输入URL地址",NULL,NULL,false);

将URL 转为string格式 的url;

url = URL;

创建文件夹 保存爬取资源

创建reptile();函数

void reptile() {
	//输入URL 正戏开始
	InputBox((LPTSTR)url, 1024, "请输入URL地址");

}

优化代码

void reptile() {
	//输入URL 正戏开始
	InputBox((LPTSTR)url, 1024, "请输入URL地址");

}
-------------------------------
.....
else if (checkButtonSelect(&btnEnter, &m)) {
			//to do
		
		reptile();
			 
		}

创建文件夹

	CreateDirectory("./resource", NULL);

	CreateDirectory("./resource/images", NULL);

	CreateDirectory("./resource/videos", NULL);

抓取函数

 bool startCatch(string url)//抓取url
{
	 
	queue<string> q;//url队列
	q.push(url);

	while (!q.empty())
	{

		string currentUrl = q.front();//当前的URL
		q.pop();//删除

		//解析URL
		if (false == AnalysisURL(url))
		{
			continue;
		}
	}



	return true;
}


原理图
在这里插入图片描述

包含头文件queue

#include

 //解析URL
bool AnalysisURL(string url) {
	HWND hwndurl;
	//获取当前窗口句柄
	hwndurl = GetHWnd();

	//找http协议
	if (string::npos == url.find("http://")) {
	
	MessageBox(hwnd, "解析失败未找到协议",NULL,NULL);
	return false;//解析失败

	}

	if (url.length() <= 7)
	{
		MessageBox(hwnd, "url长度过小", NULL, NULL);
		return false;	
	}

	//截取域名
	int pos = url.find('/', 7);//从第七个开始截取
	if (pos == string::npos)
	{
		sHost = url.substr(7);
		sObject = "/";
	}
	else {
		sHost = url.substr(7, pos - 7);
		sObject = url.substr(pos);

	}

	if (sHost.empty() || sObject.empty())
	{
		MessageBox(hwndurl, "host or object is empty ", NULL, NULL);

		return false;
	}

	cout << "域名:" << sHost << endl << "资源:" << sObject << endl;


	return true;
}

 void reptile() {
	

	//创建文件夹保存爬取资源 video img   

	CreateDirectory("./resource", NULL);

	CreateDirectory("./resource/images", NULL);

	CreateDirectory("./resource/videos", NULL);

	loadimage(&imgAnalysis, "./catch.jpg");
	putimage(0, 0, &imgAnalysis);
	drawButton(&btnClose);
	 

	cin >> url;
	//开始抓
	startCatch(url);



}

	else if (checkButtonSelect(&btnEnter, &m)) {
					//to do
					MessageBox(hwndUI, "请在控制台输入URL地址", NULL, NULL);
					cout << "请输入URL" << endl;
					reptile();
				}

优化 使用多线程进行逻辑判断界面操作

好处 可以一直循环使用程序 不需要重开 UI界面一直在运行 不会死

	LPVOID param = 0; 

mainUI(param);//逻辑初始化界面

	DWORD  threadID = 0;
	
	HANDLE handleUI = CreateThread(NULL, NULL,mainUI, NULL, NULL, &threadID);

DWORD WINAPI mainUI(LPVOID param);

DWORD WINAPI mainUI(LPVOID param)
{
	 
		HWND hwndUI;
		hwndUI = GetHWnd();
		bool titleDrag = false; //表示“标题栏”是否被单击拖动
		while (1) {
			MOUSEMSG m = GetMouseMsg();
			FlushMouseMsgBuffer(); //不能少,后缀快速拖动顶部的标题按钮,将导致鼠标消息太多,
			//出现混乱!
			switch (m.uMsg) {
			case WM_MOUSEMOVE:
				if (checkButtonSelect(&btnTitle, &m)) {
					if (btnTitle.pressed == true) {
						if (titleDrag == false) { // 此时标题栏已经被点击按下,正准备拖动
							titleLastX = m.x; // 记录初始坐标
							titleLastY = m.y;
							titleDrag = true;
						}
						else { // 此时标题栏已经被点击按下,正在拖动
							// 计算拖动偏移量
							int offX = m.x - titleLastX;
							int offY = m.y - titleLastY;
							moveWindow(hwnd, offX, offY); // 根据拖动偏移量,移动窗口
						}
					}
				}
				else if (checkButtonSelect(&btnEnter, &m)) {
					
					btnEnter.pressed = true;
					drawButton(&btnEnter);
				}
				else if (checkButtonSelect(&btnClose, &m)) {
					btnClose.pressed = true;
					drawButton(&btnClose);
				}
				else {
					// 检查鼠标是否从按钮内移动到按钮之外
					if (btnClose.pressed == true) { // 鼠标从关闭按钮移出
						btnClose.pressed = false;
						drawButton(&btnClose);
					}
					if (btnEnter.pressed == true) { // 鼠标从发送按钮移出
						btnEnter.pressed = false;
						drawButton(&btnEnter);
					}
				}
				break;
			case WM_LBUTTONDOWN:
				if (checkButtonSelect(&btnTitle, &m)) {
					btnTitle.pressed = true; // 单击按下标题栏
				}
				else if (checkButtonSelect(&btnClose, &m)) {
					btnClose.pressed = true;
					drawButton(&btnClose);
				}
				else if (checkButtonSelect(&btnEnter, &m)) {
					btnEnter.pressed = true;
					drawButton(&btnEnter);
				}
				break;
			case WM_LBUTTONUP:
				if (checkButtonSelect(&btnClose, &m)) {
					closegraph();
					exit(0);
				}
				else if (checkButtonSelect(&btnEnter, &m)) {
					//to do
					MessageBox(hwndUI, "请在控制台输入URL地址", NULL, NULL);
					cout << "请输入URL" << endl;
					reptile();


				}
				else if (checkButtonSelect(&btnTitle, &m))
				{
					// 松开标题栏按钮(左键抬起)
					btnTitle.pressed = false;
					titleDrag = false;
				}
				break;
			}
		}

	 
	return NULL;
}

联网下载html

bool startCatch(string url)//抓取url
{
	 
	queue<string> q;//url队列
	q.push(url);

	while (!q.empty())
	{

		string currentUrl = q.front();//当前的URL
		q.pop();//删除

		//解析URL
		if (false == AnalysisURL(url))
		 
			continue;
		if (false == Connect())
			continue;

			
	}



	return true;
}

bool Connect() {

	//初始化网络
	WSADATA wsadata;
	if (WSAStartup(MAKEWORD(2, 2), &wsadata))  
		return false;
	 
	//创建套接字
	sock_client = socket(AF_INET, SOCK_STREAM, 0);

	if (sock_client == INVALID_SOCKET)
	 return false;
	 

	//解析域名为IP地址
	hostent *p =  gethostbyname(sHost.c_str());

	if (p == NULL)
		return false;
	//连接web服务器
	sockaddr_in sa;
	sa.sin_family = AF_INET;
	sa.sin_port = htons(80);
	//IP地址
	memcpy(&sa.sin_port, p->h_addr, 4);

	if (connect(sock_client, (sockaddr*)&sa, sizeof(sockaddr)))
		return false;


}

获取网页

string GetHtml(string url)//获取网页
{
	//解析URL
	if (false == AnalysisURL(url))

		return "";
	if (false == Connect())
		return "";

	//获取网页,发送Get请求 HTTP协议
	string info;
	info += "GET" + sObject + "HTTP/1.1\r\n";
	info += "Host: " + sHost + "\r\n";
	info += "Connection: Close\r\n\r\n";

	if (SOCKET_ERROR == send(sock_client, info.c_str(), info.length(), NULL))
		return false;
	
	//接受数据
	char ch = 0;
	string html;
	while (recv(sock_client, &ch, sizeof(char), 0)) {
		html += ch;
	}

	return html;

}

代码优化


​ #Include
​ //接受数据
​ char ch = 0;

fstream dataFile;   //创建一个文件,用于存放html的内容dataFile.open("D:\\html.txt", std::ios::out);
dataFile.open("./html.txt", ios::out);
if (!dataFile)
{
	printf("文件打开失败!\n");
 
}



string html;
while (recv(sock_client, &ch, sizeof(char), 0)) {
	html += ch;
	dataFile << ch;

}
dataFile.close();

运行出现错误connect连接失败;
在这里插入图片描述

更改代码(代码写错了)

	if (SOCKET_ERROR == connect(sock_client, (sockaddr*)&sa, sizeof(sockaddr)) )
		{
			cout << "服务器连接失败" << endl;

			return false;
		}
		else
		{
			cout<<"服务器连接成功"<<endl;
			return true;
		}
	 
	

遍历URL

cout << html << endl;

		//匹配所有URL 正则表达式
		smatch mat;
		string::const_iterator start = html.begin();
		string::const_iterator end = html.end();

		//正则表达式
		regex gex("http://[^\\s'\"<>()]+");
		vector<string> vecUrl;

		while (regex_search(start,end,mat,gex))
		{
			string newurl(mat[0].first, mat[0].second);
			

			 //把新的URL存起来
			vecUrl.push_back(newurl);

			start = mat[0].second;

		}
		
		//遍历所有URL
		for (int i = 0;i < vecUrl.size();i++)
		{
			string filename = "./resource/image/1.jpg";

			//判断是否为图片
			string imgUrl = vecUrl[i];
			if (imgUrl.find(".jpg") != string::npos)
			{
				//这是一个jpg图片
				Download(imgUrl, filename);
			}


		}

下载图片

bool Download(string url, string filename) {

	FILE* fp = fopen(filename.c_str(), "wb");
	char ch = 0;
	char buffer[20] = { 0 };
	int nRecv = 0;
	while (recv(sock_client,buffer,sizeof(buffer),0))
	{
		fwrite(buffer, 1, nRecv, fp);
	}


	fclose(fp);

}

至此,一个图形化界面的c++爬虫就做好了,后续还有代码优化(文件头处理,图片批量下载,代码重构)

源代码:

head.h

#pragma once
#ifndef HEAD_H    //目的是为了防止头文件重复包含
#define HEAD_H
#include <iostream>
#include <string>
#include <conio.h>
#include <queue>
#include <graphics.h>
#include <Windows.h>
#include <regex>
#pragma comment (lib,"WS2_32.lib")

#include <fstream>    //包含文件流的头文件

using namespace std;

#define WINDOW_WIDTH 482
#define WINDOW_HEIGHT 300


//定义按钮
struct Button {
	IMAGE imgNormal;
	IMAGE imgPress;
	int width, highth;
	int x, y;
	int flag; // 按钮的int类型标记
	bool pressed;
};


void initButton(Button* btn, const char* normalFile, const char* pressFile, int width, int highth, int flag);
void drawPNG(int  picture_x, int picture_y, IMAGE* picture);
bool checkButtonSelect(Button* btn, MOUSEMSG* msg);
void moveWindow(HWND hwnd, int offX, int offY);
void drawButton(Button* btn);
void initUI();
DWORD WINAPI mainUI(LPVOID param);

void reptile();//爬虫函数
bool startCatch(string url);
bool AnalysisURL(string url);
bool Connect();//连接网络
string GetHtml(string url);
bool Download(string url,string filename);

int screenWidth;
int screenHeight;
HWND hwnd;//UI窗口句柄
IMAGE imgBg;//背景图片
IMAGE imgAnalysis;
//定义按钮
Button btnClose;
Button btnTitle;
Button btnEnter;

int titleLastX; //窗口的上一次位置(X 坐标位置)
int titleLastY; //窗口的上一次位置(X 坐标位置
 


	
SOCKET sock_client;//客户端套接字

//URL
string url;
string sObject;
string sHost;//主机名


#endif

还有的资源(图片等)我会提供压缩包在我的主页可进行下载。麻烦关注~

参考文献

参考文献

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

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

相关文章

python 列表推导式、元组推导式 字典推导式 、三元运算符

一、基本语法结构 列表推导式的基本语法结构为&#xff1a; [ expression for item in iterable if condition ] 其中&#xff0c;expression表示参与列表生成的表达式&#xff0c;可包含变量、函数调用等操作&#xff1b;item表示生成列表中的元素&#xff1b;iterable表示…

Kubernetes中Pod的生命周期、重启策略

Kubernetes中Pod的生命周期、重启策略 1、Pod生命周期和重启策略 Pod 在整个生命周期中被系统定义为各种状态&#xff0c;熟悉 Pod 的各种状态对于理解如何设置 Pod 的调度策略、重启策 略是很有必要的&#xff0c;Pod 的状态如表所示。 Pod的重启策略(RestartPolicy)应用于…

Vue3项目Ant-Design-Vue汉化(a-date-picker等组件)

前言 Ant-Design-Vue 组件库某些组件默认是英文显示的&#xff0c;如时间选择等组件。这些组件的显示需要用户手动去进行汉化。 官方文档对此也给出了说明及示例&#xff0c;但截止到本篇博客发布日期&#xff0c;示例与实际项目配置存在小幅度出入。我也因此踩了一些坑&…

【Linux】文件描述符(下篇)

文章目录 &#x1f4d6; 前言1. 文件描述符fd的分配规则2. 重定向的本质3. 缓冲区的理解3.1 感受缓冲区的存在&#xff1a;3.2 正式认识缓冲区&#xff1a;综合例题&#xff1a; 4. 模拟实现C语言的文件操作5. 完善之前实现的shell5.1 程序替换&#xff0c;会影响曾经子进程打开…

机器学习技术(三)——机器学习实践案例总体流程

机器学习实践案例总体流程 文章目录 机器学习实践案例总体流程一、引言二、案例1、决策树对鸢尾花分类1.数据来源2.数据导入及描述3.数据划分与特征处理4.建模预测 2、各类回归波士顿房价预测1.案例数据2.导入所需的包和数据集3.载入数据集&#xff0c;查看数据属性&#xff0c…

【动态规划算法练习】day15

文章目录 一、01背包1.题目简介2.解题思路3.代码4.运行结果 二、416. 分割等和子集1.题目简介2.解题思路3.代码4.运行结果 三、494. 目标和1.题目简介2.解题思路3.代码4.运行结果 四、1049. 最后一块石头的重量 II1.题目简介2.解题思路3.代码4.运行结果 总结 一、01背包 1.题目…

【设计模式】第十三章:模板方法模式详解及应用案例

系列文章 【设计模式】七大设计原则 【设计模式】第一章&#xff1a;单例模式 【设计模式】第二章&#xff1a;工厂模式 【设计模式】第三章&#xff1a;建造者模式 【设计模式】第四章&#xff1a;原型模式 【设计模式】第五章&#xff1a;适配器模式 【设计模式】第六章&…

20.BeautifulSoup库的安装及导入

文章目录 1.BeautifulSoup库简介2.BeautifulSoup库的安装3.BeautifulSoup和beautifulsoup4的区别4.获取网页源代码知识回顾4.1 手动获取网页的源代码4.2 requests库获取网页的源代码 5. 利用bs4库输出网页源代码6.bs4库的导入语法 1.BeautifulSoup库简介 BeautifulSoup库是Pyt…

1.监控分布式--zabbix

文章目录 监控分布式-zabbix、prometheus概念工作原理功能组件部署zabbix安装Nginx和PHP环境部署数据库编码安装zabbix编译安装zabbix server客户端安装zabbix agent服务 监控分布式-zabbix、prometheus 利用一个优秀的监控软件&#xff0c;我们可以: 通过一个友好的界面进行…

NGINX+Tomcat负载均衡、动静分离集群

目录 前言 一、NGINX正向代理与反向代理 1.1、NGINX正向代理 1.2、NGINX反向代理 1. 2.1Nginx配置反向代理的主要参数 二、负载均衡 三、NGINX动静分离集群 3.1动静分离原理 四、NginxTomcat动静分离 4.1搭建nginx代理服务器192.168.14.100 4.1.1安装 NGINX依赖环境 …

创建UI组件库后上传NPM

上篇已经讲了如何创建自己的组件库&#xff0c;这篇讲怎么上传npm后&#xff0c;可以下载使用 1.首先看下组件的文件结构 在index.js中要写上每个组件可以按需引用的条件 import Button from "./src/button";Button.install function(Vue) {Vue.component(Button.…

Tkinter_使用Progressbar创建和管理进度条

前言 Progressbar是Tkinter库中的一个小部件&#xff0c;用于创建和管理进度条。它可以在图形用户界面中显示任务的进度&#xff0c;并提供了多种样式和配置选项。 使用Progressbar&#xff0c;你可以按照固定或不确定的进度展示任务的进行状态。它可以显示任务完成的百分比&am…

“this“ 隐式具有类型 “any“,因为它没有类型注释。

在 tsconfig.json文件中 将 "noImplicitThis" 改为false "noImplicitThis": false,

工业互联网如何促进传统制造业的高效生产?

工业互联网&#xff0c;也称为工业物联网&#xff08;IIoT&#xff09;&#xff0c;是指将联网设备和系统集成到传统制造流程中。它结合了传感器、数据分析、机器学习和自动化&#xff0c;以优化和提高制造各个方面的效率。工业互联网促进传统制造业高效生产的方式有&#xff1…

机器学习、监督学习、无监督学习基本概念

- 机器学习 机器学习是一门多领域交叉学科&#xff0c;涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为&#xff0c;以获取新的知识或技能&#xff0c;重新组织已有的知识结构使之不断改善自身的性能。机器学习有…

Nginx反向代理提示413 Request Entity Too Large

请求返回的内容如下 <html> <head><title>413 Request Entity Too Large</title></head> <body> <center><h1>413 Request Entity Too Large</h1></center> <hr><center>nginx/1.20.2</center>…

BPM工作流引擎优势

什么是BPM工作流引擎&#xff1f; BPM工作流引擎是对企业的业务进行的管理&#xff0c;是一个开放性的平台。它是BPM与工作流引擎的结合。不仅能够实现所有OA的功能&#xff0c;还能够实现以端到端为中心的协作&#xff0c;重视企业从战略到执行自上而下的流程化、规范化管理&a…

用OpenCV创建一张类型为CV_8UC1的单通道随机灰度图像

#include <iostream> #include <opencv2/imgcodecs.hpp> #include <opencv2/opencv.hpp> #include <opencv2/highgui.hpp>int

差分进化算法(Differential Evolution,DE,附简单案例及详细matlab源码)

作者&#xff1a;非妃是公主 专栏&#xff1a;《智能优化算法》 博客地址&#xff1a;https://blog.csdn.net/myf_666 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录 专栏推荐序一、概论二、差分进化算法&a…

7、Maxwell安装部署

1、Maxwell简介 1.1 Maxwell概述 Maxwell 是由美国Zendesk公司开源&#xff0c;用Java编写的MySQL变更数据抓取软件。它会实时监控Mysql数据库的数据变更操作&#xff08;包括insert、update、delete&#xff09;&#xff0c;并将变更数据以 JSON 格式发送给 Kafka、Kinesi等…