├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── cflw代码库py ├── cflw中国_身份证.py ├── cflw函数.py ├── cflw图像.py ├── cflw字符串.py ├── cflw工具.py ├── cflw工具_序列.py ├── cflw工具_运算.py ├── cflw按键脚本_win.py ├── cflw控制台.py ├── cflw操作系统.py ├── cflw操作系统_linux.py ├── cflw操作系统_win.py ├── cflw数学.py ├── cflw数学_向量.py ├── cflw数学_图形.py ├── cflw数学_平面几何.py ├── cflw数学_矩阵.py ├── cflw数学_随机.py ├── cflw时间.py ├── cflw爬虫.py ├── cflw爬虫_代理列表.py ├── cflw简单网管.py ├── cflw简单网管_标识.py ├── cflw简单网管_派.py ├── cflw类型.py ├── cflw网络地址.py ├── cflw网络连接.py ├── cflw网络连接_串口.py ├── cflw网络连接_安全外壳.py ├── cflw网络连接_视窗.py ├── cflw网页连接.py ├── cflw网页连接_微软.py ├── cflw网页连接_火狐.py ├── cflw网页连接_谷歌.py ├── cflw英语.py ├── cflw辅助.py └── cflw输入_win.py ├── 文档 ├── 使用说明.md └── 图片 │ ├── 使用说明1.png │ └── 使用说明2.png ├── 测试 ├── 文章_小说网站爬虫.py ├── 测试_代理列表.py ├── 测试_代理列表.txt ├── 测试_小说下载.py ├── 测试_矩阵.py └── 测试_解析参数.py └── 程序 ├── 图片提取水印.py └── 图片添加水印.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 cflw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 乘风龙王的代码库(python) 2 | 主要是一些随便写写的东西,其中有很多没写完的半成品,有的甚至从来没运行过。代码文件的编码为**utf-8无bom**。 3 | 4 | 项目依赖项:此代码库所引用的其他第三方库在代码文件开头导入语句后面用注释给出库名,可通过pip安装。 5 | * requests 6 | * beautifulsoup4 7 | * pyserial 8 | * pywin32 9 | * paramiko 10 | * pillow 11 | 12 | **网络设备脚本**相关代码已从此代码库拆分并转移到 https://github.com/cflw/network_device_script
13 | **小说下载器**已移到 https://github.com/cflw/novel_downloader 14 | 15 | ### 文章 16 | 按时间顺序排列 17 | * [用python编写小说网站爬虫](https://zhuanlan.zhihu.com/p/51309019) \[知乎\] 18 | * [用python给图片添加数字水印](https://zhuanlan.zhihu.com/p/111163052) \[知乎\] 19 | 20 | ## 内容包含 21 | ### 工具 22 | * **cflw字符串**:用来判断中文的函数和正则表达式,和一些计算处理字符串的函数。 23 | * **cflw时间**:一些时间类。 24 | * **cflw辅助**:一些装饰器,*没什么用*。 25 | * **cflw工具_运算**:一些小函数 26 | 27 | ### 数学 28 | * **cflw数学**:常用数学函数 29 | * **cflw数学_向量** 30 | * **cflw数学_平面几何** 31 | * **cflw数学_图形**:颜色 32 | * **cflw数学_矩阵** 33 | * **cflw数学_随机**:抄袭c++标准库的\ 34 | 35 | ### 网络 36 | * **cflw网络地址**:提供对IPv4和IPv6地址的解析与计算,提供对物理(Media Access Control)地址的解析与计算 37 | * **cflw网络连接**:提供统一的接口,通过Telnet、SSH、Console等方式连接到网络设备。 38 | * ~~cflw网络设备~~(已移到[网络设备脚本](https://github.com/cflw/network_device_script)):提供统一的接口对路由器、交换机等网络设备进行控制。 39 | * **cflw网页连接**:创建为**网络设备脚本**使用的网页连接 40 | * **cflw简单网管**:提供统一的简单网络管理协议(Simple Network Manage Protocol)接口 41 | 42 | ### 爬虫 43 | * **cflw爬虫**:提供爬虫相关实用工具 44 | * **cflw爬虫_代理列表**:获取可用的HTTP代理 45 | * ~~cflw小说下载~~(已移到[小说下载器](https://github.com/cflw/novel_downloader)):从一些盗版小说网站上下载小说(~ ̄▽ ̄)~ 。 46 | 47 | ### 图形&图像 48 | * **cflw图像**:处理图像 49 | 50 | ### 输入 51 | * **cflw输入_win**:只有一些枚举。完整内容见[乘风龙王的代码库(c++)](https://github.com/cflw/cflw_cpp)中的**cflw输入_win** 52 | * **cflw按键脚本_win**:模拟键盘鼠标输入 53 | 54 | ### 其他 55 | * **cflw英语**:包含常用单词的字符串数组 56 | 57 | ## 使用说明 58 | 见[使用说明](文档/使用说明.md) -------------------------------------------------------------------------------- /cflw代码库py/cflw中国_身份证.py: -------------------------------------------------------------------------------- 1 | import re 2 | from . import cflw时间 as 时间 3 | from . import cflw字符串 as 字符串 4 | #身份证正则和区域信息 https://raw.githubusercontent.com/jayknoxqu/id-number-util/master/constant.py 5 | c十五位身份证正则 = re.compile(r"[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}") 6 | c十八位身份证正则 = re.compile(r"[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]") 7 | #取身份证信息 8 | def fg区域(a号码: str): 9 | return int(a号码[:6]) 10 | def fg年(a号码: str): 11 | return int(a号码[6: 10]) 12 | def fg月(a号码: str): 13 | return int(a号码[10: 12]) 14 | def fg日(a号码: str): 15 | return int(a号码[12: 14]) 16 | def fg性别(a号码: str): 17 | return int(a号码[16]) % 2 18 | def fg校验码(a号码: str): 19 | return a号码[17] 20 | def fs月(a号码, a月): 21 | return a号码[:10] + 字符串.f数字整齐化(a月, 2) + a号码[12:] 22 | def fs日(a号码, a日): 23 | return a号码[:12] + 字符串.f数字整齐化(a月, 2) + a号码[14:] 24 | def fs月日(a号码, a月, a日): 25 | return a号码[:10] + 字符串.f数字整齐化(a月, 2) + 字符串.f数字整齐化(a日, 2) + a号码[14:] 26 | #计算 27 | def f计算校验码(a号码: str): 28 | """计算第18位 29 | a号码: 17位号码,18位号码""" 30 | v校验和 = 0 31 | for i in range(17): 32 | v校验和 += ((1 << (17 - i)) % 11) * int(a号码[i]) 33 | v校验码 = (12 - (v校验和 % 11)) % 11 34 | return str(v校验码) if v校验码 < 10 else "X" 35 | def f验证身份证号(a号码: str): 36 | v校验码 = f计算校验码(a号码) 37 | return a号码[17] == v校验码 38 | def fe补全出生月日(a号码: str): 39 | """补全出生月日, 适用于:火车票 40 | a号码: 18位身份证号,出生月日随意""" 41 | v年 = fg年(a号码) 42 | for v月, v日 in 时间.fe全年月日(时间.fi闰年(v年)): 43 | v号码 = fs月日(a号码, v月, v日) 44 | if f验证身份证号(v号码): 45 | yield v号码 -------------------------------------------------------------------------------- /cflw代码库py/cflw函数.py: -------------------------------------------------------------------------------- 1 | def A忽略异常(af): 2 | def f(*args, **kwargs): 3 | try: 4 | return af(*args, **kwargs) 5 | except Exception as e: 6 | return None 7 | return f -------------------------------------------------------------------------------- /cflw代码库py/cflw图像.py: -------------------------------------------------------------------------------- 1 | import enum 2 | import functools 3 | from PIL import Image, ImageDraw #pillow 4 | from . import cflw数学 as 数学 5 | from . import cflw数学_向量 as 向量 6 | from . import cflw数学_图形 as 图形 7 | class E定位(enum.IntEnum): 8 | e左上 = enum.auto() 9 | e中上 = enum.auto() 10 | e右上 = enum.auto() 11 | e左中 = enum.auto() 12 | e中间 = enum.auto() 13 | e右中 = enum.auto() 14 | e左下 = enum.auto() 15 | e中下 = enum.auto() 16 | e右下 = enum.auto() 17 | class E寻址(enum.IntEnum): 18 | e环绕 = enum.auto() 19 | e镜面 = enum.auto() 20 | e夹取 = enum.auto() 21 | e颜色 = enum.auto() 22 | class E采样(enum.IntEnum): 23 | e最近点 = enum.auto() 24 | e线性 = enum.auto() 25 | class C模式: 26 | c二值 = "1" 27 | c灰度 = "L" 28 | c红绿蓝 = "RGB" 29 | c红绿蓝阿 = "RGBA" 30 | c印刷四色 = "CMYK" 31 | rgb = "RGB" 32 | rgba = "RGBA" 33 | cmyk = "CMYK" 34 | c水印掩码 = 3 35 | c水印透明度 = 0.05 36 | def fe坐标(a尺寸: tuple): 37 | for y in range(a尺寸[1]): 38 | for x in range(a尺寸[0]): 39 | yield x, y 40 | def fc图像(a数据: list, a模式: str, a尺寸: tuple, a颜色 = 0): 41 | v新图 = Image.new(str(a模式), a尺寸, a颜色) 42 | v新图.putdata(a数据) 43 | return v新图 44 | def F坐标到索引(a尺寸: tuple): 45 | return lambda x, y: int(y * a尺寸[0] + x) 46 | #=============================================================================== 47 | # 简单计算 48 | #=============================================================================== 49 | #像素 50 | def f双像素运算m(a像素0: tuple, a像素1: tuple, af运算s): 51 | return tuple(af运算s(v像素1, v像素2) for v像素1, v像素2 in zip(a像素0, a像素1)) 52 | def F双像素运算m(a像素0: tuple, a像素1: tuple, af运算s): 53 | return functools.partial(f双像素运算m, af运算s = af运算s) 54 | def f单像素运算m(a像素: tuple, af运算s): 55 | return tuple(af运算s(v像素) for v像素 in a像素) 56 | def F单像素运算m(a像素: tuple, af运算s): 57 | return functools.partial(f单像素运算m, af运算s = af运算s) 58 | #类型转换 59 | def ft尺寸(a): 60 | v类型 = type(a) 61 | if v类型 in (向量.S向量2, 向量.S向量3, 向量.S向量4): 62 | return a.x, a.y 63 | elif v类型 in (list, tuple): 64 | if len(a) >= 2: 65 | return tuple(a) 66 | else: 67 | raise ValueError("长度必需>=2") 68 | else: 69 | raise ValueError("无法识别的类型") 70 | def ft颜色(a颜色, a模式): 71 | #生成元组 72 | v类型 = type(a颜色) 73 | if v类型 == int: 74 | return a颜色 75 | elif v类型 == 图形.S颜色: 76 | return tuple(int(v * 255) for v in a颜色.fe分量()) 77 | elif v类型 in (list, tuple): 78 | if len(a颜色) >= 3: 79 | return tuple(a颜色) 80 | else: 81 | raise ValueError("长度必需>=3") 82 | else: 83 | raise ValueError("无法识别的类型") 84 | #=============================================================================== 85 | # 像素读写 86 | #=============================================================================== 87 | def f像素写m(a像素: tuple, a写: tuple, a掩码: int): 88 | "多通道" 89 | return f双像素运算m(a像素, a写, functools.partial(f像素写s, a掩码 = a掩码)) 90 | def f像素写s(a像素: int, a写: int, a掩码: int): 91 | "单通道" 92 | return (a像素 & ~a掩码) | (a写 & a掩码) 93 | def f像素读m(a像素: tuple, a掩码: int): 94 | "多通道" 95 | return f单像素运算m(a像素, functools.partial(f像素读s, a掩码 = a掩码)) 96 | def f像素读s(a像素: int, a掩码: int): 97 | "单通道" 98 | return a像素 & a掩码 99 | def f颜色缩小m(a像素: tuple, a掩码: int): 100 | "多通道" 101 | return f单像素运算m(a像素, functools.partial(f颜色缩小s, a掩码 = a掩码)) 102 | def f颜色缩小s(a像素: int, a掩码: int): 103 | "单通道" 104 | return a像素 // (256 // (a掩码 + 1)) 105 | def f颜色放大m(a像素: tuple, a掩码: int): 106 | "多通道" 107 | return f单像素运算m(a像素, functools.partial(f颜色放大s, a掩码 = a掩码)) 108 | def f颜色放大s(a像素: int, a掩码: int): 109 | "单通道" 110 | return a像素 * 255 // a掩码 111 | #=============================================================================== 112 | # 二维图像计算 113 | #=============================================================================== 114 | def f对(af0, af1, a: tuple): 115 | return af0(a[0]), af1(a[1]) 116 | def f内(a坐标: int, a尺寸: int): 117 | return a坐标 if 数学.fi限制内(a坐标, 0, a尺寸 - 1) else None 118 | def f计算偏移(a原尺寸: tuple, a新尺寸: tuple, a定位: E定位): 119 | v差x = a新尺寸[0] - a原尺寸[0] 120 | v差y = a新尺寸[1] - a原尺寸[1] 121 | if a定位 in (E定位.e左上, E定位.e左中, E定位.e左下): 122 | v偏移x = 0 123 | elif a定位 in (E定位.e中上, E定位.e中间, E定位.e中下): 124 | v偏移x = v差x // 2 125 | elif a定位 in (E定位.e右上, E定位.e右中, E定位.e右下): 126 | v偏移x = v差x 127 | if a定位 in (E定位.e左上, E定位.e中上, E定位.e右上): 128 | v偏移y = 0 129 | elif a定位 in (E定位.e左中, E定位.e中间, E定位.e右中): 130 | v偏移y = v差y // 2 131 | elif a定位 in (E定位.e左下, E定位.e中下, E定位.e右下): 132 | v偏移y = v差y 133 | return v偏移x, v偏移y 134 | def F寻址_相对(a偏移: tuple): 135 | "给定新尺寸坐标, 计算出原尺寸坐标" 136 | return lambda x, y: (x - a偏移[0], y - a偏移[1]) 137 | def F寻址_环绕(a原尺寸: tuple, a偏移: tuple): 138 | vf相对 = F寻址_相对(a偏移) 139 | vf循环x = functools.partial(数学.f循环, a最小值 = 0, a最大值 = a原尺寸[0] - 1) 140 | vf循环y = functools.partial(数学.f循环, a最小值 = 0, a最大值 = a原尺寸[1] - 1) 141 | return lambda x, y: f对(vf循环x, vf循环y, vf相对(x, y)) 142 | def F寻址_镜面(a原尺寸: tuple, a偏移: tuple): 143 | vf相对 = F寻址_相对(a偏移) 144 | vf镜面x = functools.partial(数学.f整数镜面, a最小值 = 0, a最大值 = a原尺寸[0] - 1) 145 | vf镜面y = functools.partial(数学.f整数镜面, a最小值 = 0, a最大值 = a原尺寸[1] - 1) 146 | return lambda x, y: f对(vf镜面x, vf镜面y, vf相对(x, y)) 147 | def F寻址_夹取(a原尺寸: tuple, a偏移: tuple): 148 | vf相对 = F寻址_相对(a偏移) 149 | vf限制x = functools.partial(数学.f限制, a最小值 = 0, a最大值 = a原尺寸[0] - 1) 150 | vf限制y = functools.partial(数学.f限制, a最小值 = 0, a最大值 = a原尺寸[1] - 1) 151 | return lambda x, y: f对(vf限制x, vf限制y, vf相对(x, y)) 152 | def F寻址_颜色(a原尺寸: tuple, a偏移: tuple): 153 | vf相对 = F寻址_相对(a偏移) 154 | vf颜色x = functools.partial(f内, a尺寸 = a原尺寸[0]) 155 | vf颜色y = functools.partial(f内, a尺寸 = a原尺寸[1]) 156 | return lambda x, y: f对(vf颜色x, vf颜色y, vf相对(x, y)) 157 | def F取像素(a原数据: list, a原尺寸: tuple, af寻址坐标, a颜色): 158 | """高级的取像素""" 159 | vf索引 = F坐标到索引(a原尺寸) 160 | def f取像素(x, y): 161 | vx, vy = af寻址坐标(x, y) 162 | if vx != None and vy != None: 163 | return a原数据[vf索引(vx, vy)] 164 | else: 165 | return a颜色 166 | return f取像素 167 | #=============================================================================== 168 | # 混合,像素必需是rgba字节整数格式 169 | #=============================================================================== 170 | def f颜色混合_正常(c0: int, a0: int, c1: int, a1: int): 171 | return c0 * (255 - a1) // 255 + c1 * a1 // 255 172 | def f颜色混合_叠加(c0: int, a0: int, c1: int, a1: int): 173 | return (c0 * a0 // 255 + c1 * a1 // 255) % 255 174 | def f颜色混合_叠底(c0: int, a0: int, c1: int, a1: int): 175 | return (c0 * a0 // 255 - c1 * a1 // 255) % 255 176 | def f像素混合(a像素0: tuple, a像素1: tuple, af颜色通道, af阿通道): 177 | a0 = a像素0[3] 178 | a1 = a像素1[3] 179 | r = af颜色通道(a像素0[0], a0, a像素1[0], a1) 180 | g = af颜色通道(a像素0[1], a0, a像素1[1], a1) 181 | b = af颜色通道(a像素0[2], a0, a像素1[2], a1) 182 | a = af阿通道(a0, a1) 183 | return (r, g, b, a) 184 | def f像素混合_正常(a像素0: tuple, a像素1: tuple): 185 | return f像素混合(a像素0, a像素1, f颜色混合_正常, max) 186 | def f像素混合_叠加(a像素0: tuple, a像素1: tuple): 187 | return f像素混合(a像素0, a像素1, f颜色混合_叠加, max) 188 | def f像素混合_叠底(a像素0: tuple, a像素1: tuple): 189 | return f像素混合(a像素0, a像素1, f颜色混合_叠底, max) 190 | #=============================================================================== 191 | # 通用图像处理 192 | #=============================================================================== 193 | def f调整画布大小(a图像, a尺寸, a定位: E定位 = E定位.e左上, a寻址: E寻址 = E寻址.e颜色, a颜色: 图形.S颜色 = 图形.S颜色.c黑): 194 | v原尺寸 = a图像.size 195 | v新尺寸 = ft尺寸(a尺寸) 196 | v偏移 = f计算偏移(v原尺寸, v新尺寸, a定位) 197 | vf寻址 = { 198 | E寻址.e环绕: F寻址_环绕, 199 | E寻址.e夹取: F寻址_夹取, 200 | E寻址.e镜面: F寻址_镜面, 201 | E寻址.e颜色: F寻址_颜色, 202 | }[a寻址](v原尺寸, v偏移) 203 | v原图像 = list(a图像.getdata()) 204 | v颜色 = ft颜色(a颜色, a图像.mode) 205 | vf取像素 = F取像素(v原图像, v原尺寸, vf寻址, v颜色) 206 | v新图像 = list(vf取像素(x, y) for x, y in fe坐标(v新尺寸)) 207 | return fc图像(v新图像, a图像.mode, a尺寸) 208 | def f平铺图像(a图像, a尺寸): 209 | "等于 f调整画布大小(a图像, a尺寸, a定位 = E定位.e左上, a寻址 = E寻址.e环绕, a颜色 = 图形.S颜色.c黑)" 210 | v图像 = Image.new(a图像.mode, a尺寸, (0, 0, 0, 0)) 211 | v尺寸x, v尺寸y = ft尺寸(a尺寸) 212 | for y in range(0, v尺寸y, a图像.height): 213 | for x in range(0, v尺寸x, a图像.width): 214 | v图像.paste(a图像, (x, y)) 215 | return v图像 216 | def f调整图像大小(a图像, a尺寸, a采样 = E采样.e线性): 217 | raise NotImplementedError() 218 | def f单图像像素运算(a图像, af运算m): 219 | v图像数据 = list(a图像.getdata()) 220 | v处理数据 = list(af运算m(v图像像素) for v图像像素 in v图像数据) 221 | return fc图像(v处理数据, a图像.mode, a图像.size) 222 | def f双图像像素运算_顺序(a图像0, a图像1, af运算m): 223 | """逐数据运算,如果图像尺寸不同,运算的像素可能有对不上""" 224 | v图像数据0 = list(a图像0.getdata()) 225 | v图像数据1 = list(a图像1.getdata()) 226 | v处理数据 = list(af运算m(v图像像素0, v图像像素1) for v图像像素0, v图像像素1 in zip(v图像数据0, v图像数据1)) 227 | return fc图像(v处理数据, a图像0.mode, a图像0.size) 228 | def f双图像像素运算_对齐(a图像0, a图像1, af运算m): 229 | """逐坐标运算,能保证2张图的像素坐标对得上""" 230 | v图像数据0 = list(a图像0.getdata()) 231 | v图像数据1 = list(a图像1.getdata()) 232 | vf索引0 = F坐标到索引(a图像0.size) 233 | vf索引1 = F坐标到索引(a图像1.size) 234 | v宽1 = a图像1.width 235 | v高1 = a图像1.height 236 | def f运算(x, y): 237 | if x < v宽1 and y < v高1: 238 | return af运算m(v图像数据0[vf索引0(x, y)], v图像数据1[vf索引1(x, y)]) 239 | else: 240 | return v图像数据0[vf索引0(x, y)] 241 | v处理数据 = list(f运算(x, y) for x, y in fe坐标(a图像0.size)) 242 | return fc图像(v处理数据, a图像0.mode, a图像0.size) 243 | #=============================================================================== 244 | # 特殊图像处理 245 | #=============================================================================== 246 | def f添加最低有效位水印(a图像, a水印, a掩码 = c水印掩码): 247 | return f双图像像素运算_顺序(a图像, a水印, lambda a像素, a写: f像素写m(a像素, f颜色缩小m(a写, a掩码), a掩码)) 248 | def f提取最低有效位水印(a图像, a掩码 = c水印掩码): 249 | return Image.eval(a图像, lambda a像素: f颜色放大s(f像素读s(a像素, a掩码), a掩码)) 250 | def f添加透明水印(a图像, a水印, a透明度 = c水印透明度): 251 | """PIL.Image.blend不处理透明通道,所以写一个替代""" 252 | def f混合(a像素0: tuple, a像素1: tuple): 253 | a0 = a像素0[3] if len(a像素0) > 3 else 1 254 | a1 = int(a像素1[3] * a透明度) 255 | r = f颜色混合_正常(a像素0[0], a0, a像素1[0], a1) 256 | g = f颜色混合_正常(a像素0[1], a0, a像素1[1], a1) 257 | b = f颜色混合_正常(a像素0[2], a0, a像素1[2], a1) 258 | a = max(a0, a1) 259 | return (r, g, b, a) 260 | return f双图像像素运算_顺序(a图像, a水印, f混合) -------------------------------------------------------------------------------- /cflw代码库py/cflw字符串.py: -------------------------------------------------------------------------------- 1 | import string 2 | import re 3 | import functools 4 | from . import cflw工具_运算 as 运算 5 | #=============================================================================== 6 | # 常量 7 | #=============================================================================== 8 | c换行符 = "\n" 9 | #字符串 10 | c字符串_半角字母数字符号 = string.ascii_letters + string.digits + string.punctuation 11 | c字符串_全角数字 = '0123456789' 12 | c字符串_全角小写字母 = 'abcdefghijklmnopqrstuvwxyz' 13 | c字符串_全角大写字母 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 14 | #编码范围,使用unicode编码 15 | c编码范围_半角字符 = range(0x21, 0x7f) 16 | c编码范围_全角字符 = range(0x2e80, 0xd7ff) 17 | c编码范围_汉字 = range(0x4e00, 0x9fa6) 18 | #正则表达式,需要编译 19 | c正则表达式_文字 = r"[\w\u4e00-\u9fa6]" 20 | ca汉字大小写 = [ 21 | ("一", "壹"), 22 | ("二", "贰"), 23 | ("三", "叁"), 24 | ("四", "肆"), 25 | ("五", "伍"), 26 | ("六", "陆"), 27 | ("七", "柒"), 28 | ("八", "捌"), 29 | ("九", "玖"), 30 | ("十", "拾"), 31 | ("百", "佰"), 32 | ("千", "仟") 33 | ] 34 | #=============================================================================== 35 | # 字符计算&判断 36 | #=============================================================================== 37 | def fi半角字符(a字符): 38 | v编码 = ord(a字符) 39 | return v编码 in c编码范围_半角字符 40 | def fi汉字(a字符): 41 | v编码 = ord(a字符) 42 | return v编码 in c编码范围_汉字 43 | def f计算字符宽度(a字符: str): 44 | "汉字,全角字符算2个字符宽,tab算8个字符宽" 45 | v编码 = ord(a字符) 46 | if v编码 in c编码范围_半角字符: #半角字符 47 | return 1 48 | elif v编码 in c编码范围_全角字符: #全角字符 49 | return 2 50 | elif v编码 == 9: #制表符 51 | return 8 52 | else: #未知 53 | return 0 54 | def fi闭(a字符): 55 | return a字符 in "[]" 56 | def fi开(a字符): 57 | return a字符 in "()" 58 | #=============================================================================== 59 | # 字符串查找&计算 60 | #=============================================================================== 61 | def f计算字符串宽度(a字符串): 62 | v字符串 = str(a字符串) 63 | v宽度 = 0 64 | for v in v字符串: 65 | v宽度 += f计算字符宽度(v) 66 | return v宽度 67 | def f统计汉字数量(a字符串): 68 | "统计字符串中出现的汉字的字数" 69 | v字符串 = str(a字符串) 70 | v数量 = 0 71 | for v in v字符串: 72 | if fi汉字(v): 73 | v数量 += 1 74 | return v数量 75 | def f全部找(a字符串: str, a找: str): 76 | """a找 在 a字符串 中出现位置,返回列表""" 77 | v列表 = [] 78 | v位置 = 0 79 | while True: 80 | v位置 = a字符串.find(a找, v位置) 81 | if v位置 >= 0: 82 | v列表.append(v位置) 83 | v位置 += 1 84 | else: 85 | break 86 | return v列表 87 | def fe找(a字符串: str, a找: str): 88 | """返回迭代器""" 89 | v位置 = 0 90 | while True: 91 | v位置 = a字符串.find(a找, v位置) 92 | if v位置 >= 0: 93 | yield v位置 94 | v位置 += 1 95 | else: 96 | break 97 | def f连续找最后(a字符串: str, *aa找, a开始 = 0): 98 | "根据要找的字符串一直往后找" 99 | v位置 = a开始 - 1 100 | for v找 in aa找: 101 | v位置 = a字符串.find(v找, v位置 + 1) 102 | if v位置 < 0: 103 | break 104 | return v位置 105 | def fe分隔后每组长度(a字符串, a分隔): 106 | va分隔 = a字符串.split(a分隔) 107 | for v字符串 in va分隔: 108 | yield len(v字符串) 109 | def f找前面匹配(aa字符串, a找, a标记 = 0): 110 | '从列表中找出前面与a字符串匹配的项' 111 | v正则 = re.compile(r"^" + a找, a标记) 112 | for v字符串 in aa字符串: 113 | if type(v字符串) != str: 114 | raise TypeError("元素类型必须是字符串") 115 | if re.search(v正则, v字符串): 116 | return v字符串 117 | def fi前面匹配(a原始字符串, a查找字符串, a标记 = 0): 118 | v正则 = re.compile(a查找字符串, a标记) 119 | if re.match(v正则, a原始字符串): 120 | return True 121 | else: 122 | return False 123 | def f查找_保留找到(a位置: int): 124 | """保留找到值,找不到则返回None""" 125 | if a位置 == -1: 126 | return None 127 | else: 128 | return a位置 129 | def f查找_计算偏移(a位置, a偏移: int): 130 | """判断位置是否有效,有效则计算""" 131 | if a位置 != None: 132 | return a位置 + a偏移 133 | else: 134 | return None 135 | def f找字符串之间(a字符串: str, a开始: str, a结束: str, a包含开始: bool = False, a反向查找: bool = False)->slice: 136 | """找原始字符串中开始到结束字符串之间的字符串,返回切片 137 | 例如:f("a.b.c.d", "." ,".")返回slice(1,3) 138 | """ 139 | #找位置 140 | if a反向查找: 141 | if a结束: 142 | v结束位置 = a字符串.rfind(a结束) 143 | v结束位置 = f查找_保留找到(v结束位置) 144 | else: 145 | v结束位置 = None 146 | if a开始: 147 | v结束位置1 = f查找_计算偏移(v结束位置, (-len(a结束) if a结束 else -1)) 148 | v开始位置 = a字符串.rfind(a开始, None, v结束位置1) 149 | v开始位置 = f查找_保留找到(v开始位置) 150 | else: 151 | v开始位置 = 0 152 | else: #正向查找 153 | if a开始: 154 | v开始位置 = a字符串.find(a开始) 155 | v开始位置 = f查找_保留找到(v开始位置) 156 | else: 157 | v开始位置 = 0 158 | if a结束: 159 | v开始位置1 = f查找_计算偏移(v开始位置, (len(a开始) if a开始 else 1)) 160 | v结束位置 = a字符串.find(a结束, v开始位置1) 161 | v结束位置 = f查找_保留找到(v结束位置) 162 | else: 163 | v结束位置 = None 164 | #返回 165 | if a包含开始 or v开始位置 == None: 166 | return slice(v开始位置, v结束位置) 167 | else: 168 | if a开始: 169 | return slice(v开始位置 + len(a开始), v结束位置) 170 | else: 171 | return slice(v开始位置, v结束位置) 172 | def f找行开始位置(a字符串: str, a位置: int, a换行符: str = c换行符)->int: 173 | """查找当前位置所在行的开始位置,不含换行符""" 174 | v行开始位置 = a字符串.rfind(a换行符, None, a位置) 175 | if v行开始位置 == -1: 176 | return 0 177 | else: 178 | return v行开始位置 + 1 179 | def f找行结束位置(a字符串: str, a位置: int, a换行符: str = c换行符)->int: 180 | """查找当前位置所在行的结束位置,含换行符""" 181 | v行结束位置 = a字符串.find(a换行符, a位置) 182 | if v行结束位置 == -1: 183 | return len(a字符串) 184 | else: 185 | return v行结束位置 186 | def f找包含行(a字符串: str, a查找: str, a开始位置: int = 0, a换行符: str = c换行符)->slice: 187 | """查找目标字符串所在的行的切片""" 188 | v查找位置 = a字符串.find(a查找, a开始位置) 189 | if v查找位置 == -1: 190 | return None #找不到 191 | v行开始位置 = f找行开始位置(a字符串, v查找位置) 192 | v行结束位置 = f找行结束位置(a字符串, v查找位置) 193 | return slice(v行开始位置, v行结束位置) 194 | def fe包含行(a字符串: str, a查找: str, a开始位置: int = 0, a换行符: str = c换行符): 195 | v位置 = a开始位置 196 | while True: 197 | v切片 = f找包含行(a字符串, a查找, v位置, a换行符) 198 | if v切片 == None: 199 | break 200 | yield a字符串[v切片] 201 | v位置 = v切片.stop 202 | def f找上一行位置(a字符串: str, a位置: int, a换行符: str = c换行符, a循环: int = 1)->int: 203 | v行结束位置 = a位置 204 | for i in range(a循环): 205 | v行结束位置 = a字符串.rfind(a换行符, 0, v行结束位置) 206 | if v行结束位置 == -1: 207 | return -1 #没有上一行 208 | v行开始位置 = f找行开始位置(a字符串, v行结束位置) 209 | return v行开始位置 210 | def f找下一行位置(a字符串: str, a位置: int, a换行符: str = c换行符, a循环: int = 1)->int: 211 | v行开始位置 = a位置 212 | for i in range(a循环): 213 | v行开始位置 = a字符串.find(a换行符, v行开始位置) 214 | if v行开始位置 == -1: 215 | return -1 #没有下一行 216 | v行开始位置 = v行开始位置 + 1 217 | return v行开始位置 218 | def f找当前行切片(a字符串: str, a位置: int, a换行符: str = c换行符)->slice: 219 | """定位当前行的切片""" 220 | v行开始位置 = a字符串.rfind(a换行符, 0, a位置) + 1 #找到换行符位置,+1才是行开始位置 221 | v行结束位置 = a字符串.find(a换行符, a位置) 222 | return slice(max(v行开始位置, 0), v行结束位置) 223 | def f找上一行切片(a字符串: str, a位置: int, a换行符: str = c换行符, a循环: int = 1)->slice: 224 | """往前定位行""" 225 | v行结束位置 = a位置 226 | for i in range(a循环): 227 | v行结束位置 = a字符串.rfind(a换行符, 0, v行结束位置) 228 | if v行结束位置 == -1: 229 | return None #没有上一行 230 | v行开始位置 = f找行开始位置(a字符串, v行结束位置) 231 | return slice(v行开始位置, v行结束位置) 232 | def f找下一行切片(a字符串: str, a位置: int, a换行符: str = c换行符, a循环: int = 1)->slice: 233 | """往后定位行, 循环0次是当前行, 循环1次是下一行""" 234 | v行开始位置 = a位置 235 | for i in range(a循环): 236 | v行开始位置 = a字符串.find(a换行符, v行开始位置) 237 | if v行开始位置 == -1: 238 | return None #没有下一行 239 | v行开始位置 = v行开始位置 + 1 240 | v行结束位置 = f找行结束位置(a字符串, v行开始位置) 241 | return slice(v行开始位置, v行结束位置) 242 | def fi数字(a字符串: str)->bool: 243 | "a字符串.strip().isdigit()" 244 | return a字符串.strip().isdigit() 245 | def fi连续范围(a字符串: str)->bool: 246 | """为真: "a-b", "a~b" """ 247 | if "-" in a字符串: 248 | v分割 = a字符串.split("-") 249 | elif "~" in a字符串: 250 | v分割 = a字符串.split("~") 251 | else: 252 | return False 253 | if len(v分割) != 2: 254 | return False 255 | a, b = v分割 256 | if not fi数字(a): 257 | return False 258 | if not fi数字(b): 259 | return False 260 | return True 261 | def fi区间范围(a字符串: str)->bool: 262 | """为真: "(a, b)", "[a, b]" """ 263 | if not a字符串[0] in "([": 264 | return False 265 | if not a字符串[-1] in ")]": 266 | return False 267 | v分割 = a字符串[1:-1].split(",") 268 | if len(v分割) != 2: 269 | return False 270 | a, b = v分割 271 | if not fi数字(a): 272 | return False 273 | if not fi数字(b): 274 | return False 275 | return True 276 | def f取行缩进(a行: str, a制表符长度: int = 4)->int: 277 | v缩进 = 0 278 | for i in range(len(a行)): 279 | c = a行[i] 280 | if c == ' ': 281 | v缩进 += 1 282 | elif c == '\t': 283 | v缩进 = v缩进 + a制表符长度 - v缩进 % a制表符长度 284 | else: 285 | break 286 | return v缩进 287 | #=============================================================================== 288 | # 字符串操作,返回字符串 289 | #=============================================================================== 290 | def f去头尾空白(a字符串: str): 291 | return a字符串.strip() 292 | def f去前面(a字符串: str, a前面: str): 293 | "前面及更前的字符串全部去除" 294 | v位置 = a字符串.find(a前面) 295 | if v位置 > 0: 296 | return a字符串[v位置 + len(a前面):] 297 | return a字符串 298 | def f去后面(a字符串: str, a后面: str): 299 | "后面及更后的字符串全部去除" 300 | v位置 = a字符串.rfind(a后面) 301 | if v位置 > 0: 302 | return a字符串[:v位置] 303 | return a字符串 304 | def f去非十六进制数字(a字符串): 305 | if len(a字符串) < 2: 306 | v字符串 = a字符串 307 | elif a字符串[1] in "xX": #去掉0x 308 | v字符串 = a字符串[2:] 309 | else: 310 | v字符串 = a字符串 311 | v字符串 = "".join([v for v in v字符串 if v in "0123456789abcdefABCDEF"]) #提取数字 312 | return v字符串 313 | def f去非数字(a字符串): 314 | return "".join([v for v in a字符串 if v in "0123456789"]) 315 | def f去词(a字符串, a序号, a分隔 = " "): 316 | va文本 = a字符串.split(a分隔) 317 | va文本.pop(a序号) 318 | return a分隔.join(va文本) 319 | def f插入字符串(a字符串, a位置, a插入字符串): 320 | return a字符串[:a位置] + a插入字符串 + a字符串[a位置:] 321 | def f隔段插入字符串(a字符串, a插入字符串, a间隔): 322 | """每隔一段距离插入字符串 323 | a间隔 的类型可以是int或range""" 324 | v字符串 = str(a字符串) 325 | v类型 = type(a间隔) 326 | if v类型 == int: 327 | v长度 = len(a字符串) 328 | v余数 = v长度 % a间隔 329 | if v余数 == 0: #不能包含尾 330 | i = v长度 - a间隔 331 | else: 332 | i = v长度 - v余数 333 | while i > 0: 334 | v字符串 = f插入字符串(v字符串, i, a插入字符串) 335 | i -= a间隔 336 | elif v类型 == range: 337 | v长度 = len(a字符串) 338 | v尾 = int(a间隔.stop) 339 | v头 = int(a间隔.start) 340 | v步进 = int(a间隔.step) 341 | if v头 < 0: 342 | v头 = v步进 343 | v余数 = (v尾 - v头) % v步进 344 | if v余数 == 0: #不能包含尾 345 | i = v长度 - v步进 346 | else: 347 | i = v长度 - v余数 348 | while i >= v头: 349 | v字符串 = f插入字符串(v字符串, i, a插入字符串) 350 | i -= v步进 351 | if i == 0: 352 | break #不能包含头 353 | else: 354 | raise TypeError() 355 | return v字符串 356 | def f填充_(a字符串, a填充, a目标长度, af填充): 357 | """af填充(a原字符串, a填充字符串)""" 358 | if not a填充: 359 | raise ValueError() 360 | v当前长度 = len(a字符串) 361 | if v当前长度 < a目标长度: 362 | v填充数量 = (a目标长度 - v当前长度) // len(a填充) 363 | return af填充(a字符串, a填充 * v填充数量) 364 | else: 365 | return a字符串 366 | def f前面填充(a字符串, a填充, a目标长度): 367 | """当a字符串长度小于a目标长度,则填充到目标长度""" 368 | return f填充_(a字符串, a填充, a目标长度, lambda a, b: b + a) 369 | def f后面填充(a字符串, a填充, a目标长度): 370 | """当a字符串长度小于a目标长度,则填充到目标长度""" 371 | return f填充_(a字符串, a填充, a目标长度, lambda a, b: a + b) 372 | def f匹配补全(a字符串, aa字符串): 373 | for v字符串 in aa字符串: 374 | if a字符串 in v字符串: 375 | return v字符串 376 | return None 377 | def f前面匹配补全(a字符串, aa字符串, a正则标志 = 0): 378 | v正则 = re.compile(r"^" + a字符串, a正则标志) 379 | for v字符串 in aa字符串: 380 | if a字符串 == v字符串: 381 | return v字符串 382 | elif re.search(v正则, v字符串): 383 | return v字符串 384 | return None 385 | def fe字符串特定字符之间(a字符串, a字符, a开始位置 = 0): 386 | v字符长度 = len(a字符) 387 | v开始位置 = a开始位置 388 | v结束位置 = 0 389 | while True: 390 | v结束位置 = a字符串.find(a字符, v开始位置 + 1) 391 | if v结束位置 == -1: 392 | yield a字符串[v开始位置 : ] 393 | else: 394 | yield a字符串[v开始位置 : v结束位置] 395 | v开始位置 = v结束位置 + v字符长度 396 | def f提取字符串之间(a字符串, a开始, a结束, a包含开始 = False, a反向查找 = False, a结束严谨 = True): 397 | """找原始字符串中开始到结束字符串之间的字符串,找不到返回"" 398 | 例如:f("a.b.c.d", "." ,".")返回"b" 399 | a包含开始: 返回的字符串包含开始字符串 400 | a反向查找: 401 | a结束严谨: 结果找不到结束就返回"", 不严谨则返回开始到字符串结尾""" 402 | v位置 = f找字符串之间(a字符串, a开始, a结束, a包含开始, a反向查找) 403 | #找不到则返回空 404 | if v位置.start == None: 405 | return None 406 | if v位置.stop == None: 407 | if not a结束: #没有 a结束 408 | return a字符串[v位置.start:] 409 | if a结束严谨: #有 a结束 410 | return None 411 | return a字符串[v位置.start:] 412 | #正常返回 413 | return a字符串[v位置] 414 | def f转大写数字(a字符串): 415 | v字符串 = str(a字符串) 416 | for v in ca汉字大小写: 417 | v字符串.replace(v[0], v[1]) 418 | return v字符串 419 | def fe分割(a字符串, a分割 = "\n", a开始位置 = 0): 420 | v开始位置 = a开始位置 421 | v长度 = len(a字符串) 422 | while True: 423 | v结束位置 = a字符串.find(a分割, v开始位置) 424 | if v结束位置 == -1: 425 | yield a字符串[v开始位置:] 426 | break 427 | else: 428 | yield a字符串[v开始位置 : v结束位置] 429 | v开始位置 = v结束位置 + 1 430 | if v开始位置 >= v长度: 431 | break 432 | def fe按位置分割(a字符串, *aa位置, af暂回 = str.strip): 433 | "包含位置字符" 434 | v开始 = 0 435 | vf暂回处理 = af暂回 if af暂回 else 运算.f原值 436 | for v位置 in aa位置: 437 | if v位置 == 0: 438 | continue 439 | v结束 = v位置 440 | yield vf暂回处理(a字符串[v开始:v结束]) 441 | v开始 = v结束 442 | yield vf暂回处理(a字符串[v开始:]) #最后一列 443 | def fe按字符分割(a字符串, *aa字符, af暂回 = str.strip): 444 | "不包含分割字符" 445 | v开始 = 0 446 | vf暂回处理 = af暂回 if af暂回 else 运算.f原值 447 | for v字符 in aa字符: 448 | v结束 = a字符串.find(v字符, v开始) 449 | yield vf暂回处理(a字符串[v开始:v结束]) 450 | v开始 = v结束 + 1 451 | if v开始 < len(a字符串): 452 | yield vf暂回处理(a字符串[v开始:]) 453 | def f回车处理(a字符串: str): 454 | "\\r后的字符会覆盖行首内容" 455 | va行 = [] 456 | for v原行 in a字符串.split("\n"): 457 | v新行 = "" 458 | #遍历\r,覆盖行首 459 | v开始位置 = 0 460 | while True: 461 | v结束位置 = v原行.find("\r", v开始位置) 462 | if v结束位置 >= 0: 463 | v新行 = f覆盖(v新行, v原行[v开始位置 : v结束位置]) 464 | else: 465 | v新行 = f覆盖(v新行, v原行[v开始位置:]) 466 | break 467 | v开始位置 = v结束位置 + 1 468 | va行.append(v新行) 469 | return "\n".join(va行) 470 | def f覆盖(a原: str, a新: str, a开始位置 = 0): 471 | if not a新: #没东西不覆盖 472 | return a原 473 | v原长度 = len(a原) 474 | if a开始位置 > v原长度: 475 | raise ValueError("开始位置不能超过原字符串长度") 476 | v目标长度 = a开始位置 + len(a新) 477 | if v目标长度 > v原长度: 478 | return a原[0 : a开始位置] + a新 479 | else: 480 | return a原[0 : a开始位置] + a新 + a原[v目标长度:] 481 | def f提取字符串周围(a字符串: str, a前: str, a中: str, a后: str): 482 | """找包含中间的字符串,返回前后字符串.\n 483 | 找不到中间则返回"",找不到两边则取头尾\n 484 | 例如: f提取字符串周围("123 456 789", " ", "5", " ")返回" 456 " """ 485 | #找 486 | if type(a中) == int: 487 | v位置 = a中 488 | v长度 = 1 489 | else: 490 | v位置 = a字符串.find(a中) 491 | v长度 = len(a中) 492 | if not v位置: 493 | return "" 494 | #前 495 | if type(a前) == int: 496 | v前 = v位置 + a前 497 | else: 498 | v前 = a字符串.rfind(a前, 0, v位置) 499 | if v前 < 0: 500 | v前 = 0 501 | #后 502 | if type(a后) == int: 503 | v后 = v位置 + v长度 + a后 504 | else: 505 | v后 = a字符串.find(a后, v位置 + v长度) 506 | #结束 507 | if v后 < 0: 508 | return a前 509 | else: 510 | return a字符串[a前: a后] 511 | def F提取字符串周围(a前: str, a中: str, a后: str): 512 | return functools.partial(f提取字符串周围, a前 = a前, a中 = a中, a后 = a后) 513 | def f提取包含行(a字符串: str, a包含: str): 514 | """从字符串中提取包含指定文本的行, 返回的字符串不含换行符, 找不到则返回"" """ 515 | for v行 in a字符串.split("\n"): 516 | if a包含 in v行: 517 | return v行 518 | return "" 519 | def F提取包含行(a包含: str): 520 | return functools.partial(f提取包含行, a包含 = a包含) 521 | def f提取第几行(a文本: str, a行数: int): 522 | """从0开始, 超出范围则抛出异常""" 523 | v位置 = 0 524 | v行数 = 0 525 | while True: 526 | v行结束 = a文本.find("\n", v位置) 527 | v行 = a文本[v位置 : v行结束] 528 | if v行数 == a行数: 529 | return v行 530 | v位置 = v行结束 + 1 531 | v行数 += 1 532 | class C推进取词: 533 | def __init__(self, a文本: str): 534 | self.ma词 = a文本.split() 535 | self.m数量 = len(self.ma词) 536 | self.i = 0 537 | def f取词(self)->str: 538 | if self.i >= self.m数量: 539 | return None 540 | return self.ma词[self.i] 541 | def f推进(self): 542 | self.i += 1 543 | def f取词推进(self)->str: #先取词再推进 544 | if self.i >= self.m数量: 545 | return None 546 | v词 = self.ma词[self.i] 547 | self.i += 1 548 | return v词 549 | #=============================================================================== 550 | # 特殊字符处理 551 | #=============================================================================== 552 | def fi标识符字符(c: str): 553 | """可以作为标识符字符的: 554 | 数字, 大小写字母, _, 各国语言文字(除了标点符号) 555 | """ 556 | v编码 = ord(c) 557 | if v编码 < 0x30: #符号 558 | return False 559 | elif v编码 < 0x3a: #0x30~0x3a 数字 560 | return True 561 | elif v编码 < 0x41: #符号 562 | return False 563 | elif v编码 < 0x5b: #0x41~0x5a 大写字母 564 | return True 565 | elif v编码 == 0x5f: #0x5f 下划线 566 | return True 567 | elif v编码 < 0x61: #符号 568 | return False 569 | elif v编码 < 0x7b: #0x61~0x7b 小写字母 570 | return True 571 | elif v编码 < 0x2e80: 572 | return False 573 | elif v编码 < 0x9fa5: #中日韩符号文字 574 | return True 575 | else: 576 | return False 577 | def f去特殊字符(s: str): # 578 | """去除不能作为python标识符的字符""" 579 | return "".join(list(filter(lambda c: fi标识符字符(c), s))) 580 | #=============================================================================== 581 | # 字符串转换 582 | #=============================================================================== 583 | def ft字符串(*a元组, a分隔符 = "\t"): 584 | v格式 = "%s" + a分隔符 585 | return (v格式 * len(a元组)) % a元组 586 | def ft字符串序列(a序列): 587 | for v in a序列: 588 | yield str(v) 589 | def ft范围(a字符串: str): 590 | """支持的格式:\n 591 | 连字符: "a-b", "a~b"\n 592 | 区间: "(a, b)", "[a, b]" """ 593 | v左闭 = True 594 | v右闭 = True 595 | if "-" in a字符串: 596 | v分割 = a字符串.split("-") 597 | elif "~" in a字符串: 598 | v分割 = a字符串.split("~") 599 | elif "," in a字符串: 600 | v左闭 = fi闭(a字符串[0]) 601 | v右闭 = fi闭(a字符串[-1]) 602 | v分割 = a字符串[1:-1].split(",") 603 | else: 604 | raise ValueError("无法把字符串转换成 range 对象") 605 | a, b = v分割 606 | v左 = int(a) 607 | if not v左闭: #左开 608 | v左 += 1 609 | v右 = int(b) 610 | if v右闭: #右闭 611 | v右 += 1 612 | return range(v左, v右) 613 | #=============================================================================== 614 | # 文本对齐 615 | #=============================================================================== 616 | class C文本对齐处理: 617 | def __init__(self, a宽度, a对齐方向 = -1): 618 | self.m宽度 = a宽度 619 | self.fs对齐方向(a对齐方向) 620 | self.fs边距(0, 0) 621 | def fs对齐方向(self, a对齐方向): 622 | if type(a对齐方向) in (int, float): 623 | self.m对齐方向 = a对齐方向 624 | elif type(a对齐方向) == str: 625 | v字符 = a对齐方向[0] 626 | if 'l' == v字符: 627 | self.m对齐方向 = -1 628 | elif 'r' == v字符: 629 | self.m对齐方向 = 1 630 | elif 'c' == v字符: 631 | self.m对齐方向 = 0 632 | elif '左' == v字符: 633 | self.m对齐方向 = -1 634 | elif '右' == v字符: 635 | self.m对齐方向 = 1 636 | elif '中' == v字符 or '居中' == a对齐方向[0:2]: 637 | self.m对齐方向 = 0 638 | else: 639 | raise ValueError 640 | else: 641 | raise TypeError 642 | def fs边距(self, a左边距, a右边距): 643 | self.m左边距 = a左边距 644 | self.m右边距 = a右边距 645 | def f处理(self, a字符串): 646 | '把原字符串转换成对齐后的字符串' 647 | v宽度 = f计算字符宽度(a字符串) 648 | v空格 = self.m宽度 - v宽度 649 | if v空格 < 0: 650 | raise ValueError('参数字符串的宽度超出范围') 651 | if self.fi左对齐(): 652 | v处理后 = a字符串 + ' ' * v空格 653 | elif self.fi右对齐(): 654 | v处理后 = ' ' * v空格 + a字符串 655 | return ' ' * self.m左边距 + v处理后 + ' ' * self.m右边距 656 | def fi左对齐(self): 657 | return self.m对齐方向 < 0 658 | def fi右对齐(self): 659 | return self.m对齐方向 > 0 660 | def fi居中对齐(self): 661 | return self.m对齐方向 == 0 662 | def f数字整齐化(a数字: int, a位数: int): 663 | """前面补零, 使之整齐 664 | f(1, 2) -> "01" 665 | f(998, 2) -> "98" 666 | """ 667 | v数字 = str(a数字) 668 | v长度 = len(v数字) 669 | if v长度 < a位数: 670 | return "0" * (a位数 - v长度) + v数字 671 | elif v长度 > a位数: 672 | return v数字[v长度 - a位数:] 673 | else: 674 | return v数字 675 | #=============================================================================== 676 | # 模板 677 | #=============================================================================== 678 | class C模板: 679 | c匹配括号 = re.compile(r"\{" + c正则表达式_文字 + r"+\}") 680 | def __init__(self, s: str): 681 | self.m字符串 = s 682 | self.ma参数 = [] 683 | v列表 = C模板.c匹配括号.findall(s) 684 | for v in v列表: 685 | self.ma参数.append((C模板.f去括号(v), v)) #添加("k", "{k}"),前者用于查找,后者用于替换 686 | def f替换(self, **d): 687 | v字符串 = self.m字符串 688 | for v参数 in self.ma参数: 689 | k = v参数[0] 690 | if k in d: 691 | v = str(d[k]) 692 | v字符串 = v字符串.replace(v参数[1], v) 693 | return v字符串 694 | @staticmethod 695 | def f去括号(s: str)->str: 696 | return s[1:-1] 697 | @staticmethod 698 | def f加括号(s: str)->str: 699 | return "{" + s + "}" -------------------------------------------------------------------------------- /cflw代码库py/cflw工具.py: -------------------------------------------------------------------------------- 1 | import math 2 | import re 3 | c数字正则 = re.compile(r"\d+") 4 | class S版本号: 5 | def __init__(self, aa版本): 6 | self.ma版本 = list(int(v) for v in aa版本) 7 | def __str__(self): 8 | return ".".join(str(v) for v in self.ma版本) 9 | def __repr__(self): 10 | return "" 11 | def __cmp__(self, a): 12 | v类型 = type(a) 13 | if v类型 == S版本号: 14 | v长度0 = len(self.ma版本) 15 | v长度1 = len(a.ma版本) 16 | for i in range(min(v长度0, v长度1)): 17 | v比较 = self.ma版本[i] - a.ma版本[i] 18 | if v比较 != 0: 19 | return v比较 20 | return v长度0 - v长度1 21 | elif v类型 == int: 22 | return self.ma版本[0] - a 23 | elif v类型 == float: 24 | v版本号 = S版本号.fc小数(a) 25 | return self.__cmp__(v版本号) 26 | elif v类型 == str: 27 | v版本号 = S版本号.fc字符串(a) 28 | return self.__cmp__(v版本号) 29 | elif v类型 in (list, tuple): 30 | v版本号 = S版本号.fc元组(a) 31 | return self.__cmp__(v版本号) 32 | else: 33 | raise TypeError("无法解析的类型") 34 | def __eq__(self, a): 35 | return self.__cmp__(a) == 0 36 | def __ne__(self, a): 37 | return self.__cmp__(a) != 0 38 | def __lt__(self, a): 39 | return self.__cmp__(a) < 0 40 | def __le__(self, a): 41 | return self.__cmp__(a) <= 0 42 | def __gt__(self, a): 43 | return self.__cmp__(a) > 0 44 | def __ge__(self, a): 45 | return self.__cmp__(a) >= 0 46 | def __getitem__(self, k): 47 | if k >= len(self.ma版本): 48 | return 0 49 | else: 50 | return self.ma版本[k] 51 | def __setitem__(self, k, v): 52 | v长度 = len(self.ma版本) 53 | if k >= v长度: 54 | self.ma版本.extend([0] * (v长度 - k)) 55 | self.ma版本.append(v) 56 | else: 57 | self.ma版本[k] = v 58 | def __len__(self): 59 | return len(self.ma版本) 60 | @staticmethod 61 | def fc自动(*a): 62 | v长度 = len(a) 63 | if v长度 == 0: 64 | raise ValueError("必需有参数") 65 | if v长度 > 1: 66 | return S版本号(a) 67 | v = a[0] 68 | v类型 = type(v) 69 | if v类型 == int: 70 | return S版本号.fc整数(v) 71 | elif v类型 == float: 72 | return S版本号.fc小数(v) 73 | elif v类型 == str: 74 | return S版本号.fc字符串(v) 75 | elif v类型 in (list, tuple): 76 | return S版本号.fc元组(v) 77 | elif v类型 == S版本号: 78 | return S版本号(v.ma版本) 79 | else: 80 | raise TypeError("无法解析的类型") 81 | @staticmethod 82 | def fc字符串(a字符串: str): 83 | va分割 = a字符串.split(".") 84 | def f处理(a段): 85 | va数字 = c数字正则.findall(a段) 86 | return int(va数字[0]) 87 | v元组 = tuple(f处理(v) for v in va分割) 88 | return S版本号.fc分段(*v元组) 89 | @staticmethod 90 | def fc分段(*a元组): 91 | return S版本号(a元组) 92 | @staticmethod 93 | def fc数字(a): 94 | v类型 = type(a) 95 | if v类型 == int: 96 | return S版本号.fc整数(a) 97 | elif v类型 == float: 98 | return S版本号.fc小数(a) 99 | else: 100 | raise TypeError("无法解析的类型") 101 | @staticmethod 102 | def fc整数(a: int): 103 | return S版本号((a,)) 104 | @staticmethod 105 | def fc小数(a: float): 106 | v整数 = math.floor(a) 107 | v小数 = a - v整数 108 | if v小数 > 0: #可能有0.0 109 | v小数 = v小数 * 10 ** math.ceil(-math.log10(v小数)) 110 | return S版本号.fc分段(v整数, v小数) 111 | @staticmethod 112 | def fc元组(a元组: tuple): 113 | return S版本号(a元组) 114 | def ft元组(self): 115 | return self.ma版本 -------------------------------------------------------------------------------- /cflw代码库py/cflw工具_序列.py: -------------------------------------------------------------------------------- 1 | #=============================================================================== 2 | # 序列 3 | #=============================================================================== 4 | def fe如果(af判断, a序列): 5 | for v元素 in a序列: 6 | if af判断(v元素): 7 | yield v元素 8 | def f折叠(af运算, a初始值, a序列): 9 | v结果 = a初始值 10 | for v元素 in a序列: 11 | v结果 = af运算(v结果, v元素) 12 | return v结果 13 | def f映射(af运算, a序列): 14 | for v元素 in a序列: 15 | yield af运算(v元素) 16 | #=============================================================================== 17 | # 字典 18 | #=============================================================================== 19 | def f字典按值找键(a字典: dict, a值): 20 | for v键, v值 in a字典.items(): 21 | if v值 == a值: 22 | return v键 23 | return None 24 | def f整数位与键为真则添加值(a整数, a字典): 25 | v列表 = [] 26 | for k, v in a字典.items(): 27 | if a整数 & k: 28 | v列表.append(v) 29 | return v列表 30 | def f字典键值反转(a字典): 31 | return dict(zip(a字典.values(), a字典.keys())) 32 | def f字典有键则运算(a字典, a键, af运算): 33 | if a键 in a字典: 34 | return af运算(a字典[a键]) 35 | return None 36 | #=============================================================================== 37 | # 切片 38 | #=============================================================================== 39 | def F切片(a开始, a结束, a间距 = None): 40 | def f切片(a序列): 41 | return a序列[slice(a开始, a结束, a间距)] 42 | return f切片 43 | class C切片组: 44 | """指定一组序号,按索引取切片""" 45 | def __init__(self, *aa索引): 46 | if aa索引[0] == 0: 47 | self.ma索引 = aa索引 48 | else: 49 | self.ma索引 = (0,) + aa索引 50 | self.m长度 = len(self.ma索引) 51 | def __getitem__(self, k): 52 | return self.fg切片(k) 53 | def __iter__(self): 54 | for i in range(self.m长度): 55 | yield self.fg切片(i) 56 | def fg切片(self, k): 57 | if self.m长度 > k + 1: 58 | return slice(self.ma索引[k], self.ma索引[k+1]) 59 | elif self.m长度 == k + 1: 60 | return slice(self.ma索引[k], None) 61 | else: 62 | raise IndexError() 63 | def F切片(self, k): 64 | v切片 = self.fg切片(k) 65 | def f切片(a序列): 66 | return a序列[v切片] 67 | return f切片 68 | def F多切片(self, *k): 69 | va切片 = list(self.fg切片(kk) for kk in k) 70 | def f切片(a序列): 71 | return (a序列[v切片] for v切片 in va切片) 72 | return f切片 -------------------------------------------------------------------------------- /cflw代码库py/cflw工具_运算.py: -------------------------------------------------------------------------------- 1 | import operator 2 | def f原值(a): #不做任何处理的函数 3 | return a 4 | def f空(*a, **b): 5 | pass 6 | def f空0(): 7 | pass 8 | def f空1(a0): 9 | pass 10 | def f总是真(*a, **b): 11 | return True 12 | def f总是假(*a, **b): 13 | return False 14 | #比较 15 | f等于 = operator.eq 16 | f不等于 = operator.ne 17 | f小于 = operator.lt 18 | f大于 = operator.gt 19 | f小于等于 = operator.le 20 | f大于等于 = operator.ge 21 | def f比较(a, b): 22 | if hasattr(a, "__cmp__"): 23 | return a.__cmp__(b) 24 | if a > b: 25 | return 1 26 | if a < b: 27 | return -1 28 | return 0 29 | def f反比较(a, b): 30 | if hasattr(a, "__cmp__"): 31 | return -a.__cmp__(b) 32 | if a > b: 33 | return -1 34 | if a < b: 35 | return 1 36 | return 0 37 | #逻辑运算 38 | def f且(a, b): 39 | return a and b 40 | def f或(a, b): 41 | return a or b 42 | f非 = operator.not_ 43 | f真 = operator.truth 44 | f是 = operator.is_ 45 | f不是 = operator.is_not 46 | #位运算 47 | f位与 = operator.and_ 48 | f位或 = operator.or_ 49 | f位异或 = operator.xor 50 | f位反 = operator.invert 51 | def f位拆分(a整数: int)->list: 52 | v位 = 1 53 | v列表 = [] 54 | while v位 <= a整数: 55 | if a整数 & v位: 56 | v列表.append(v位) 57 | v位 *= 2 58 | return v列表 59 | #四则运算 60 | f加 = operator.add 61 | f减 = operator.sub 62 | f乘 = operator.mul 63 | f除 = operator.truediv 64 | f正 = operator.pos 65 | f负 = operator.neg 66 | f乘方 = operator.pow 67 | f矩乘 = operator.matmul 68 | #序列运算 69 | f包含 = operator.contains #b in a 70 | def f不包含(a, b): 71 | "not b in a" 72 | return not b in a 73 | def f属于(a, b): 74 | "a in b" 75 | return a in b 76 | def f不属于(a, b): 77 | "not a in b" 78 | return not a in b 79 | def F包含(a): 80 | def f包含(b): 81 | return b in a 82 | return f包含 83 | def F属于(a): 84 | def f属于(b): 85 | return a in b 86 | return f属于 -------------------------------------------------------------------------------- /cflw代码库py/cflw按键脚本_win.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import time 3 | import win32api #pywin32 4 | import win32con #pywin32 5 | import win32gui #pywin32 6 | from . import cflw数学 as 数学 7 | from . import cflw数学_向量 as 向量 8 | from . import cflw输入_win as 输入 9 | #=============================================================================== 10 | # 视窗原生结构 11 | #=============================================================================== 12 | class POINT(ctypes.Structure): 13 | _fields_ = [("x", ctypes.c_ulong), ("y", ctypes.c_ulong)] 14 | #=============================================================================== 15 | # 鼠标按键 16 | #=============================================================================== 17 | E鼠标按键 = 输入.E鼠标按键 18 | ca鼠标按键 = { 19 | #按键 按下 松开 20 | E鼠标按键.e左键: (win32con.MOUSEEVENTF_LEFTDOWN, win32con.MOUSEEVENTF_LEFTUP), 21 | E鼠标按键.e右键: (win32con.MOUSEEVENTF_RIGHTDOWN, win32con.MOUSEEVENTF_RIGHTUP), 22 | E鼠标按键.e中键: (win32con.MOUSEEVENTF_MIDDLEDOWN, win32con.MOUSEEVENTF_MIDDLEUP), 23 | } 24 | def fg鼠标坐标(): 25 | v点 = POINT() 26 | ctypes.windll.user32.GetCursorPos(ctypes.byref(v点)) 27 | return 向量.S向量2(v点.x, v点.y) 28 | def f鼠标移动到(a坐标): 29 | ctypes.windll.user32.SetCursorPos(int(a坐标.x), int(a坐标.y)) 30 | def f鼠标移动向(a移动): 31 | v坐标 = fg鼠标坐标() 32 | v移动 = v坐标 + a移动 33 | f鼠标移动到(v移动) 34 | def f鼠标平滑移动到(a坐标, a时间 = 1, a细分 = 10): 35 | v开始坐标 = fg鼠标坐标() 36 | f鼠标平滑移动(v开始坐标, a坐标, a时间, a细分) 37 | def f鼠标平滑移动向(a移动, a时间 = 1, a细分 = 10): 38 | v开始坐标 = fg鼠标坐标() 39 | f鼠标平滑移动(v开始坐标, v开始坐标 + a移动, a时间, a细分) 40 | def f鼠标平滑移动(a开始坐标, a结束坐标, a时间 = 1, a细分 = 10): 41 | v时间间隔 = a时间 / a细分 42 | for i in range(1, a细分 + 1): 43 | v坐标 = 数学.f插值(a开始坐标, a结束坐标, i / a细分) 44 | f鼠标移动到(v坐标) 45 | time.sleep(v时间间隔) 46 | def f鼠标按下(a按键): 47 | win32api.mouse_event(ca鼠标按键[a按键][0], 0, 0, 0, 0) 48 | def f鼠标松开(a按键): 49 | win32api.mouse_event(ca鼠标按键[a按键][1], 0, 0, 0, 0) 50 | def f鼠标按键(a按键, a时间 = 0): 51 | f鼠标按下(a按键) 52 | time.sleep(a时间) 53 | f鼠标松开(a按键) 54 | #=============================================================================== 55 | # 键盘按键 56 | #=============================================================================== 57 | E键盘按键 = 输入.E键盘按键 58 | def f键盘按下(a按键): 59 | win32api.keybd_event(a按键, 0, 0, 0) 60 | def f键盘松开(a按键): 61 | win32api.keybd_event(a按键, 0, win32con.KEYEVENTF_KEYUP, 0) 62 | def f键盘按键(a按键, a时间 = 0): 63 | f键盘按下(a按键) 64 | time.sleep(a时间) 65 | f键盘松开(a按键) -------------------------------------------------------------------------------- /cflw代码库py/cflw控制台.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from . import cflw字符串 as 字符串 3 | g单行覆盖输出宽度 = 0 4 | def f单行覆盖输出(a文本): 5 | "反复调用会覆盖之前输出的字符,不想覆盖了就换行" 6 | v宽度 = 字符串.f计算字符串宽度(a文本) 7 | sys.stdout.write(a文本) 8 | if g单行覆盖输出宽度 > v宽度: 9 | sys.stdout.write(" " * (g单行覆盖输出宽度 - v宽度)) 10 | g单行覆盖输出宽度 = v宽度 11 | sys.stdout.write("\r") 12 | sys.stdout.flush() 13 | class C参数解析器: 14 | class S参数属性: 15 | def __init__(self): 16 | self.m参数名 = "" 17 | self.m类型 = str 18 | self.m帮助 = "" 19 | self.m默认 = "" 20 | def __init__(self): 21 | self.ma参数属性 = {} 22 | def f添加参数(self, *aa参数, a类型 = str, a帮助 = "", a默认 = ""): 23 | v属性 = C参数解析器.S参数属性() 24 | v属性.m类型 = a类型 25 | v属性.m帮助 = a帮助 26 | v属性.m默认 = a默认 27 | for v参数名 in aa参数: 28 | v属性.m参数名 = v参数名 29 | self.ma参数属性[v参数名] = v属性 30 | def fg帮助文本(self): 31 | raise NotImplementedError() 32 | def f解析参数(self, a = None): 33 | #取参数 34 | if a == None: 35 | if len(sys.argv) < 2: 36 | return {} 37 | va参数 = sys.argv[1:] 38 | else: 39 | va参数 = str(a).split() 40 | #解析参数 41 | v结果 = {} 42 | v参数名 = None 43 | for v参数 in va参数: 44 | if v参数名 == None: 45 | if v参数 in self.ma参数属性: 46 | v参数名 = v参数 47 | v结果[v参数名] = None 48 | else: 49 | v结果[v参数名] = self.ma参数属性[v参数名].m类型(v参数) 50 | v参数名 = None 51 | #赋默认值 52 | for k, v in v结果: 53 | if v == None and self.ma参数属性[k].m默认: 54 | v结果[k] = self.ma参数属性[k].m默认 55 | #返回 56 | return v结果 57 | class C命令解析器: 58 | class S命令属性: 59 | def __init__(self): 60 | self.m命令名 = "" 61 | self.mf命令 = None 62 | self.m参数名 = "" 63 | self.m命令帮助 = "" 64 | def __init__(self): 65 | self.ma命令属性 = {} 66 | def f添加命令(self, a命令名, af命令, a参数名 = "参数", a帮助 = ""): 67 | v属性 = S命令属性() 68 | v属性.m命令名 = a命令名 69 | v属性.mf命令 = af命令 70 | v属性.m参数名 = a参数名 71 | v属性.m命令帮助 = a帮助 72 | self.ma命令属性[a命令名] = v属性 73 | def f循环(self): 74 | while True: 75 | v输入 = input(">") 76 | self.f解析命令(v输入) 77 | def f解析命令(self, a命令: str): 78 | va命令 = a命令.split() 79 | if len(va命令) > 1: 80 | v参数 = tuple(va命令[1:]) 81 | else: 82 | v参数 = () 83 | try: 84 | self.ma命令属性[va命令[0]].mf命令(*v参数) 85 | except Exception as e: 86 | print(e) 87 | -------------------------------------------------------------------------------- /cflw代码库py/cflw操作系统.py: -------------------------------------------------------------------------------- 1 | import os 2 | if os.name == "nt": 3 | from .cflw操作系统_win import * 4 | else: 5 | from .cflw操作系统_linux import * -------------------------------------------------------------------------------- /cflw代码库py/cflw操作系统_linux.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | import pathlib 4 | def fi程序存在(a目录: str, a文件名: str): 5 | v目录 = pathlib.Path(a目录) 6 | v程序路径 = v目录 / a文件名 7 | if os.path.exists(v程序路径): 8 | return v程序路径 9 | def f搜索程序路径(a文件名: str, a环境变量: str = "PATH"): 10 | """搜索环境变量的程序,返回绝对路径""" 11 | v环境变量值 = os.environ[a环境变量] 12 | if ":" in v环境变量值: #linux使用:分隔 13 | for v环境变量值1 in v环境变量值.split(":"): 14 | if v路径 := fi程序存在(v环境变量值1, a文件名): 15 | return v路径 16 | else: 17 | if v路径 := fi程序存在(v环境变量值, a文件名): 18 | return v路径 19 | -------------------------------------------------------------------------------- /cflw代码库py/cflw操作系统_win.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path 3 | import pathlib 4 | def fi程序存在(a目录: str, a文件名: str): 5 | v目录 = pathlib.Path(a目录) 6 | v程序路径 = v目录 / a文件名 7 | if os.path.exists(v程序路径): 8 | return v程序路径 9 | if not ".exe" in a文件名: #加.exe重新搜索 10 | v程序路径 = v目录 / (a文件名 + ".exe") 11 | if os.path.exists(v程序路径): 12 | return v程序路径 13 | def f搜索程序路径(a文件名: str, a环境变量: str = "PATH"): 14 | """搜索环境变量的程序,返回绝对路径. windows系统可以省略exe""" 15 | v环境变量值 = os.environ[a环境变量] 16 | if ";" in v环境变量值: #windows使用;分隔 17 | for v环境变量值1 in v环境变量值.split(";"): 18 | if v路径 := fi程序存在(v环境变量值1, a文件名): 19 | return v路径 20 | else: 21 | if v路径 := fi程序存在(v环境变量值, a文件名): 22 | return v路径 23 | -------------------------------------------------------------------------------- /cflw代码库py/cflw数学.py: -------------------------------------------------------------------------------- 1 | import math 2 | # 3 | def f循环(a值, a最小值, a最大值): 4 | assert(a最小值 < a最大值) 5 | v差 = a最大值 - a最小值 6 | v基本倍 = math.floor(a值 / v差) 7 | v循环倍 = math.ceil(a最小值 / v差) 8 | return a值 - v差 * (v基本倍 - v循环倍) 9 | def f限制(a值, a最小值, a最大值): 10 | assert(a最小值 < a最大值) 11 | if a值 < a最小值: 12 | return a最小值 13 | elif a值 > a最大值: 14 | return a最大值 15 | else: 16 | return a值 17 | def fi限制内(a值, a最小值, a最大值): 18 | assert(a最小值 <= a最大值) 19 | if a值 < a最小值: 20 | return False 21 | elif a值 > a最大值: 22 | return False 23 | else: 24 | return True 25 | def fi限制外(a值, a最小值, a最大值): 26 | assert(a最小值 < a最大值) 27 | if a值 < a最小值: 28 | return True 29 | elif a值 > a最大值: 30 | return True 31 | else: 32 | return False 33 | def f镜面(a值: float, a最小值: float, a最大值: float): 34 | """像镜子一样循环""" 35 | assert(a最小值 < a最大值) 36 | v差 = a最大值 - a最小值 37 | v基本倍 = math.floor(a值 / v差) 38 | v循环倍 = math.ceil(a最小值 / v差) 39 | v倍差 = v基本倍 - v循环倍 40 | v循环 = a值 - v差 * v倍差 41 | return f对称(v循环, (a最大值 + a最小值) / 2) if v倍差 % 2 else v循环 42 | def f整数镜面(a值: int, a最小值: int, a最大值: int): 43 | """[最小值, 最大值] 44 | 1,2,3|3,2,1|1,2,3 这样的""" 45 | assert(a最小值 < a最大值) 46 | v结束 = a最大值 + 1 47 | v差 = v结束 - a最小值 48 | v基本倍 = a值 // v差 49 | v相对位置 = a值 - v差 * v基本倍 50 | return a最大值 - v相对位置 if v基本倍 % 2 else a最小值 + v相对位置 51 | def f对称(a值, a对称): 52 | "值关于对称点对称" 53 | return 2 * a对称 - a值 # a对称 - (a值 - a对称) 54 | def f插值(a0, a1, a插值): 55 | return a0 + (a1 - a0) * a插值 56 | def ft合适(a): 57 | if "." in a: 58 | return float(a) 59 | if "∞" in a: 60 | return math.inf * (-1 if a[0] == "-" else 1) 61 | return int(a) 62 | #=============================================================================== 63 | def f算术平均数(*a): 64 | return sum(a) / len(a) 65 | def f几何平均数(*a): 66 | m = 1 67 | for v in a: 68 | m *= v 69 | return math.sqrt(m) 70 | def f平方和的平方根(*a): 71 | return math.sqrt(sum(v ** 2 for v in a)) 72 | #=============================================================================== 73 | class S区间: 74 | def __init__(self, a左值, a左闭, a右值, a右闭): 75 | self.m左值 = a左值 76 | self.m左闭 = a左闭 77 | self.m右值 = a右值 78 | self.m右闭 = a右闭 79 | @staticmethod 80 | def fc左右(a左: tuple, a右: tuple): 81 | def f(a): 82 | if type(a) == tuple: 83 | return a[0], a[1] 84 | else: 85 | return a, True 86 | return S区间(*f(a左), *f(a右)) 87 | @staticmethod 88 | def fc字符串(a: str, at值 = ft合适): 89 | v = str(a) 90 | v左闭 = a[0] == "[" 91 | v右闭 = a[-1] == "]" 92 | v左值, v右值 = a[1:-1].split(",") 93 | v左值, v右值 = at值(v左值), at值(v右值) 94 | return S区间(v左值, v左闭, v右值, v右闭) 95 | def __str__(self): 96 | v左符号 = "[" if self.m左闭 else "(" 97 | v右符号 = "]" if self.m右闭 else ")" 98 | return "%s%d, %d%s" % (v左符号, self.m左值, self.m右值, v右符号) 99 | def fi区间内(self, a数字): 100 | return (self.m左值.__le__ if self.m左闭 else self.m左值.__lt__)(a数字) and (self.m右值.__ge__ if self.m右闭 else self.m右值.__gt__)(a数字) -------------------------------------------------------------------------------- /cflw代码库py/cflw数学_向量.py: -------------------------------------------------------------------------------- 1 | import math 2 | from . import cflw数学 as 数学 3 | from . import cflw数学_矩阵 as 矩阵 4 | #=============================================================================== 5 | # 任意向量 6 | #=============================================================================== 7 | class S向量: 8 | def __init__(self, n, *t): 9 | self.m值 = list(t) 10 | def fc向量(a数量, *a值): 11 | if a数量 < 2: 12 | raise ValueError() 13 | elif a数量 == 2: 14 | return S向量2(*a值) 15 | elif a数量 == 3: 16 | return S向量3(*a值) 17 | elif a数量 == 4: 18 | return S向量4(*a值) 19 | else: 20 | return S向量(a数量, a值) 21 | #=============================================================================== 22 | # 向量2 23 | #=============================================================================== 24 | class S向量2: 25 | def __init__(self, ax = 0, ay = 0): 26 | self.x = ax 27 | self.y = ay 28 | def __str__(self): 29 | return "(" + str(self.x) + ", " + str(self.y) + ")" 30 | @staticmethod 31 | def fc方向r(a大小, a方向): 32 | return S向量2(math.cos(a方向) * a大小, math.sin(a方向) * a大小) 33 | @staticmethod 34 | def fc方向d(a大小, a方向): 35 | v方向 = math.radians(a方向) 36 | return S向量2.fc方向r(a大小, a方向) 37 | def __add__(self, a): 38 | "向量2 + 向量2" 39 | v类型 = type(a) 40 | if v类型 == S向量2: 41 | x = self.x + a.x 42 | y = self.y + a.y 43 | elif v类型 == S极向量2: 44 | raise NotImplementedError() 45 | else: 46 | raise TypeError() 47 | return S向量2(x, y) 48 | def __sub__(self, a): 49 | "向量2 - 向量2" 50 | v类型 = type(a) 51 | if v类型 == S向量2: 52 | x = self.x - a.x 53 | y = self.y - a.y 54 | elif v类型 == S极向量2: 55 | raise NotImplementedError() 56 | else: 57 | raise TypeError() 58 | return S向量2(x, y) 59 | def __mul__(self, a): 60 | "向量2 * 实数" 61 | v = float(a) 62 | x = self.x * v 63 | y = self.y * v 64 | return S向量2(x, y) 65 | def __truediv__(self, a): 66 | "向量2 / 实数" 67 | v = float(a) 68 | x = self.x / v 69 | y = self.y / v 70 | return S向量2(x, y) 71 | def fg大小(self): 72 | return math.hypot(self.x, self.y) 73 | def fg方向r(self): 74 | return math.atan2(self.y, self.x) 75 | def fg方向d(self): 76 | return math.degrees(self.fg方向r()) 77 | def fg到点距离(self, a点): 78 | x = self.x - a点.x 79 | y = self.y - a点.y 80 | return math.hypot(x, y) 81 | def fg到点方向r(self, a点): 82 | x = a点.x - self.x 83 | y = a点.y - self.y 84 | return math.atan2(y, x) 85 | def fg到点方向d(self, a点): 86 | return math.degrees(self.fg到点方向r(a点)) 87 | def fs大小(self, a大小): 88 | v倍数 = a大小 / self.fg大小() 89 | self.x *= v倍数 90 | self.y *= v倍数 91 | def fs方向r(self, a方向): 92 | v大小 = fg大小() 93 | self.x = math.cos(a方向) * a大小 94 | self.y = math.sin(a方向) * a大小 95 | def fs方向d(self, a方向): 96 | self.fs方向r(math.radians(a方向)) 97 | def f点乘(self, a向量): 98 | return self.x * a向量.x + self.y * a向量.y 99 | def ft向量3(self, az = 0): 100 | return S向量3(self.x, self.y, az) 101 | def ft向量4(self, az = 0, aw = 0): 102 | return S向量4(self.x, self.y, az, aw) 103 | def ft元组(self): 104 | return (self.x, self.y) 105 | def ft极向量2(self): 106 | return S极向量2.fc直角(self.x, self.y) 107 | m大小 = property(fg大小, fs大小, None, "向量大小") 108 | m方向r = property(fg方向r, fs方向r, None, "向量方向(弧度)") 109 | m方向d = property(fg方向d, fs方向d, None, "向量方向(度)") 110 | S向量2.c零 = S向量2(0, 0) 111 | #=============================================================================== 112 | # 向量3 113 | #=============================================================================== 114 | class S向量3: 115 | def __init__(self, ax = 0, ay = 0, az = 0): 116 | self.x = ax 117 | self.y = ay 118 | self.z = az 119 | def __add__(self, a): 120 | "向量3 + 向量3" 121 | v类型 = type(a) 122 | if v类型 == S向量3: 123 | return S向量3(self.x + a.x, self.y + a.y, self.z + a.z) 124 | else: 125 | raise TypeError() 126 | def __mul__(self, a): 127 | "向量3 * 实数" 128 | v = float(a) 129 | return S向量3(self.x * v, self.y * v, self.z * v) 130 | def fg大小(self): 131 | return 数学.f平方和的平方根(self.x, self.y, self.z) 132 | def fs大小(self, a大小): 133 | v倍数 = a大小 / self.fg大小() 134 | self.x *= v倍数 135 | self.y *= v倍数 136 | self.z *= v倍数 137 | def f点乘(self, a向量): 138 | return self.x * a向量.x + self.y * a向量.y + self.z * a向量.z 139 | def f叉乘(self, a向量): 140 | return S向量3( 141 | self.y * a向量.z - self.z * a向量.y, 142 | self.z * a向量.x - self.x * a向量.z, 143 | self.x * a向量.y - self.y * a向量.z 144 | ) 145 | def ft向量2(self): 146 | return S向量2(self.x, self.y) 147 | def ft向量4(self, aw = 0): 148 | return S向量4(self.x, self.y, self.z, aw) 149 | def ft元组(self): 150 | return (self.x, self.y, self.z) 151 | m大小 = property(fg大小, fs大小, None, "向量大小") 152 | S向量3.c零 = S向量3(0, 0, 0) 153 | #=============================================================================== 154 | # 向量4 155 | #=============================================================================== 156 | class S向量4: 157 | def __init__(self, ax = 0, ay = 0, az = 0, aw = 0): 158 | self.x = ax 159 | self.y = ay 160 | self.z = az 161 | self.w = aw 162 | def __mul__(self, a): 163 | v类型 = type(a) 164 | if isinstance(a, 矩阵.S矩阵): 165 | if a.fg行数() != 4 or a.fg列数 != 4: 166 | raise ValueError("矩阵行列数不匹配") 167 | v = S向量4() 168 | for i in range(4): 169 | for j in range(4): 170 | v[k] = self[i] * a.fg值(j, i) 171 | return v 172 | elif v类型 in (float, int): 173 | x = self.x * a 174 | y = self.y * a 175 | z = self.z * a 176 | w = self.w * a 177 | return S向量4(x, y, z, w) 178 | else: 179 | raise TypeError() 180 | def __getitem__(self, k): 181 | if k == 0: 182 | return self.x 183 | elif k == 1: 184 | return self.y 185 | elif k == 2: 186 | return self.z 187 | elif k == 3: 188 | return self.w 189 | else: 190 | raise IndexError() 191 | def __setitem__(self, k, v): 192 | if k == 0: 193 | self.x = v 194 | elif k == 1: 195 | self.y = v 196 | elif k == 2: 197 | self.z = v 198 | elif k == 3: 199 | self.w = v 200 | else: 201 | raise IndexError() 202 | def __iter__(self): 203 | yield self.x 204 | yield self.y 205 | yield self.z 206 | yield self.w 207 | def fg大小(self): 208 | return 数学.f平方和的平方根(self.x, self.y, self.z, self.w) 209 | def fs大小(self, a大小): 210 | v倍数 = a大小 / self.fg大小() 211 | self.x *= v倍数 212 | self.y *= v倍数 213 | self.z *= v倍数 214 | self.w *= v倍数 215 | def f点乘(self, a向量): 216 | return self.x * a向量.x + self.y * a向量.y + self.z * a向量.z + self.w * a向量.w 217 | def ft向量2(self): 218 | return S向量2(self.x, self.y) 219 | def ft向量3(self): 220 | return S向量3(self.x, self.y, self.z) 221 | def ft元组(self): 222 | return (self.x, self.y, self.z, self.w) 223 | m大小 = property(fg大小, fs大小, None, "向量大小") 224 | S向量4.c零 = S向量4(0, 0, 0, 0) 225 | #=============================================================================== 226 | # 极向量2 227 | #=============================================================================== 228 | class S极向量2: 229 | "用极坐标表示的向量" 230 | def __init__(self, ar, at): 231 | self.r = ar 232 | self.t = at 233 | @staticmethod 234 | def fc直角(self, ax, ay): 235 | t = math.atan2(ay, ax) 236 | r = 数学.f平方和的平方根(ax, ay) 237 | return S极向量2(r, t) 238 | def __add__(self, a): 239 | "极向量加极向量" 240 | v类型 = type(a) 241 | if v类型 == S极向量2: 242 | raise NotImplementedError() 243 | elif v类型 == S向量2: 244 | raise NotImplementedError() 245 | else: 246 | raise TypeError() 247 | def __mul__(self, a): 248 | "极向量乘实数" 249 | v = float(a) 250 | r = self.r * v 251 | return S极向量2(r, self.t) 252 | def ft向量2(self): 253 | return S向量2.fc方向r(self.r, self.t) -------------------------------------------------------------------------------- /cflw代码库py/cflw数学_图形.py: -------------------------------------------------------------------------------- 1 | import math 2 | from . import cflw数学 as 数学 3 | #=============================================================================== 4 | # 颜色转换 5 | #=============================================================================== 6 | def f红绿蓝到平均f(r: float, g: float, b: float): 7 | return (r + g + b) / 3 8 | def f红绿蓝到平均b(r: int, g: int, b: int): 9 | return (r + g + b) // 3 10 | def f红绿蓝到灰度f(r: float, g: float, b: float): 11 | return r * 0.299 + g * 0.587 + b * 0.114 12 | def f红绿蓝到灰度b(r: int, g: int, b: int): 13 | return (r*76 + g*150 + b*30) >> 8 14 | #=============================================================================== 15 | # 颜色 16 | #=============================================================================== 17 | class S颜色: 18 | def __init__(self, r = 0, g = 0, b = 0, a = 1): 19 | self.r = float(r) 20 | self.g = float(g) 21 | self.b = float(b) 22 | self.a = float(a) 23 | @staticmethod 24 | def fc红绿蓝全彩(r, g, b, a饱合度 = 1, a亮度 = 1, a = 1): 25 | v最大 = max(r, g, b) 26 | assert(v最大 > 0) 27 | r = 数学.f插值(1, r / v最大, a饱合度) * a亮度 28 | g = 数学.f插值(1, g / v最大, a饱合度) * a亮度 29 | b = 数学.f插值(1, b / v最大, a饱合度) * a亮度 30 | return S颜色(r, g, b, a) 31 | @staticmethod 32 | def fc色环(a色环, a饱合度 = 1, a亮度 = 1, a = 1): 33 | "0~1:红~红" 34 | return fc色环(a色环 * 3, a饱合度, a亮度, a) 35 | @staticmethod 36 | def fc三基色环(a环, a饱合度 = 1, a亮度 = 1, a = 1): 37 | "0红1绿2蓝" 38 | v = 数学.f循环(a环, 0, 3) 39 | if v < 1: 40 | r = 数学.f插值(1, 0, v) 41 | g = 数学.f插值(0, 1, v) 42 | b = 0 43 | elif v < 2: 44 | v插值 = v - 1 45 | r = 0 46 | g = 数学.f插值(1, 0, v插值) 47 | b = 数学.f插值(0, 1, v插值) 48 | else: #v <= 3 49 | v插值 = v - 2 50 | r = 数学.f插值(0, 1, v插值) 51 | g = 0 52 | b = 数学.f插值(1, 0, v插值) 53 | return fc红绿蓝全彩(r, g, b, a饱合度, a亮度, a) 54 | @staticmethod 55 | def fc彩虹(a环, a饱合度 = 1, a亮度 = 1, a = 1): 56 | v = 数学.f循环(a环, 0, 7) 57 | if v < 2: #红->黄 58 | v插值 = v / 2 59 | r = 1 60 | g = 数学.f插值(0, 1, v插值) 61 | b = 0 62 | elif v < 3: #黄->绿 63 | v插值 = v - 2 64 | r = 数学.f插值(0, 1, v插值) 65 | g = 1 66 | b = 0 67 | elif v < 5: #绿->蓝 68 | v插值 = (v - 3) / 2 69 | r = 0 70 | g = 数学.f插值(1, 0, v插值) 71 | b = 数学.f插值(0, 1, v插值) 72 | else: #5~7:蓝->红 73 | v插值 = (v - 5) / 2 74 | r = 数学.f插值(0, 1, v插值) 75 | g = 0 76 | b = 数学.f插值(1, 0, v插值) 77 | return fc红绿蓝全彩(r, g, b, a饱合度, a亮度, a) 78 | def __getitem__(self, k): 79 | if k == 0: 80 | return self.r 81 | elif k == 1: 82 | return self.g 83 | elif k == 2: 84 | return self.b 85 | elif k == 3: 86 | return self.a 87 | else: 88 | raise KeyError() 89 | def __setitem__(self, k, v): 90 | if k == 0: 91 | self.r = float(v) 92 | elif k == 1: 93 | self.g = float(v) 94 | elif k == 2: 95 | self.b = float(v) 96 | elif k == 3: 97 | self.a = float(v) 98 | else: 99 | raise KeyError() 100 | def __eq__(self, a): 101 | return self.r == a.r and self.g == a.g and self.b == a.b and self.a == a.a 102 | def __ne__(self, a): 103 | return self.r != a.r or self.g != a.g or self.b != a.b or self.a != a.a 104 | def __mul__(self, a0): 105 | r = self.r * a0 106 | g = self.g * a0 107 | b = self.b * a0 108 | a = self.a * a0 109 | return S颜色(r, g, b, a) 110 | def f分量乘(self, a颜色): 111 | r = self.r * a颜色.r 112 | g = self.g * a颜色.g 113 | b = self.b * a颜色.b 114 | a = self.a * a颜色.a 115 | return S颜色(r, g, b, a) 116 | def fe分量(self): 117 | yield self.r 118 | yield self.g 119 | yield self.b 120 | yield self.a 121 | def ft元组rgba(self): 122 | """包含rgba""" 123 | return (self.r, self.g, self.b, self.a) 124 | def ft元组rgb(self): 125 | """包含rgb""" 126 | return (self.r, self.g, self.b) 127 | def fg灰度(self): 128 | return f红绿蓝到灰度f(self.r, self.g, self.b) 129 | ft元祖 = ft元组rgba 130 | S颜色.c白 = S颜色(1, 1, 1, 1) 131 | S颜色.c黑 = S颜色(0, 0, 0, 1) 132 | S颜色.c红 = S颜色(1, 0, 0, 1) 133 | S颜色.c橙 = S颜色(1, 0.5, 0, 1) 134 | S颜色.c黄 = S颜色(1, 1, 0, 1) 135 | S颜色.c绿 = S颜色(0, 1, 0, 1) 136 | S颜色.c青 = S颜色(0, 1, 1, 1) 137 | S颜色.c蓝 = S颜色(0, 0, 1, 1) 138 | S颜色.c紫 = S颜色(1, 0, 1, 1) 139 | -------------------------------------------------------------------------------- /cflw代码库py/cflw数学_平面几何.py: -------------------------------------------------------------------------------- 1 | import math 2 | from cflw数学_向量 import * 3 | #=============================================================================== 4 | # 几何结构 5 | #=============================================================================== 6 | class S圆形: 7 | def __init__(self, a坐标: S向量2, a半径: float): 8 | self.m坐标 = a坐标 9 | self.m半径 = a半径 10 | @staticmethod 11 | def fc坐标半径(a坐标: S向量2, a半径: float): 12 | return S圆形(a坐标, a半径) 13 | @staticmethod 14 | def fc坐标直径(a坐标: S向量2, a直径: float): 15 | return S圆形(a坐标, a直径 / 2) 16 | def f相交判定(self, a): 17 | if isinstance(a, S圆形): 18 | return f圆形相交判定(self, a) 19 | class S矩形: 20 | def __init__(self, a坐标: S向量2, a半尺寸: S向量2): 21 | self.m坐标 = a坐标 22 | self.m半尺寸 = a半尺寸 23 | @staticmethod 24 | def fc坐标半尺寸(a坐标: S向量2, a半尺寸: S向量2): 25 | return S矩形(a坐标, a半尺寸) 26 | @staticmethod 27 | def fc坐标尺寸(a坐标: S向量2, a尺寸: S向量2): 28 | return S矩形(a坐标, a尺寸 / 2) 29 | class S旋转矩形: 30 | def __init__(self, a坐标: S向量2, a半尺寸: S向量2, a方向: float): 31 | self.m坐标 = a坐标 32 | self.m半尺寸 = a半尺寸 33 | self.m方向 = a方向 34 | @staticmethod 35 | def fc坐标半尺寸(a坐标: S向量2, a半尺寸: S向量2, a方向: float = 0): 36 | return S旋转矩形(a坐标, a半尺寸, a方向) 37 | @staticmethod 38 | def fc坐标尺寸(a坐标: S向量2, a尺寸: S向量2, a方向: float = 0): 39 | return S旋转矩形(a坐标, a尺寸 / 2, a方向) 40 | def f相交判定(self, a): 41 | raise NotImplementedError() 42 | #=============================================================================== 43 | # 相交判定函数 44 | #=============================================================================== 45 | def f相交判定(a0, a1): 46 | return a0.f相交判定(a1) 47 | def f圆形相交判定(a0: S圆形, a1: S圆形): 48 | v距离 = a0.m坐标.fg到点距离(a1.m坐标) 49 | return v距离 <= a0.m半径 + a1.m半径 50 | def f矩形相交判定(a0: S矩形, a1: S矩形): 51 | v距离x = abs(a0.m坐标.x - a1.m坐标.x) 52 | v距离y = abs(a0.m坐标.y - a1.m坐标.y) 53 | if v距离x <= a0.m半尺寸.x + a1.m半尺寸.x: 54 | return True 55 | elif v距离y <= a0.m半尺寸.y + a1.m半尺寸.y: 56 | return True 57 | else: 58 | return False 59 | -------------------------------------------------------------------------------- /cflw代码库py/cflw数学_矩阵.py: -------------------------------------------------------------------------------- 1 | import math 2 | #=============================================================================== 3 | # 任意矩阵 4 | #=============================================================================== 5 | class S多维矩阵: 6 | def __init__(self, a数量: tuple, a值): 7 | v总数量 = 1 8 | self.m数量 = [] #表示每一维度的数量 9 | for v in a数量: 10 | v数量 = int(v) 11 | if v数量 < 1: 12 | raise ValueError 13 | self.m数量.append(v数量) 14 | v总数量 *= v数量 15 | self.m = [0] * v总数量 #值 16 | v数量 = min(v总数量, len(a值)) 17 | for i in range(v数量): 18 | self.m[i] = a值[i] 19 | def __getitem__(self, k): 20 | v类型 = type(k) 21 | v维数 = self.fg维数() 22 | if v类型 == int: 23 | return self.m[k] 24 | elif v类型 == tuple: 25 | return self.fg值(*k) 26 | elif v类型 == slice: 27 | if k.step: 28 | self.fx维数(k.start) 29 | self.fx维数(k.end) 30 | v步进类型 = type(k.step) 31 | if v步进类型 == int: 32 | v步进值 = (k.step,) * v维数 33 | elif v步进类型 == tuple: 34 | self.fx维数(k.step) 35 | else: 36 | raise TypeError("无法解析的类型") 37 | else: 38 | v步进值 = (1,) * v维数 39 | def f递归(d, i, l): 40 | l.append(i) 41 | if d < v维数 - 1: #继续递归 42 | for j in range(k.start[d], k.end[d], k.step[d]): 43 | f递归(d + 1, j, l) 44 | else: #到底 45 | raise NotImplementedError() 46 | l.pop() 47 | for i in range(k.start[0], k.end[0], k.step[0]): 48 | f递归(0, i, []) 49 | else: 50 | raise TypeError("无法解析的类型") 51 | def fg维数(self): 52 | return len(self.m数量) 53 | def fg数量(self): 54 | return self.m数量 55 | def fg总数量(self): 56 | v总 = 1 57 | for v in self.m数量: 58 | v总 *= v 59 | return v总 60 | def fg值(self, *t): 61 | return self.m[self.f计算索引(*t)] 62 | def fx维数(self, t, x = True): 63 | if self.fg维数() != len(t): 64 | if x: 65 | raise ValueError("维数不一致") 66 | return False 67 | return True 68 | def f计算索引(self, *t): 69 | if not hasattr(self, "mf计算索引"): #生成乘表 70 | self.mf计算索引 = F计算矩阵索引(self.m数量) 71 | return self.mf计算索引(*t) 72 | class F计算矩阵索引: 73 | def __init__(self, a数量: tuple): 74 | self.m数量 = a数量 75 | self.m乘表 = [1] * self.m数量 76 | v积 = 1 77 | for i in range(v维数 - 2, -1, -1): 78 | v积 *= self.m数量[i] 79 | self.m乘表[i] = v积 80 | def __call__(self, *a): 81 | if len(a) != self.m数量: 82 | raise ValueError("维数不一致") 83 | v索引 = 0 84 | for i in range(self.m数量): 85 | v索引 += self.m乘表[i] * a[i] 86 | return v索引 87 | #=============================================================================== 88 | # 任意二维矩阵 89 | #=============================================================================== 90 | class S矩阵: 91 | def __init__(self, a数量: tuple, a值): 92 | if len(a数量) != 2: 93 | raise ValueError() 94 | self.m行 = int(a数量[0]) 95 | self.m列 = int(a数量[1]) 96 | self.m数量 = self.m行 * self.m列 97 | v参数值数 = len(a值) 98 | if v参数值数 > self.m数量: 99 | self.m值 = a值[:self.m数量] 100 | else: 101 | self.m值 = a值 + [0] * (self.m数量 - v参数值数) 102 | def __str__(self): 103 | s = "" 104 | for i in range(self.m行): 105 | v开始 = i * self.m列 106 | if i == 0: 107 | v开始字符, v结束字符 = "┌", "┐" 108 | elif i == self.m行 - 1: 109 | v开始字符, v结束字符 = "└", "┘" 110 | else: 111 | v开始字符, v结束字符 = "│", "│" 112 | s += v开始字符 + "\t".join([str(v) for v in self.m值[v开始 : v开始 + self.m列]]) + v结束字符 + "\n" 113 | return s 114 | def __add__(self, a矩阵): 115 | if self.m行 != a矩阵.m行 or self.m列 != a矩阵.m列: 116 | raise ValueError("矩阵行列数不匹配") 117 | v值 = [0] * self.m数量 118 | for i in range(self.m行): 119 | for j in range(self.m列): 120 | v索引 = i * self.m列 + j 121 | v值[v索引] = S矩阵.f值相加(self.m值[v索引], a矩阵.m值[v索引]) 122 | return S矩阵((self.m行, self.m列), v值) 123 | def __mul__(self, a矩阵): 124 | if self.m列 != a矩阵.m行: 125 | raise ValueError("矩阵行列数不匹配") 126 | v行 = self.m行 127 | v列 = a矩阵.m列 128 | v总数 = v行 * v列 129 | v值 = [0] * v总数 130 | for i in range(v行): 131 | for j in range(v列): 132 | ok = i * v列 + j 133 | for k in range(self.m列): 134 | ak = i * self.m列 + k 135 | bk = k * a矩阵.m列 + j 136 | v值[ok] = S矩阵.f值相加(v值[ok], S矩阵.f值相乘(self.m值[ak], a矩阵.m值[bk])) 137 | return S矩阵((v行, v列), v值) 138 | def __getitem__(self, k): 139 | return self.m值[self.f计算索引(k[0], k[1])] 140 | def fg行数(self): 141 | return self.m行 142 | def fg列数(self): 143 | return self.m列 144 | def fg值(self, i, j): 145 | return self.m值[self.f计算索引(i, j)] 146 | def f计算索引(self, i, j): 147 | return i * self.m列 + j 148 | @staticmethod 149 | def f值相加(a, b): 150 | va是数字 = type(a) in (int, float) 151 | vb是数字 = type(b) in (int, float) 152 | if va是数字 and vb是数字: 153 | return a + b 154 | if va是数字 and a == 0: 155 | return b 156 | if vb是数字 and b == 0: 157 | return a 158 | return str(a) + "+" + str(b) 159 | @staticmethod 160 | def f值相乘(a, b): 161 | def f加括号(a): 162 | v = str(a) 163 | if "+" in v: 164 | return "(" + v + ")" 165 | else: 166 | return v 167 | va是数字 = type(a) in (int, float) 168 | vb是数字 = type(b) in (int, float) 169 | if va是数字 and vb是数字: 170 | return a * b 171 | if va是数字: 172 | if a == 0: 173 | return 0 174 | elif a == 1: 175 | return b 176 | if vb是数字: 177 | if b == 0: 178 | return 0 179 | elif b == 1: 180 | return a 181 | return f加括号(a) + "*" + f加括号(b) 182 | #=============================================================================== 183 | # 二阶矩阵 184 | #=============================================================================== 185 | class S矩阵2(S矩阵): 186 | def __init__(self, a值): 187 | S矩阵.__init__(self, (2, 2), a值) 188 | @staticmethod 189 | def fc单位(): 190 | return S矩阵2([ 191 | 1, 0, 192 | 0, 1 193 | ]) 194 | @staticmethod 195 | def fc旋转(a): 196 | s = math.sin(a) 197 | c = math.cos(a) 198 | return S矩阵2x2([ 199 | c, s, 200 | s, c 201 | ]) 202 | @staticmethod 203 | def fc缩放(a): 204 | v类型 = a 205 | if v类型 in (tuple, list): 206 | if len(a) != 2: 207 | raise ValueError() 208 | x = a[0] 209 | y = a[1] 210 | raise NotImplementedError() 211 | #=============================================================================== 212 | # 三阶矩阵 213 | #=============================================================================== 214 | class S矩阵3(S矩阵): 215 | def __init__(self, a值): 216 | S矩阵.__init__(self, (3, 3), a值) 217 | @staticmethod 218 | def fc单位(): 219 | return S矩阵3([ 220 | 1, 0, 0, 221 | 0, 1, 0, 222 | 0, 0, 1 223 | ]) 224 | #=============================================================================== 225 | # 四阶矩阵 226 | #=============================================================================== 227 | class S矩阵4(S矩阵): 228 | def __init__(self, a值): 229 | S矩阵.__init__(self, (4, 4), a值) 230 | @staticmethod 231 | def fc单位(): 232 | return S矩阵4([ 233 | 1, 0, 0, 0, 234 | 0, 1, 0, 0, 235 | 0, 0, 1, 0, 236 | 0, 0, 0, 1 237 | ]) -------------------------------------------------------------------------------- /cflw代码库py/cflw数学_随机.py: -------------------------------------------------------------------------------- 1 | import time 2 | import math 3 | import random 4 | from . import cflw数学 as 数学 5 | #=============================================================================== 6 | # 随机数引擎 7 | #=============================================================================== 8 | class I随机数引擎: 9 | def f生成i(self): 10 | '生成一个随机数' 11 | raise NotImplementedError 12 | def f生成f(self): 13 | return self.f生成i() / self.fg最大值() 14 | def fs种子(self): 15 | '设置随机数引擎的种子' 16 | raise NotImplementedError 17 | def f丢弃(self, a次数 = 1): 18 | i = 0 19 | while i < a次数: 20 | self.f生成i() 21 | i += 1 22 | def fs种子(self, a种子): 23 | raise NotImplementedError 24 | def fg最大值(self): 25 | '一个随机数引擎所能生成的最大值' 26 | raise NotImplementedError 27 | def fg状态(self): 28 | "取随机数引擎状态" 29 | raise NotImplementedError 30 | def fs状态(self, a): 31 | "设置状态" 32 | raise NotImplementedError 33 | #具体随机数引擎 34 | class C默认引擎(I随机数引擎): 35 | def __init__(self): 36 | self.m值 = 0 37 | def f生成i(self): 38 | self.m值 = random.random() 39 | return self.m值 40 | def f生成f(self): 41 | self.m值 = random.random() 42 | return self.m值 43 | def fs种子(self, a种子): 44 | random.seed(a种子) 45 | def fg最大值(self): 46 | return 1 47 | def fg状态(self): 48 | return random.getstate() 49 | def fs状态(self, a状态): 50 | random.setstate(a状态) 51 | class C线性同余(I随机数引擎): 52 | c构造参数0 = (16807, 1, 2147483647) 53 | c构造参数1 = (48271, 1, 2147483647) 54 | def __init__(self, a倍数, a加数, a除数): 55 | self.m倍数 = int(a倍数) 56 | self.m加数 = int(a加数) 57 | self.m除数 = int(a除数) 58 | self.m值 = 0 59 | def f生成i(self): 60 | self.m值 = (self.m值 * self.m倍数 + self.m加数) % self.m除数 61 | return self.m值 62 | def fs种子(self, a种子): 63 | self.m值 = int(a种子) % self.m除数 64 | def fg最大值(self): 65 | return self.m除数 66 | class C次数叠加同余(I随机数引擎): 67 | c最大值 = 2 ** 32 - 1 68 | def __init__(self, a余数0, a余数1): 69 | self.m余数0 = a余数0 70 | self.m余数1 = a余数1 71 | self.m次数 = 0 72 | self.m值 = 0 73 | def f生成i(self): 74 | self.m值 = (self.m次数 + 1) * (self.m次数 % self.m余数0 + 1) + self.m值 * (self.m次数 % self.m余数1 + 1) 75 | self.m值 %= C次数叠加同余.c最大值 76 | self.m次数 += 1 77 | return self.m值 78 | def fg状态(self): 79 | return (self.m值, self.m次数) 80 | def fs状态(self, a): 81 | self.m值 = a[0] 82 | self.m次数 = a[1] 83 | def fs种子(self, a种子): 84 | self.m值 = int(a种子) % C次数叠加同余.c最大值 85 | self.m次数 = int(math.log(self.m值)) 86 | def fg最大值(self): 87 | return C次数叠加同余.c最大值 88 | #=============================================================================== 89 | # 随机数分布 90 | #=============================================================================== 91 | class I随机数分布: 92 | def f转换(self, a): 93 | raise NotImplementedError 94 | #具体分布 95 | class C整数区间(I随机数分布): 96 | '得到[a, b)区间内的随机数' 97 | def __init__(self, a最小值, a最大值): 98 | #检查参数合法性 99 | if a最小值 > a最大值: 100 | raise ValueError 101 | #赋初始值 102 | self.m最小值 = int(a最小值) 103 | self.m最大值 = int(a最大值) 104 | def f转换(self, a): 105 | v差 = self.m最大值 - self.m最小值 106 | v余数 = a * v差 107 | return self.m最小值 + int(v余数) 108 | class C实数区间(I随机数分布): 109 | '得到[a, b)区间内的随机数' 110 | def __init__(self, a最小值, a最大值): 111 | #检查参数合法性 112 | if a最小值 > a最大值: 113 | raise ValueError 114 | #赋初始值 115 | self.m最小值 = float(a最小值) 116 | self.m最大值 = float(a最大值) 117 | def f转换(self, a): 118 | v差 = self.m最大值 - self.m最小值 119 | v余数 = a * v差 120 | return self.m最小值 + float(v余数) 121 | class C百分比(I随机数分布): 122 | '0到1' 123 | def f转换(self, a): 124 | return float(a) 125 | class C概率(C百分比): 126 | '有多少的概率得到true' 127 | def __init__(self, a概率): 128 | #检查参数合法性 129 | v概率 = float(a概率) 130 | if v概率 < 0 or v概率 > 1: 131 | raise ValueError 132 | #赋初始值 133 | self.m概率 = v概率 134 | def f转换(self, a): 135 | return float(a) >= self.m概率 136 | class C二项分布(I随机数分布): 137 | '根据次数和成功率得到成功的次数(随机数)' 138 | def __init__(self, a次数, a概率): 139 | #检查参数合法性 140 | v次数 = int(a次数) 141 | if v次数 < 1: 142 | raise ValueError 143 | v概率 = float(a概率) 144 | if v概率 < 0 or v概率 > 1: 145 | raise ValueError 146 | #赋初始值 147 | self.m次数 = v次数 148 | self.m概率 = v概率 149 | def f转换(self, a): 150 | v总概率 = self.m概率 * float(a) 151 | return int(self.m次数 * v总概率) 152 | class C圆形区域(I随机数分布): 153 | def __init__(self, a圆形): 154 | self.m圆形 = a圆形 155 | def f转换(self, a): 156 | v分割 = C分割随机数.f分割2(a) 157 | v大小 = v分割[0] * self.m圆形.m半径 158 | v方向 = v分割[1] * math.pi 159 | return 数学.S向量2.fc方向r(v大小, v方向) 160 | #=============================================================================== 161 | # 随机数工具 162 | #=============================================================================== 163 | #生成种子 164 | class C生成种子: 165 | @staticmethod 166 | def f时间(a最大值): 167 | v当前时间 = time.time() 168 | v小数 = math.modf(v当前时间)[0] 169 | v整数 = math.floor(v小数 * a最大值) 170 | return int(v整数) 171 | #生成随机数 172 | class C生成随机数: 173 | def __init__(self, a0, a1): 174 | #检查参数 175 | if isinstance(a0, I随机数引擎): 176 | if isinstance(a1, I随机数分布): 177 | v引擎 = a0 178 | v分布 = a1 179 | else: 180 | raise TypeError 181 | elif isinstance(a0, I随机数分布): 182 | v分布 = a0 183 | if isinstance(a1, I随机数引擎): 184 | v引擎 = a1 185 | else: 186 | v引擎 = C默认引擎() 187 | #赋初始值 188 | self.m引擎 = v引擎 189 | self.m分布 = v分布 190 | def fs种子(self, a种子 = None): 191 | if a种子 == None: 192 | self.m引擎.fs种子(C生成种子.f时间(self.m最大值)) 193 | else: 194 | self.m引擎.fs种子(a种子) 195 | def f生成(self): 196 | return self.m分布.f转换(self.m引擎.f生成f()) 197 | #随机工具 198 | class C随机工具: 199 | def __init__(self, a引擎): 200 | if not issubclass(a引擎, I随机数引擎): 201 | raise TypeError 202 | self.m引擎 = a引擎 203 | def fs种子(self, a种子 = None): 204 | if a种子 == None: 205 | self.m引擎.fs种子(C生成种子.f时间(self.m最大值)) 206 | else: 207 | self.m引擎.fs种子(a种子) 208 | def f选择(self, a序列): 209 | '和random.choice()相同功能' 210 | v索引 = self.m引擎.f生成i() * len(a序列) / (self.m引擎.fg最大值() + 1) 211 | return a序列[v索引] 212 | class C分割随机数: 213 | @staticmethod 214 | def f分割2(a): 215 | v0 = a 216 | v1 = 1 / a % 1 217 | return (v0, v1) 218 | @staticmethod 219 | def f分割3(a): 220 | v0 = a 221 | v1 = 1 / a % 1 222 | v2 = 1 / v1 % 1 223 | return (v0, v1, v2) 224 | @staticmethod 225 | def f分割n(a, n): 226 | a = [] 227 | v = a 228 | for i in range(n): 229 | a.append(v) 230 | v = 1 / v % 1 231 | return a 232 | def f测试随机质量(a随机数引擎, a次数 = 10000): 233 | d = {} 234 | v和 = 0 235 | v开始时间 = time.time() 236 | for i in range(a次数): 237 | v = a随机数引擎.f生成f() 238 | v和 += v 239 | #结算 240 | v结束时间 = time.time() 241 | d["次数"] = a次数 242 | d["时间"] = v结束时间 - v开始时间 243 | d["平均值"] = v和 / a次数 244 | return d 245 | #=============================================================================== 246 | def main(): 247 | #v引擎 = C次数叠加同余(16807, 48271) 248 | #v引擎 = C线性同余(*C线性同余.c构造参数0) 249 | v引擎 = C默认引擎() 250 | v引擎.fs种子(time.time()) 251 | for i in range(10): 252 | d = f测试随机质量(v引擎, 100000) 253 | print(d) 254 | if __name__ == "__main__": 255 | main() -------------------------------------------------------------------------------- /cflw代码库py/cflw时间.py: -------------------------------------------------------------------------------- 1 | import time 2 | import datetime 3 | import math 4 | c元 = datetime.datetime.strptime("","") #计算机可记录的首个日期 5 | c元年 = datetime.timedelta(days = c元.year * 365.25) #以公元为参考 6 | #=============================================================================== 7 | # 计算间隔的秒表 8 | #=============================================================================== 9 | class C秒表: 10 | "计算开始到滴答的时间。单位:秒" 11 | def __init__(self): 12 | self.f重置() 13 | def f重置(self): 14 | "时间清零" 15 | self.m时间 = time.time() 16 | def f滴答(self): 17 | "返回经过的时间" 18 | v当前时间 = time.time() 19 | return v当前时间 - self.m时间 20 | class C计时器: 21 | "滴答一段时间后返回true,并重新计时" 22 | def __init__(self, a时间 = 1, a等待 = True): 23 | self.f重置(a时间) 24 | self.fs等待(a等待) 25 | def f重置(self, a时间): 26 | self.m滴答时间 = float(a时间) 27 | self.m累积时间 = 0.0 28 | self.m上次时间 = time.time() 29 | def fs等待(self, a): 30 | if type(a) == bool: 31 | if a: 32 | self.m等待时间 = math.sqrt(self.m滴答时间) / 100.0 33 | else: 34 | self.m等待时间 = 0.0 35 | else: 36 | self.m等待时间 = float(a) 37 | def f滴答(self): 38 | v这次时间 = time.time() 39 | self.m累积时间 += v这次时间 - self.m上次时间 40 | self.m上次时间 = v这次时间 41 | v超过 = False 42 | if self.m累积时间 >= self.m滴答时间: 43 | if self.m累积时间 >= self.m滴答时间 * 2: 44 | self.m累积时间 = 0 #防止程序卡住使累积时间太大,导致计时器短时间内多次滴答 45 | else: 46 | self.m累积时间 -= self.m滴答时间 47 | v超过 = True 48 | if self.m等待时间 > 0: 49 | time.sleep(self.m等待时间) 50 | return v超过 51 | #=============================================================================== 52 | # 阻塞 53 | #=============================================================================== 54 | class C未来阻塞: 55 | '一开始确定一个时间并开始计时,滴答时阻塞,直到指定时间结束' 56 | def __init__(self, a时间 = 1): 57 | self.m秒表 = C秒表() 58 | self.f重置(a时间) 59 | def f重置(self, a时间): 60 | self.m等待时间 = float(a时间) 61 | self.m间隔 = self.m时间 / 10.0 62 | self.m秒表.f重置() 63 | def f滴答(self): 64 | while True: 65 | if self.m秒表.f滴答() < self.m等待时间: 66 | time.sleep(self.m间隔) 67 | else: 68 | break 69 | class C循环阻塞: 70 | '用在循环语句的条件中,自动阻塞一段时间,到时间返回False跳出循环' 71 | def __init__(self, a时间 = 1.0, a次数 = None, a间隔 = None): #次数只是用来计算时间间隔,实际循环次数可能比指定次数少 72 | self.m秒表 = C秒表() 73 | self.m时间 = a时间 74 | if a次数: 75 | self.m间隔 = a时间 / float(a次数) 76 | elif a间隔: 77 | self.m间隔 = a间隔 78 | else: 79 | self.m间隔 = 0.1 80 | self.m开始 = True 81 | def f滴答(self): 82 | if self.m开始: #第1次总是进入循环 83 | self.m开始 = False 84 | return True 85 | if self.m秒表.f滴答() < self.m时间: 86 | time.sleep(self.m间隔) 87 | return True 88 | else: 89 | return False 90 | #=============================================================================== 91 | # 格式化字符串 92 | #=============================================================================== 93 | class C时间转字符串: 94 | c日期时间全数字 = '%Y%m%d%H%M%S' 95 | c日期时间中文 = '%Y年%m月%d日%H时%M分%S秒' 96 | c日期全数字 = '%Y%m%d' 97 | c时间全数字 = '%H%M%S' 98 | @staticmethod 99 | def f取时间(a时间): 100 | if a时间: 101 | return a时间 102 | else: #空的,取现在时间 103 | return time.localtime() 104 | @staticmethod 105 | def f转换(a格式, a时间 = None): 106 | v时间 = C时间转字符串.f取时间(a时间) 107 | return time.strftime(a格式, v时间) 108 | @staticmethod 109 | def f日期时间全数字(a时间 = None): 110 | return C时间转字符串.f转换(C时间转字符串.c日期时间全数字, a时间) 111 | @staticmethod 112 | def f日期时间中文(a时间 = None): 113 | return C时间转字符串.f转换(C时间转字符串.c日期时间中文, a时间) 114 | @staticmethod 115 | def f日期全数字(a时间 = None): 116 | return C时间转字符串.f转换(C时间转字符串.c日期全数字, a时间) 117 | @staticmethod 118 | def f时间全数字(a时间 = None): 119 | return C时间转字符串.f转换(C时间转字符串.c时间全数字, a时间) 120 | @staticmethod 121 | def f日期分隔(a时间, a分隔符): 122 | pass 123 | #=============================================================================== 124 | # 字符串转时间 125 | #=============================================================================== 126 | class C字符串转时间: 127 | @staticmethod 128 | def f时间(a): 129 | v数量 = a.count(":") 130 | if v数量 == 0: #时 131 | return time.strptime(a, "%H") 132 | if v数量 == 1: #时:分 133 | return time.strptime(a, "%H:%M") 134 | if v数量 == 2: #时:分:秒 135 | return time.strptime(a, "%H:%M:%S") 136 | raise ValueError 137 | class C字符串转时间差: 138 | @staticmethod 139 | def f字符串格式(a字符串, a格式): 140 | v原始 = datetime.datetime.strptime(a字符串, a格式) 141 | v差 = v原始 - c元 142 | if "%Y" in a格式 or "%y" in a格式: #格式里是否带有年 143 | return v差 + c元年 144 | else: 145 | return v差 146 | @staticmethod 147 | def f时间(a): 148 | v元组 = a.split(":") 149 | v数量 = len(v数量) 150 | v字典 = {} 151 | if v数量 >= 1: 152 | v字典["hours"] = float(v元组[0]) 153 | if v数量 >= 2: 154 | v字典["minutes"] = float(v元组[1]) 155 | if v数量 >= 3: 156 | v字典["seconds"] = float(v元组[2]) 157 | if v数量 >= 4: 158 | raise ValueError 159 | return datetime.timedelta(**v字典) 160 | def strptimedelta(str, format): 161 | return C字符串转时间差.f字符串格式(str, format) 162 | #=============================================================================== 163 | # 时区 164 | #=============================================================================== 165 | class S时区: 166 | def __init__(self, a名称, a秒): 167 | self.m名称 = a名称 168 | self.m秒 = a秒 169 | @staticmethod 170 | def fc系统时区(): 171 | v时区名 = time.tzname[0].encode("latin-1").decode("gbk") 172 | v秒 = -time.timezone 173 | return S时区(v时区名, v秒) 174 | def fg时(self): 175 | return f总秒取时(self.m秒) 176 | def fg分(self): 177 | return f总秒取分(self.m秒) 178 | def fg秒(self): 179 | return f总秒取秒(self.m秒) 180 | def fg时分秒(self): 181 | return f总秒拆成时分秒(self.m秒) 182 | def fg标准时区缩写(self): 183 | return "GMT+" + str(self.fg时()) 184 | def ft标准库时区(self): 185 | "转datetime.timezone" 186 | return datetime.timezone(datetime.timedelta(seconds = self.m秒), self.fg标准时区缩写()) 187 | #c北京时间 = S时区("beijing", 26600) 188 | #=============================================================================== 189 | # 时间计算 190 | #=============================================================================== 191 | def f总秒取时(a秒): 192 | return math.floor(a秒 // 3600) 193 | def f总秒取分(a秒): 194 | return math.floor(a秒 % 3600 // 60) 195 | def f总秒取秒(a秒): 196 | return math.floor(a秒 % 60) 197 | def f总秒拆成时分秒(a秒): 198 | v时 = f总秒取时(a秒) 199 | v分 = f总秒取分(a秒) 200 | v秒 = f总秒取秒(a秒) 201 | return (v时, v分, v秒) 202 | def f总秒拆成分秒(a秒): 203 | v分 = a秒 // 60 204 | v秒 = a秒 % 60 205 | return (v分, v秒) 206 | #=============================================================================== 207 | # 日期 208 | #=============================================================================== 209 | c每月日数 = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) 210 | c每月日数_闰年 = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) 211 | def fi闰年(a年): 212 | v年 = int(a年) 213 | if v年 % 400: 214 | return True 215 | return (v年 % 4) and (not v年 % 100) 216 | def fe全年月日(ai闰年 = False): 217 | """(1,1)到(12,31)""" 218 | v月 = 1 219 | v每月日数 = c每月日数_闰年 if ai闰年 else c每月日数 220 | for v当月日数 in v每月日数: 221 | for v日 in range(1, v当月日数 + 1): 222 | yield v月, v日 223 | v月 += 1 224 | -------------------------------------------------------------------------------- /cflw代码库py/cflw爬虫.py: -------------------------------------------------------------------------------- 1 | import re 2 | from bs4 import BeautifulSoup #beautifulsoup4 3 | import requests #requests 4 | c超文本传输协议错误正则表达式 = re.compile(r"\d\d\d") 5 | def fc解析器bs(a文本): 6 | return BeautifulSoup(a文本, "html.parser") 7 | def f获取文档(a地址, a请求头 = None, a失败重试次数 = 5): 8 | e = RuntimeError("失败重试次数过多") 9 | for i in range(a失败重试次数): 10 | try: 11 | v请求 = requests.get(url = a地址, headers = a请求头) 12 | v请求.encoding = v请求.apparent_encoding 13 | v页面 = v请求.text 14 | if f检测超文本传输协议错误(v页面): 15 | raise RuntimeError() 16 | return v页面 17 | except Exception as e: 18 | continue #重试 19 | raise e 20 | def f检测超文本传输协议错误(a文档)->int: 21 | if len(a文档) > 1000: #大文档应该没问题 22 | return 0 23 | v匹配结果 = c超文本传输协议错误正则表达式.search(a文档) 24 | if v匹配结果: 25 | return int(v匹配结果.group(0)) 26 | return 0 #没错误返回0 27 | class I文档: 28 | def __init__(self): 29 | self.m文档 = None 30 | def f重新载入(self): 31 | self.m文档 = fc解析器bs(f获取文档(self.fg地址())) 32 | def f载入(self): 33 | if not self.m文档: 34 | self.f重新载入() 35 | def fg地址(self): 36 | raise NotImplementedError() -------------------------------------------------------------------------------- /cflw代码库py/cflw爬虫_代理列表.py: -------------------------------------------------------------------------------- 1 | from . import cflw爬虫 as 爬虫 2 | c地址 = "http://www.xicidaili.com/nn/" 3 | c请求头 = { 4 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", 5 | "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", 6 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0", 7 | } 8 | def f获取文档(): 9 | return 爬虫.f获取文档(c地址, a请求头 = c请求头) 10 | def f解析列_字符串(a元素): 11 | return a元素.get_text().strip() 12 | def f解析列_国家(a元素): 13 | v元素 = a元素.find("img") 14 | if v元素: 15 | return v元素.get("src")[-6:-4] 16 | else: 17 | return "" 18 | def f解析列_延迟时间(a元素): 19 | v元素 = a元素.find("div", class_ = "bar") 20 | return float(v元素.get("title")[:-1]) 21 | def F解析列_转换(a类型): 22 | def f(a元素): 23 | return a类型(f解析列_字符串(a元素)) 24 | return f 25 | ca不处理列 = (f解析列_字符串,) * 10 26 | ca处理列 = (f解析列_国家, f解析列_字符串, F解析列_转换(int), f解析列_字符串, f解析列_字符串, f解析列_字符串, f解析列_延迟时间, f解析列_延迟时间, f解析列_字符串, f解析列_字符串) 27 | def f解析文档(a文档): 28 | v文档 = 爬虫.fc解析器bs(a文档) 29 | v表格 = v文档.find("table", id = "ip_list") 30 | va = [] 31 | for v行 in v表格.find_all("tr"): 32 | #取列 33 | def fe列(): 34 | i = 0 35 | for v列 in v行.children: 36 | if i % 2 != 0: 37 | yield v列 38 | i += 1 39 | va列 = [v列 for v列 in fe列()] 40 | #处理列 41 | va新列 = [] 42 | va处理列 = ca处理列 if va else ca不处理列 #第1行是标题行时,不处理 43 | for v列, vf in zip(va列, va处理列): 44 | va新列.append(vf(v列)) 45 | #添加行 46 | va.append(va新列) 47 | return va 48 | def f一键获取列表(): 49 | return f解析文档(f获取文档()) 50 | -------------------------------------------------------------------------------- /cflw代码库py/cflw简单网管.py: -------------------------------------------------------------------------------- 1 | import functools 2 | #=============================================================================== 3 | # 接口 4 | #=============================================================================== 5 | class I简单网管: 6 | def f获取(self, a标识): 7 | """snmpget""" 8 | raise NotImplementedError() 9 | def f遍历(self, a开始, a结束): 10 | """snmpwalk""" 11 | raise NotImplementedError() 12 | def f设置(self, a标识, a值): 13 | """snmpset""" 14 | raise NotImplementedError() 15 | def f陷阱(self, a标识): 16 | """snmptrap""" 17 | raise NotImplementedError() 18 | #=============================================================================== 19 | # 结构 20 | #=============================================================================== 21 | @functools.total_ordering 22 | class S对象标识符: 23 | def __init__(self, aa值): 24 | self.ma值 = list(aa值) 25 | def __eq__(self, a): 26 | return self.ma值 == a 27 | def __lt__(self, a): 28 | return self.ma值 < a 29 | def __len__(self): 30 | return len(self.ma值) 31 | def __getitem__(self, k): 32 | return self.ma值[k] 33 | def __setitem__(self, k, v): 34 | self.ma值[k] = v 35 | def __str__(self): 36 | return "." + ".".join(map(str, self.ma值)) 37 | @staticmethod 38 | def fc自动(*a): 39 | v长度 = len(a) 40 | if v长度 > 1: #视为多个值 41 | return S对象标识符.fc值(*a) 42 | v = a[0] 43 | v类型 = type(v) 44 | if v类型 == str: 45 | return S对象标识符.fc字符串(v) 46 | elif v类型 in (tuple, list): 47 | return S对象标识符.fc值(*v) 48 | elif v类型 == S对象标识符: 49 | return v 50 | else: 51 | raise TypeError("无法解析的类型") 52 | @staticmethod 53 | def fc值(*aa值): 54 | return S对象标识符(aa值) 55 | @staticmethod 56 | def fc字符串(a: str): 57 | if a[0] == '.': 58 | return S对象标识符(map(int, a[1:].split("."))) 59 | else: 60 | return S对象标识符(map(int, a.split("."))) 61 | def f添加(self, a值): 62 | return S对象标识符(self.ma值 + [a值]) 63 | def f删除末尾(self): 64 | return S对象标识符(self.ma值[:-1]) 65 | def f末尾加一(self): 66 | return S对象标识符(self.ma值[:-1] + [self.ma值[-1] + 1]) -------------------------------------------------------------------------------- /cflw代码库py/cflw简单网管_标识.py: -------------------------------------------------------------------------------- 1 | #=============================================================================== 2 | # 常见的对象标识符 3 | #=============================================================================== 4 | sysName = "1.3.6.1.2.1.1.5" 5 | sysDescr = "1.3.6.1.2.1.1.1" 6 | ifNumber = "1.3.6.1.2.1.2.1" 7 | ifDescr = "1.3.6.1.2.1.2.2.1.2" 8 | ifInOctet = "1.3.6.1.2.1.2.2.1.10" 9 | ifOutOctet = "1.3.6.1.2.1.2.2.1.16" 10 | ifInUcastPkts = "1.3.6.1.2.1.2.2.1.11" 11 | ifOutUcastPkts = "1.3.6.1.2.1.2.2.1.17" 12 | ipNetToMediaPhysAddress = "1.3.6.1.2.1.4.22.1.2" 13 | ipOperStatus = "1.3.6.1.2.1.2.2.1.8" 14 | -------------------------------------------------------------------------------- /cflw代码库py/cflw简单网管_派.py: -------------------------------------------------------------------------------- 1 | import pysnmp.hlapi as 接口 #pysnmp 2 | import pysnmp.proto.rfc1902 as 类型 3 | import pysnmp.proto.rfc1905 as rfc1905 4 | from . import cflw简单网管 as 简单网管 5 | #=============================================================================== 6 | # 工具 7 | #=============================================================================== 8 | def fc对象标识符(a标识, a值 = rfc1905.unSpecified): 9 | return 接口.ObjectType(接口.ObjectIdentity(str(a标识)), a值) 10 | def fc通知标识符(a标识, aa值 = {}): 11 | return 接口.NotificationType(接口.objectIdentity(a标识), aa值.keys(), aa值) 12 | def ft自动(a绑定变量1): 13 | """自动转换成python内置类型""" 14 | v类型 = type(a绑定变量1) 15 | if v类型 in (类型.OctetString, 类型.OctetString): #八进制字符串 16 | return str(a绑定变量1) 17 | elif v类型 in (类型.Integer, 类型.Integer32, 类型.Counter32, 类型.Counter64, 类型.Unsigned32, 类型.Gauge32): #整数 18 | return int(a绑定变量1) 19 | elif v类型 == 类型.IpAddress: #网络地址4 20 | return bytes(a绑定变量1) 21 | elif v类型 == 类型.Null: #空 22 | return None 23 | else: #默认处理 24 | return str(a绑定变量1) 25 | def ft类型(at类型, a绑定变量1): 26 | if at类型: 27 | return at类型(a绑定变量1) 28 | return ft自动(a绑定变量1) 29 | def Ft类型(at类型): 30 | if at类型: 31 | return at类型 32 | return ft自动 33 | def fg对象标识符(a绑定变量0): 34 | return 简单网管.S对象标识符.fc字符串(str(a绑定变量0)) 35 | #=============================================================================== 36 | # 连接 37 | #=============================================================================== 38 | class C简单网管(简单网管.I简单网管): 39 | c连接特性 = 0x0004 40 | def __init__(self, a主机, a团体字 = "public", a版本 = 2, a端口号 = 161): 41 | self.m目标 = 接口.UdpTransportTarget((a主机, a端口号)) 42 | v模型 = 1 if a版本 == 2 else 0 #版本 43 | self.m团体字 = 接口.CommunityData(a团体字, mpModel = v模型) 44 | self.m版本 = a版本 45 | self.m引擎 = 接口.SnmpEngine() 46 | self.m上下文 = 接口.ContextData() 47 | def fc命令(self, af命令, a标识, a值 = rfc1905.unSpecified): 48 | v标识 = fc对象标识符(a标识, a值) 49 | v命令 = af命令(self.m引擎, self.m团体字, self.m目标, self.m上下文, v标识) 50 | return v命令 51 | def fc通知(self, af通知, a标识, aa值 = {}): 52 | v标识 = fc通知标识符(a标识, a值) 53 | v通知 = af通知(self.m引擎, self.m团体字, self.m目标, self.m上下文, "trap", v标识) 54 | return v通知 55 | def f获取(self, a标识, at类型 = ft自动): 56 | v命令 = self.fc命令(接口.getCmd, a标识) 57 | v错误指示, v错误状态, v错误索引, va绑定变量 = next(v命令) 58 | return ft类型(at类型, va绑定变量[0][1]) 59 | def f遍历(self, a开始, a结束 = None, at类型 = ft自动): 60 | v开始 = 简单网管.S对象标识符.fc自动(a开始) 61 | v命令 = self.fc命令(接口.nextCmd, v开始) 62 | v结束 = 简单网管.S对象标识符.fc自动(a结束) if a结束 else v开始.f末尾加一() 63 | vt类型 = Ft类型(at类型) 64 | for v错误指示, v错误状态, v错误索引, va绑定变量 in v命令: #下一个标识只有获取了才知道,所以结束了也要再获取一次 65 | v绑定变量 = va绑定变量[0] 66 | v当前 = fg对象标识符(v绑定变量[0]) 67 | if v当前 >= v结束: 68 | break 69 | yield vt类型(v绑定变量[1]) 70 | def f设置(self, a标识, a值, at类型 = ft自动): 71 | v命令 = self.fc命令(接口.setCmd, a标识, a值) 72 | v错误指示, v错误状态, v错误索引, va绑定变量 = next(v命令) 73 | return ft类型(at类型, va绑定变量[0][1]) 74 | def f陷阱(self, a标识, a值, at类型 = ft自动): 75 | v通知 = self.fc通知(接口.sendNotification, a标识, a值) 76 | v错误指示, v错误状态, v错误索引, va绑定变量 = next(v通知) 77 | return ft类型(at类型, va绑定变量[0][1]) -------------------------------------------------------------------------------- /cflw代码库py/cflw类型.py: -------------------------------------------------------------------------------- 1 | #=============================================================================== 2 | # 类型判断 3 | #=============================================================================== 4 | def fi类型(a): 5 | return a == type 6 | def fi整数(a): 7 | return type(a) == int 8 | def fi浮点数(a): 9 | return type(a) == float 10 | def fi字符串(a): 11 | return type(a) == str 12 | def fi函数(a): 13 | return hasattr(a, "__call__") 14 | def fi迭代(a): 15 | return hasattr(a, "__iter__") -------------------------------------------------------------------------------- /cflw代码库py/cflw网络地址.py: -------------------------------------------------------------------------------- 1 | import ipaddress 2 | import re 3 | import struct 4 | import math 5 | from typing import * 6 | from . import cflw字符串 as 字符串 7 | #=============================================================================== 8 | # 常量 9 | #=============================================================================== 10 | c网络地址4正则 = re.compile(r"(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}") 11 | c网络地址6正则 = re.compile(r"([a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,7}::[a-f0-9]{0,4}(:[a-f0-9]{1,4}){0,7})") 12 | c前缀正则 = re.compile(r"\/\d{1,3}\s") 13 | #=============================================================================== 14 | # 创建地址对象 15 | #=============================================================================== 16 | def f解析地址字符串(a地址: str, a严格: bool = True): #返回地址或网络号对象 17 | if '/' in a地址: 18 | return ipaddress.IPv4Network(a地址, a严格) 19 | elif '-' in a地址: 20 | return C连续地址4(a地址) 21 | else: 22 | return ipaddress.IPv4Address(a地址) 23 | class C互联网协议4: 24 | "静态类,对ipaddress模块的完善" 25 | @staticmethod 26 | def fc网络(a地址, a严格: bool = True): 27 | v类型 = type(a地址) 28 | if v类型 == ipaddress.IPv4Network: 29 | return a地址 30 | elif v类型 == tuple: 31 | return ipaddress.IPv4Network('%s/%s' % a地址[0:2], a严格) 32 | elif v类型 == list: 33 | return ipaddress.IPv4Network('%s/%s' % tuple(a地址[0:2]), a严格) 34 | elif v类型 == str: 35 | return ipaddress.IPv4Network(a地址, a严格) 36 | elif hasattr(v类型, '__str__'): 37 | return ipaddress.IPv4Network(str(a地址), a严格) 38 | else: 39 | raise TypeError() 40 | @staticmethod 41 | def fc接口(a地址): 42 | v类型 = type(a地址) 43 | if v类型 == ipaddress.IPv4Interface: 44 | return a地址 45 | elif v类型 == tuple: 46 | return ipaddress.IPv4Interface('%s/%s' % a地址[0:2]) 47 | elif v类型 == list: 48 | return ipaddress.IPv4Interface('%s/%s' % tuple(a地址[0:2])) 49 | elif v类型 == str: 50 | return ipaddress.IPv4Interface(a地址) 51 | elif hasattr(v类型, '__str__'): 52 | return ipaddress.IPv4Interface(str(a地址)) 53 | else: 54 | raise TypeError() 55 | @staticmethod 56 | def fc掩码_长度(a长度): 57 | return ipaddress.IPv4Address(2 ** 32 - 2 ** (32 - a长度)) 58 | @staticmethod 59 | def fc反掩码_长度(a长度): 60 | return ipaddress.IPv4Address(2 ** (32 - a长度) - 1) 61 | @staticmethod 62 | def f补全地址(a完整地址: str, a空缺地址: str): 63 | '''使用完整地址的前缀来填补空缺地址的前缀 64 | 例如:有2个地址"192.168.0.1"、"2",可以把第2个地址补为"192.168.0.2"''' 65 | v地址0 = a完整地址.split('.') 66 | v地址1 = a空缺地址.split('.') 67 | while True: 68 | v数量 = len(v地址1) 69 | assert(v数量 <= 4) 70 | if v地址1[0] == '': 71 | v地址1[0] = v地址0[4 - v数量] 72 | if v数量 == 4: 73 | break 74 | else: 75 | v地址1.insert(0, v地址0[3 - v数量]) 76 | return '%s.%s.%s.%s' % tuple(v地址1) 77 | @staticmethod 78 | def f分割地址掩码(a地址): 79 | v类型 = type(a地址) 80 | if v类型 in (ipaddress.IPv4Network, ipaddress.IPv4Interface): 81 | return a地址.with_netmask.split('/') 82 | else: 83 | raise TypeError() 84 | @staticmethod 85 | def f分割地址反掩码(a地址): 86 | v类型 = type(a地址) 87 | if v类型 in (ipaddress.IPv4Network, ipaddress.IPv4Interface): 88 | v反掩码 = C互联网协议4.fc反掩码_长度(a地址.prefixlen) 89 | return (a地址.network_address, v反掩码) 90 | else: 91 | raise TypeError() 92 | @staticmethod 93 | def f互补(a地址): 94 | v类型 = type(a地址) 95 | if v类型 == ipaddress.IPv4Address: 96 | v地址 = a地址 97 | elif v类型 in (ipaddress.IPv4Network, ipaddress.IPv4Interface): 98 | v地址 = a地址.network_address 99 | else: 100 | raise TypeError() 101 | v整数 = 2 ** 32 - 1 - int(v地址) 102 | return ipaddress.IPv4Address(v整数) 103 | #=============================================================================== 104 | # 网络地址4 105 | #=============================================================================== 106 | class S网络地址4: 107 | "ipv4地址结构" 108 | c最大前缀长度 = 32 109 | c全f = 0xffffffff 110 | def __init__(self, a地址: int = 0, a前缀长度: int = 0): 111 | self.m地址 = a地址 112 | self.m前缀长度 = a前缀长度 113 | def __str__(self): 114 | return self.ft字符串() 115 | def __add__(self, a): #地址加 116 | v类型 = type(a) 117 | if v类型 == int: 118 | return S网络地址4(self.m地址 + a, self.m前缀长度) 119 | raise TypeError("不支持的类型") 120 | def __sub__(self, a): #地址减 121 | v类型 = type(a) 122 | if v类型 == int: 123 | return S网络地址4(self.m地址 - a, self.m前缀长度) 124 | raise TypeError("不支持的类型") 125 | def __getitem__(self, a): 126 | """按索引获取当前网段地址, 0是网络号, -1是广播地址""" 127 | v类型 = type(a) 128 | if v类型 == int: 129 | if a >= 0: 130 | return S网络地址4(self.fg网络号i() + a, self.m前缀长度) 131 | else: #负数,从后面开始 132 | return S网络地址4(self.fg广播地址i() + a + 1, self.m前缀长度) 133 | raise TypeError("不支持的类型") 134 | @staticmethod 135 | def fc自动(*a): 136 | """ 137 | 可用字符串格式:x.x.x.x/n 138 | 例如:"1.1.1.1/24" 139 | 可用的其它类型:ipaddress模块中的ipv4相关类\n 140 | 可用的多参数:(地址, 掩码) 141 | """ 142 | v长度 = len(a) 143 | if v长度 > 1: 144 | v1 = a[1] 145 | else: 146 | v1 = 32 147 | v0 = a[0] 148 | v类型0 = type(v0) 149 | if v类型0 == S网络地址4: #参数类型(S网络地址4) 150 | if v长度 > 1: 151 | raise TypeError("参数太多") 152 | return S网络地址4(v0.m地址, v0.m前缀长度) 153 | elif v类型0 == str: 154 | #取参数 155 | if "/" in v0: 156 | v地址0, v1 = v0.split("/") 157 | if "." in v1: 158 | return S网络地址4.fc地址掩码(v地址0, v1) #格式: x.x.x.x/x.x.x.x 159 | else: 160 | return S网络地址4.fc地址前缀长度(v地址0, v1) #格式: x.x.x.x/n 161 | else: 162 | v地址0 = v0 163 | #赋值 164 | if type(v1) == str: 165 | v前缀长度 = S网络地址4.f掩码字符串转前缀长度(v1) 166 | else: 167 | v前缀长度 = int(v1) 168 | v地址 = S网络地址4.f地址字符串转整数(v地址0) 169 | return S网络地址4(v地址, v前缀长度) 170 | elif v类型0 == int: #地址是整数 171 | v前缀长度 = S网络地址4.f掩码字符串转前缀长度(v1) 172 | return S网络地址4(v0, v前缀长度) 173 | elif v类型0 in (ipaddress.IPv4Network, ipaddress.IPv4Interface): 174 | v地址, v前缀长度 = v0.with_prefixlen.split("/") 175 | return S网络地址4.fc地址前缀长度(v地址, v前缀长度) 176 | elif v类型0 == ipaddress.IPv4Address: 177 | v地址 = int(v0) 178 | return S网络地址4(v地址, v1) 179 | elif v0 == None: 180 | return S网络地址4(0, 0) 181 | else: 182 | raise TypeError("无法解析参数类型") 183 | @staticmethod 184 | def fc字符串(a地址: str): 185 | """尝试从多种格式中解析字符串""" 186 | if "/" in a地址: #x.x.x.x/n 187 | return S网络地址4.fc地址前缀长度字符串(a地址) 188 | v点数 = a地址.count(".") 189 | if " " in a地址 and v点数 == 6: #x.x.x.x m.m.m.m 190 | return S网络地址4.fc地址空格掩码字符串(a地址) 191 | #x.x.x.x 192 | return S网络地址4.fc主机地址字符串(a地址) 193 | @staticmethod 194 | def fc主机地址字符串(a地址: str): 195 | """格式: x.x.x.x""" 196 | v地址 = S网络地址4.f地址字符串转整数(a地址) 197 | return S网络地址4(v地址, 32) 198 | @staticmethod 199 | def fc地址前缀长度字符串(a地址: str): 200 | """格式: x.x.x.x/n""" 201 | v地址s, v长度s = a地址.split("/") 202 | v地址 = S网络地址4.f地址字符串转整数(v地址s) 203 | v长度 = int(v长度s) 204 | return S网络地址4(v地址, v长度) 205 | @staticmethod 206 | def fc地址空格掩码字符串(a地址: str): 207 | """格式: x.x.x.x m.m.m.m""" 208 | v地址s, v掩码s = a地址.split() 209 | v地址 = S网络地址4.f地址字符串转整数(v地址s) 210 | v长度 = S网络地址4.f掩码字符串转前缀长度(v掩码s) 211 | return S网络地址4(v地址, v长度) 212 | @staticmethod 213 | def fc地址前缀长度(a地址: Any, a前缀长度: int): 214 | if type(a地址) == str: 215 | v地址 = S网络地址4.f地址字符串转整数(a地址) 216 | else: 217 | v地址 = int(a地址) 218 | v前缀长度 = int(a前缀长度) 219 | return S网络地址4(v地址, v前缀长度) 220 | @staticmethod 221 | def fc地址掩码(a地址: Any, a掩码: Any): 222 | #地址 223 | v地址类型 = type(a地址) 224 | if v地址类型 == str: 225 | v地址 = S网络地址4.f地址字符串转整数(a地址) 226 | elif v地址类型 in (bytes, bytearray): 227 | v地址 = int.from_bytes(a地址, byteorder = "big", signed = False) 228 | else: 229 | v地址 = int(a地址) 230 | #掩码 231 | v掩码类型 = type(a掩码) 232 | if v掩码类型 == str: 233 | v前缀长度 = S网络地址4.f掩码字符串转前缀长度(a掩码) 234 | elif v掩码类型 in (bytes, bytearray): 235 | v前缀长度 = S网络地址4.f掩码整数转前缀长度(int.from_bytes(a掩码, byteorder = "big", signed = False)) 236 | else: 237 | v前缀长度 = S网络地址4.f掩码整数转前缀长度(int(a掩码)) 238 | return S网络地址4(v地址, v前缀长度) 239 | @staticmethod 240 | def fc四段(a0, a1, a2, a3, a前缀长度: int = 32): 241 | v整数 = S网络地址4.f四段转整数(a0, a1, a2, a3) 242 | return S网络地址4(v整数, a前缀长度) 243 | @staticmethod 244 | def f地址字符串转整数(a: str)->int: 245 | "x.x.x.x转32位整数" 246 | assert(type(a) == str) 247 | if a.count(".") != 3: 248 | raise ValueError() 249 | v = a.split(".") 250 | return S网络地址4.f四段转整数(v[0], v[1], v[2], v[3]) 251 | @staticmethod 252 | def f四段转整数(a0, a1, a2, a3)->int: 253 | "(a, b, c, d)转32位整数" 254 | def f(a): 255 | v = int(a) 256 | if v < 0 or v > 0xff: 257 | raise ValueError("数字超出范围0~255") 258 | return v 259 | return f(a0) * 2 ** 24 + f(a1) * 2 ** 16 + f(a2) * 2 ** 8 + f(a3) 260 | @staticmethod 261 | def f掩码字符串转前缀长度(a: str)->int: 262 | "处理正掩码,反掩码,前缀长度3种格式" 263 | if "." in a: 264 | v整数 = S网络地址4.f地址字符串转整数(a) 265 | if v整数 == 0: #全0 266 | return 0 267 | #1..0 268 | if v整数 & 0x80000000: 269 | v整数 = S网络地址4.c全f - v整数 270 | #0..1 271 | elif v整数 & 0x00000001: 272 | pass 273 | else: #未知格式 274 | v整数 = 0 275 | return 32 - int(math.log2(v整数 + 1)) 276 | else: 277 | return int(a) 278 | @staticmethod 279 | def f正掩码字符串转前缀长度(a: str)->int: 280 | """处理正掩码,已知掩码类型时可以减少判断""" 281 | v整数 = S网络地址4.f地址字符串转整数(a) 282 | if v整数 == 0: #全0 283 | return 0 284 | return 32 - int(math.log2(S网络地址4.c全f - v整数 + 1)) 285 | @staticmethod 286 | def f反掩码字符串转前缀长度(a: str)->int: 287 | """处理反掩码,已知掩码类型时可以减少判断""" 288 | v整数 = S网络地址4.f地址字符串转整数(a) 289 | if v整数 == 0: #全0 290 | return 32 291 | return 31 - int(math.log2(v整数)) 292 | @staticmethod 293 | def f掩码整数转前缀长度(a: int)->int: 294 | "参数必需是正掩码或前缀长度" 295 | if a > 32: 296 | return int(32 - math.log2(S网络地址4.c全f - a + 1)) 297 | else: 298 | return a 299 | @staticmethod 300 | def f字节转整数(a: bytes)->int: 301 | return int.from_bytes(a, byteorder = "big", signed = False) 302 | @staticmethod 303 | def f地址整数转字符串(a: int)->str: 304 | if type(a) != int: 305 | raise TypeError("参数必需是整数") 306 | va = ["0", "0", "0", "0"] 307 | v数字 = a 308 | for i in range(4): #数字转字符串后需要反转 309 | va[i] = str(v数字 % 256) 310 | v数字 //= 256 311 | va.reverse() 312 | return ".".join(va) 313 | @staticmethod 314 | def f地址整数转元组(a: int): 315 | if type(a) != int: 316 | raise TypeError("参数必需是整数") 317 | va = [0, 0, 0, 0] 318 | v数字 = a 319 | for i in range(4): #数字转字符串后需要反转 320 | va[i] = v数字 % 256 321 | v数字 //= 256 322 | va.reverse() 323 | return tuple(va) 324 | @staticmethod 325 | def fi地址格式(a): 326 | v类型 = type(a) 327 | if v类型 == str: 328 | v点数 = a.count(".") 329 | if v点数 != 3: 330 | return False 331 | va列表 = a.split(".") 332 | try: 333 | for v in va列表: 334 | v数字 = int(v) 335 | if v数字 > 255: 336 | return False 337 | except: 338 | return False 339 | #没问题 340 | return True 341 | elif v类型 in (S网络地址4, ipaddress.IPv4Address, ipaddress.IPv4Interface, ipaddress.IPv4Network): 342 | return True 343 | else: 344 | return False 345 | def fg地址s(self): 346 | """返回"x.x.x.x" """ 347 | return S网络地址4.f地址整数转字符串(self.fg地址i()) 348 | def fg地址i(self): 349 | """返回整数""" 350 | return self.m地址 351 | def fg地址t(self): 352 | """返回(x.x.x.x)""" 353 | return S网络地址4.f地址整数转元组(self.fg地址i()) 354 | def fg网络号(self): 355 | """返回地址""" 356 | v地址 = self.fg网络号i() 357 | return S网络地址4(v地址, self.m前缀长度) 358 | def fg网络号s(self): 359 | """返回"x.x.x.x" """ 360 | return S网络地址4.f地址整数转字符串(self.fg网络号i()) 361 | def fg网络号i(self): 362 | """返回整数""" 363 | return self.m地址 & self.fg掩码i() 364 | def fg广播地址(self): 365 | """返回地址""" 366 | v地址 = self.fg广播地址i() 367 | return S网络地址4(v地址, self.m前缀长度) 368 | def fg广播地址i(self): 369 | """返回整数""" 370 | return self.m地址 | self.fg反掩码i() 371 | def fg掩码s(self): 372 | """返回"x.x.x.x" """ 373 | return S网络地址4.f地址整数转字符串(self.fg掩码i()) 374 | def fg掩码i(self): 375 | """返回整数""" 376 | return S网络地址4.c全f - 2 ** (S网络地址4.c最大前缀长度 - self.m前缀长度) + 1 377 | def fg反掩码s(self): 378 | """返回"x.x.x.x" """ 379 | return S网络地址4.f地址整数转字符串(self.fg反掩码i()) 380 | def fg反掩码i(self): 381 | """返回整数""" 382 | return 2 ** (S网络地址4.c最大前缀长度 - self.m前缀长度) - 1 383 | def fg前缀长度(self): 384 | return self.m前缀长度 385 | def fg分类(self): 386 | """abcde类, a类=0, b类=1, c类=2, d类=3, e类=4""" 387 | if self.m地址 < 0x80000000: 388 | return 0 389 | elif self.m地址 < 0xc0000000: 390 | return 1 391 | elif self.m地址 < 0xe0000000: 392 | return 2 393 | elif self.m地址 < 0xf0000000: 394 | return 3 395 | else: 396 | return 4 397 | def fg地址数(self): 398 | return 2 ** (S网络地址4.c最大前缀长度 - self.m前缀长度) 399 | def fg主机地址数(self): 400 | return self.fg地址数() - 2 401 | def fe主机地址(self): 402 | v范围 = range(self.fg网络号i() + 1, self.fg广播地址i()) 403 | for i in v范围: 404 | yield S网络地址4(i, self.m前缀长度) 405 | def f地址偏移(self, a: int): 406 | return S网络地址4(self.m地址 + a, self.m前缀长度) 407 | def f网段偏移(self, a: int): 408 | return S网络地址4(self.m地址 + a * self.fg地址数(), self.m前缀长度) 409 | def fi范围内(self, a地址, a真子集 = False): 410 | v地址 = S网络地址4.fc自动(a地址) 411 | if self.m前缀长度 > v地址.m前缀长度: 412 | return False 413 | if self.m前缀长度 == v地址.m前缀长度 and a真子集: 414 | return False 415 | return self.fg网络号i() == v地址.m地址 & self.fg掩码i() 416 | def ft字符串(self): 417 | """返回"x.x.x.x/n" """ 418 | v字符串 = self.fg地址s() 419 | v长度 = self.fg前缀长度() 420 | if v长度 > 0: 421 | v字符串 += "/" + str(v长度) 422 | elif self.fg地址i() == 0: 423 | v字符串 += "/0" 424 | return v字符串 425 | def ft元组(self): 426 | """返回(x,x,x,x,n)""" 427 | return self.fg地址t() + (self.fg前缀长度(),) 428 | def fi空(self): 429 | "掩码全0" 430 | return self.m前缀长度 == 0 431 | def fi主机(self): 432 | "掩码全1" 433 | return self.m前缀长度 == 32 434 | def fi单播(self): 435 | """abc类地址""" 436 | return self.m地址 < 0xe0000000 437 | def fi组播(self): 438 | """d类地址""" 439 | return 0xe0000000 <= self.m地址 < 0xf0000000 440 | def fi网络号(self): 441 | """主机地址全为0""" 442 | return not bool(self.m地址 & self.fg反掩码i()) 443 | def fi广播(self): 444 | """主机地址全为1""" 445 | v反掩码 = self.fg反掩码i() 446 | return not bool(self.m地址 & v反掩码 ^ v反掩码) 447 | def fi保留(self): 448 | """e类地址""" 449 | return self.m地址 >= 0xf0000000 450 | def fi环回(self): 451 | """127.0.0.0/8""" 452 | return 0x7f000000 <= self.m地址 < 0x80000000 453 | def fi私有(self): 454 | """10.0.0.0/8 或 172.16.0.0/12 或 192.168.0.0/16""" 455 | return (0x0a000000 <= self.m地址 < 0x0b000000) or (0xac100000 <= self.m地址 < 0xac200000) or (0xc0a80000 <= self.m地址 < 0xc0a90000) 456 | #=============================================================================== 457 | # 网络地址6 458 | #=============================================================================== 459 | class S网络地址6: 460 | "ipv6地址,默认小写表示" 461 | c最大前缀长度 = 128 462 | c全f = 0xffffffffffffffffffffffffffffffff 463 | c多个零正则 = re.compile(r"(\:0){2,6}") 464 | def __init__(self, a地址 = 0, a前缀长度 = 0): 465 | self.m地址 = a地址 466 | self.m前缀长度 = a前缀长度 467 | def __str__(self): 468 | return self.ft字符串() 469 | def __add__(self, a): #地址加 470 | v类型 = type(a) 471 | if v类型 == int: 472 | return S网络地址6(self.m地址 + a, self.m前缀长度) 473 | raise TypeError("不支持的类型") 474 | def __sub__(self, a): #地址减 475 | v类型 = type(a) 476 | if v类型 == int: 477 | return S网络地址6(self.m地址 - a, self.m前缀长度) 478 | raise TypeError("不支持的类型") 479 | def __getitem__(self, a): 480 | """按主机地址获取当前网段完整地址 481 | 例如: S网络地址6.fc自动("fc00::/64").__getitem__("::1")返回"fc00::1/64" """ 482 | v类型 = type(a) 483 | if v类型 == int: #地址整数偏移,类似 S网络地址4.__getitem__ 484 | if a >= 0: 485 | return S网络地址6(self.fg网络号i() + a, self.m前缀长度) 486 | else: #负数,从后面开始 487 | return S网络地址6(self.fg广播地址i() + a + 1, self.m前缀长度) 488 | elif v类型 == str: #主机地址覆盖 489 | return self.f合并主机地址(a) 490 | raise TypeError("不支持的类型") 491 | @staticmethod 492 | def fc自动(*a): 493 | """ 494 | 字符串格式:x:x:x:x:x:x:x:x/64(可以使用缩写地址) 495 | """ 496 | v长度 = len(a) 497 | if v长度 > 1: 498 | v前缀长度 = a[1] 499 | else: 500 | v前缀长度 = 128 501 | v0 = a[0] 502 | v类型 = type(v0) 503 | if v类型 == str: 504 | #取参数 505 | if "/" in v0: 506 | if v0.count("/") != 1: 507 | raise ValueError("斜杠太多") 508 | v地址, v前缀长度 = v0.split("/") 509 | else: 510 | v地址 = v0 511 | #赋值 512 | v前缀长度 = int(v前缀长度) 513 | v地址 = S网络地址6.f地址字符串转整数(v地址) 514 | return S网络地址6(v地址, v前缀长度) 515 | elif v类型 == int: 516 | v前缀长度 = int(v前缀长度) 517 | return S网络地址6(v0, v前缀长度) 518 | elif v类型 in (ipaddress.IPv6Network, ipaddress.IPv6Interface): 519 | v地址, v前缀长度 = v0.with_prefixlen.split("/") 520 | return S网络地址6.fc地址前缀长度(v地址, v前缀长度) 521 | elif v类型 == ipaddress.IPv6Address: 522 | return S网络地址6(int(v0), 128) 523 | elif v0 == None: 524 | return S网络地址6(0, 0) 525 | else: 526 | raise TypeError("无法解析参数类型") 527 | @staticmethod 528 | def fc地址前缀长度(a地址, a前缀长度: int): 529 | if type(a地址) == str: 530 | v地址 = S网络地址6.f地址字符串转整数(a地址) 531 | else: 532 | v地址 = int(a地址) 533 | return S网络地址6(v地址, a前缀长度) 534 | @staticmethod 535 | def fc八段(a0, a1, a2, a3, a4, a5, a6, a7, a前缀长度 = 128): 536 | v整数 = S网络地址6.f八段转整数(a0, a1, a2, a3, a4, a5, a6, a7) 537 | return S网络地址6(v整数, a前缀长度) 538 | @staticmethod 539 | def fc地址前缀长度字符串(a地址: str): 540 | """格式: x:x:x:x:x:x:x:x/64""" 541 | if a地址.count("/") != 1: 542 | raise ValueError("斜杠太多") 543 | v地址, v前缀长度 = a地址.split("/") 544 | v前缀长度 = int(v前缀长度) 545 | v地址 = S网络地址6.f地址字符串转整数(v地址) 546 | return S网络地址6(v地址, v前缀长度) 547 | @staticmethod 548 | def fc主机地址字符串(a地址: str): 549 | """格式: x:x:x:x:x:x:x:x""" 550 | v地址 = S网络地址6.f地址字符串转整数(a地址) 551 | return S网络地址6(v地址, 128) 552 | @staticmethod 553 | def f地址字符串转整数(a): 554 | """把ipv6地址转换成128位整数, 可以使用缩写地址, 自动识别大小写""" 555 | v类型 = type(a) 556 | if v类型 == str: 557 | v字符串 = str(a) 558 | v冒号数量 = v字符串.count(":") 559 | if v冒号数量 < 2 or v冒号数量 > 8: 560 | raise ValueError("冒号太少或太多") 561 | #填充,把::改为:0:0:0:0 562 | v位置 = v字符串.find("::") 563 | if v位置 >= 0: 564 | v插入字符串 = ":0" * (8 - v冒号数量) 565 | v字符串 = v字符串[:v位置] + v插入字符串 + v字符串[v位置+1:] 566 | #转换 567 | v数字 = 0 568 | v分割 = v字符串.split(":") 569 | for v in v分割: 570 | v长度 = len(v) 571 | if v长度 > 4: 572 | raise ValueError("字符数量太多") 573 | if v: 574 | v数字 = v数字 * 0x10000 + int(v, 16) 575 | else: 576 | v数字 *= 0x10000 577 | return v数字 578 | else: 579 | raise TypeError("无法解析的参数类型") 580 | @staticmethod 581 | def f地址整数转字符串(a): 582 | def f列表数字转字符串(a列表): 583 | v列表 = [] 584 | for v in a列表: 585 | v列表.append(hex(v)[2:]) 586 | return ":".join(v列表) 587 | v分段 = S网络地址6.f地址整数转八段(a) 588 | v索引, v数量 = S网络地址6.f计算最长零段(v分段) 589 | if v数量 >= 2: 590 | v列表0 = v分段[:v索引] 591 | v列表1 = v分段[v索引 + v数量 :] 592 | v字符串 = f列表数字转字符串(v列表0) + "::" + f列表数字转字符串(v列表1) 593 | else: 594 | v字符串 = f列表数字转字符串(v分段) 595 | return v字符串 596 | @staticmethod 597 | def f八段转整数(a0, a1, a2, a3, a4, a5, a6, a7): 598 | def f(a): 599 | v = int(a) 600 | if v < 0 or v > 0xffff: 601 | raise ValueError("数字超出范围0~0xffff") 602 | return v 603 | return f(a0) * 2 ** 112 + f(a1) * 2 ** 96 + f(a2) * 2 ** 80 + f(a3) * 2 ** 64 +f(a4) * 2 ** 48 + f(a5) * 2 ** 32 + f(a6) * 2 ** 16 + f(a7) 604 | @staticmethod 605 | def f地址整数转八段(a): 606 | v分段 = [0, 0, 0, 0, 0, 0, 0, 0] 607 | v地址 = a 608 | for i in range(8): 609 | v数字 = v地址 % 0x10000 610 | v分段[7-i] = v数字 611 | v地址 //= 0x10000 612 | return v分段 613 | @staticmethod 614 | def fi地址格式(a): 615 | return True 616 | def fg地址i(self): 617 | return self.m地址 618 | def fg地址s(self): 619 | return S网络地址6.f地址整数转字符串(self.m地址) 620 | def fg网络号(self): 621 | """取该网段第一个ip. ipv6没有保留网络号,所以该地址可以用在主机上""" 622 | v地址 = self.fg网络号i() 623 | return S网络地址6.fc地址前缀长度(v地址, self.m前缀长度) 624 | def fg网络号i(self): 625 | return self.m地址 & (S网络地址6.c全f - 2 ** (128 - self.m前缀长度) + 1) 626 | def fg网络号s(self): 627 | return S网络地址6.f地址整数转字符串(self.fg网络号i()) 628 | def fg广播地址(self): 629 | """取该网段最后一个ip. ipv6没有广播地址,所以该地址可以用在主机上""" 630 | v地址 = self.fg广播地址i() 631 | return S网络地址6.fc地址前缀长度(v地址, self.m前缀长度) 632 | def fg广播地址i(self): 633 | return self.m地址 | (2 ** (128 - self.m前缀长度) - 1) 634 | def fg广播地址s(self): 635 | return S网络地址6.f地址整数转字符串(self.fg广播地址i()) 636 | def fg掩码s(self): 637 | return S网络地址6.f地址整数转字符串(self.fg掩码i()) 638 | def fg掩码i(self): 639 | return S网络地址6.c全f - 2 ** (S网络地址6.c最大前缀长度 - self.m前缀长度) + 1 640 | def fg反掩码s(self): 641 | return S网络地址6.f地址整数转字符串(self.fg反掩码i()) 642 | def fg反掩码i(self): 643 | return 2 ** (S网络地址6.c最大前缀长度 - self.m前缀长度) - 1 644 | def fi范围内(self, a地址, a真子集 = False): 645 | v地址 = S网络地址6.fc自动(a地址) 646 | if self.m前缀长度 < v地址.m前缀长度: 647 | return False 648 | if self.m前缀长度 == v地址.m前缀长度 and a真子集: 649 | return False 650 | return self.fg网络号i() == v地址.m地址 & self.fg掩码i() 651 | def ft字符串(self): 652 | v字符串 = S网络地址6.f地址整数转字符串(self.m地址) 653 | v字符串 += "/" + str(self.m前缀长度) 654 | return v字符串 655 | def fg主机地址数(self): 656 | return 2 ** (S网络地址6.c最大前缀长度 - self.m前缀长度) - 2 657 | def fg前缀长度(self): 658 | return self.m前缀长度 659 | def f合并主机地址(self, a: str): 660 | """网络号+主机地址""" 661 | v主机整数 = S网络地址6.f地址字符串转整数(a) 662 | v新地址 = self.fg网络号i() | v主机整数 663 | return S网络地址6(v新地址, self.m前缀长度) 664 | @staticmethod 665 | def f计算最长零段(a分段): 666 | "返回(索引,数量)" 667 | v索引 = 0 668 | v数量 = 0 669 | v索引0 = 0 670 | v数量0 = 0 671 | i = 0 672 | for v in a分段: 673 | if v == 0: 674 | v数量0 += 1 675 | else: 676 | if v数量 < v数量0: 677 | v索引 = v索引0 678 | v数量 = v数量0 679 | v数量0 = 0 680 | v索引0 = i + 1 681 | i += 1 682 | if v数量0 != 0: 683 | if v数量 < v数量0: 684 | v索引 = v索引0 685 | v数量 = v数量0 686 | return v索引, v数量 687 | def fe八段(self, a升序 = False): 688 | v地址 = self.m地址 689 | if a升序: 690 | for i in range(8): 691 | v数字 = v地址 % 0x10000 692 | yield v数字 693 | v地址 //= 0x10000 694 | else: #降序 695 | for i in range(8): 696 | v除数 = 0x10000 ** (7 - i) 697 | v数字 = v地址 // v除数 698 | yield v数字 699 | v地址 %= v除数 700 | def fg八段(self): 701 | return S网络地址6.f地址整数转八段(self.m地址) 702 | def fi空(self): 703 | "掩码全0" 704 | return self.m前缀长度 == 0 705 | def fi主机(self): 706 | "掩码全1" 707 | return self.m前缀长度 == 128 708 | #=============================================================================== 709 | # 物理地址 710 | #=============================================================================== 711 | class S物理地址: 712 | "mac地址" 713 | def __init__(self, a值: int = 0): 714 | self.m值 = a值 715 | @staticmethod 716 | def fc整数(a: int): 717 | return S物理地址(a) 718 | @staticmethod 719 | def fc字符串(a: str): 720 | v类型 = type(a) 721 | if v类型 == str: 722 | v字符串 = 字符串.f去非十六进制数字(a) 723 | if len(v字符串) == 12: 724 | return S物理地址(int(v字符串, 16)) 725 | else: 726 | raise ValueError() 727 | else: 728 | raise TypeError() 729 | return None 730 | @staticmethod 731 | def fc字节(a: bytes): 732 | """从字节集创建物理地址""" 733 | return S物理地址(int.from_bytes(a, byteorder = "big", signed = False)) 734 | def __str__(self): 735 | return self.fg字符串() 736 | def fg字符串(self, a分隔符 = "", a分隔位数 = 4): 737 | v字符串 = hex(self.m值)[2:] #去掉0x 738 | v长度 = len(v字符串) 739 | if v长度 < 12: 740 | v字符串 = "0" * (12 - v长度) + v字符串 741 | if a分隔符: 742 | return 字符串.f隔段插入字符串(v字符串, a分隔符, a分隔位数) 743 | else: 744 | return v字符串 745 | #=============================================================================== 746 | # 连续地址类 747 | #=============================================================================== 748 | class C连续地址4: 749 | def __init__(self, *a地址): 750 | if '-' in a地址[0]: 751 | v地址 = a地址[0].split('-') 752 | self.m地址0 = ipaddress.IPv4Address(v地址[0]) 753 | self.m地址1 = ipaddress.IPv4Address(C互联网协议4.f补全地址(v地址[0], v地址[1])) 754 | elif len(a地址) == 2: 755 | self.m地址0 = ipaddress.IPv4Address(a地址[0]) 756 | self.m地址1 = ipaddress.IPv4Address(a地址[1]) 757 | else: 758 | raise ValueError() 759 | def __iter__(self): 760 | self.m迭代计数 = int(self.m地址0) 761 | self.m迭代结束 = int(self.m地址1) 762 | return self 763 | def __next__(self): 764 | if self.m迭代计数 <= self.m迭代结束: 765 | v地址 = ipaddress.IPv4Address(self.m迭代计数) 766 | self.m迭代计数 += 1 767 | return v地址 768 | else: 769 | raise StopIteration() 770 | #=============================================================================== 771 | # 其他 772 | #=============================================================================== 773 | #类型别名 774 | Cip地址 = S网络地址4 775 | Cipv6地址 = S网络地址6 776 | Cmac地址 = S物理地址 777 | #函数 778 | def fc网络地址(*a地址): 779 | """创建版本4或版本6""" 780 | v0 = a地址[0] 781 | v类型0 = type(v0) 782 | if v类型0 == str: 783 | if ":" in v0: 784 | return S网络地址6.fc自动(*a地址) 785 | else: 786 | return S网络地址4.fc自动(*a地址) 787 | else: 788 | raise TypeError("无法识别的类型") -------------------------------------------------------------------------------- /cflw代码库py/cflw网络连接.py: -------------------------------------------------------------------------------- 1 | import enum 2 | from . import cflw时间 as 时间 3 | class E连接特性(enum.IntEnum): 4 | e命令行 = 0x0001 5 | e网页 = 0x0002 6 | c简单网管 = 0x0004 7 | e全部 = 0xffffffff 8 | #=============================================================================== 9 | # 命令行连接接口 10 | #=============================================================================== 11 | class I命令行连接: 12 | "连接接口" 13 | c连接特性 = E连接特性.e命令行 14 | def f连接(self): 15 | raise NotImplementedError() 16 | def fi连接(self): 17 | raise NotImplementedError() 18 | def f读_最新(self):#应该把没有读的内容都读出来 19 | "马上读内容,可能什么都没有" 20 | raise NotImplementedError() 21 | def f读_最近(self, a数量): 22 | "读最近几次内容,包括最新的" 23 | raise NotImplementedError() 24 | def f读_直到(self, a文本 = "", a时间 = 5): 25 | "一直读到某个文本时停止. 如果没有指定文本,直到读出任何内容时返回" 26 | v阻塞 = 时间.C循环阻塞(a时间) 27 | v内容 = "" 28 | while v阻塞.f滴答(): 29 | v内容 += self.f读_最新() 30 | if (a文本 in v内容 if a文本 else bool(v内容)): 31 | return v内容 32 | return v内容 33 | def f写(self, a文本):#向设备传输文本 34 | raise NotImplementedError() 35 | def fs编码(self, a编码):#传输文本时使用的编码 36 | self.m编码 = a编码 37 | def f关闭(self): 38 | "断开连接" 39 | raise NotImplementedError() 40 | class C命令行缓存: 41 | "把读到的内容临时存起来" 42 | def __init__(self, a大小 = 10): 43 | self.m大小 = a大小 44 | self.m缓存 = [] 45 | def f存入(self, a内容): 46 | self.m缓存.append(a内容) 47 | if len(self.m缓存) > self.m大小: 48 | self.m缓存.pop(0) 49 | def f取出(self, a数量): 50 | assert(a数量 <= self.m大小) 51 | s = "" 52 | v数量 = len(self.m缓存) 53 | if v数量 > a数量: 54 | v数量 = a数量 55 | for i in range(v数量): 56 | s += self.m缓存[i] 57 | return s 58 | def f存取(self, a存内容, a取数量): 59 | assert(a取数量 <= self.m大小) 60 | self.f存入(a存内容) 61 | return self.f取出(a取数量) 62 | def fs大小(self, a大小): 63 | self.m大小 = a大小 64 | def fg大小(self): 65 | return self.m大小 66 | class C命令行回显: 67 | c连接特性 = I命令行连接.c连接特性 68 | def __init__(self, a连接, af输入回显, af输出回显): 69 | if not isinstance(a连接, I命令行连接): 70 | raise TypeError() 71 | self.m连接 = a连接 72 | self.mf输入回显 = C命令行回显.f处理回显函数(af输入回显) 73 | self.mf输出回显 = C命令行回显.f处理回显函数(af输出回显) 74 | def f读_最新(self): 75 | v内容 = self.m连接.f读_最新() 76 | self.mf输出回显(v内容) 77 | return v内容 78 | def f读_最近(self, a数量): 79 | v内容 = self.m连接.f读_最近(a数量) 80 | self.mf输出回显(v内容) 81 | return v内容 82 | def f读_直到(self, a文本 = "", a时间 = 5): 83 | v内容 = self.m连接.f读_直到(a文本, a时间) 84 | self.mf输出回显(v内容) 85 | return v内容 86 | def f写(self, a文本): 87 | self.mf输入回显(a文本) 88 | self.m连接.f写(a文本) 89 | def fs编码(self, a编码): 90 | self.m连接.fs编码(a编码) 91 | @staticmethod 92 | def f处理回显函数(af): 93 | if hasattr(af, "__call__"): 94 | return af 95 | if bool(af): 96 | import functools 97 | return functools.partial(print, end = '', flush = True) 98 | else: 99 | from . import cflw工具_运算 as 运算 100 | return 运算.f空 101 | #=============================================================================== 102 | # 具体连接 103 | #=============================================================================== 104 | class C网络终端(I命令行连接): 105 | "telnet" 106 | c命令行缓存大小 = 10 #最近读的10个文本 107 | def __init__(self, a主机, a端口号 = 23): 108 | self.m主机 = a主机 109 | self.m端口号 = a端口号 110 | self.m终端 = None 111 | self.m编码 = "utf-8" 112 | self.m缓存 = C命令行缓存(C网络终端.c命令行缓存大小) 113 | def f连接(self): 114 | assert(not self.m终端) 115 | import telnetlib 116 | self.m终端 = telnetlib.Telnet(self.m主机, self.m端口号) 117 | def fi连接(self): 118 | return bool(self.m终端) 119 | def f读_最新(self): 120 | v数据 = self.m终端.read_very_eager() 121 | v内容 = v数据.decode(self.m编码, "backslashreplace") 122 | if v内容: 123 | self.m缓存.f存入(v内容) 124 | return v内容 125 | def f读_最近(self, a数量 = 1): 126 | self.f读_最新() 127 | return self.m缓存.f取出(a数量) 128 | def f读_直到(self, a文本 = "", a时间 = 5): 129 | """直到读出相应文本\n 130 | 如果没有指定文本,直到读出任何内容时返回。 131 | """ 132 | if a文本: #直到读出相应文本 133 | return self.m终端.read_until(a文本.encode(self.m编码), a时间).decode(self.m编码, "backslashreplace") 134 | else: #直到有内容出现 135 | v阻塞 = 时间.C循环阻塞(a时间) 136 | while v阻塞.f滴答(): 137 | v内容 = self.f读_最新() 138 | if v内容: 139 | return v内容 140 | return v内容 141 | def f写(self, a文本: str): 142 | self.m终端.write(a文本.encode(self.m编码)) 143 | def f关闭(self): 144 | self.m终端.close() 145 | self.m终端 = None 146 | class C空连接(I命令行连接): 147 | "什么也不做" 148 | c连接特性 = 0xffffffff 149 | def f连接(self): 150 | pass 151 | def fi连接(self): 152 | return True 153 | def f读_最新(self): 154 | return "" 155 | def f读_最近(self, a数量): 156 | return "" 157 | def f写(self, a文本: str):#向设备传输文本 158 | v文本 = a文本.replace('\r', '\n') 159 | print(v文本, end = '') 160 | def fs编码(self, a编码):#传输文本时使用的编码 161 | pass 162 | def f关闭(self): 163 | pass 164 | -------------------------------------------------------------------------------- /cflw代码库py/cflw网络连接_串口.py: -------------------------------------------------------------------------------- 1 | import time 2 | from . import cflw网络连接 as 连接 3 | import serial #pyserial 4 | class C串口(连接.I命令行连接): 5 | "serial" 6 | def __init__(self, a端口名, a波特率 = 9600): 7 | #连接参数 8 | self.m端口名 = a端口名 9 | self.m波特率 = a波特率 10 | #其它 11 | self.m编码 = "ascii" 12 | self.m缓存 = 连接.C命令行缓存() 13 | def f连接(self): 14 | self.m串口 = serial.Serial(#下面这些参数根据情况修改 15 | port = self.m端口名, 16 | baudrate = self.m波特率, 17 | parity = serial.PARITY_NONE, 18 | stopbits = serial.STOPBITS_ONE, 19 | bytesize = serial.EIGHTBITS, 20 | timeout = 1 21 | ) 22 | def f读_最新(self): 23 | v数据 = b"" 24 | while self.m串口.in_waiting > 0: 25 | v数据 += self.m串口.read(self.m串口.in_waiting) 26 | time.sleep(0.1) 27 | v内容 = v数据.decode(self.m编码, "backslashreplace") 28 | if v内容: 29 | self.m缓存.f存入(v内容) 30 | return v内容 31 | def f读_最近(self, a数量 = 1): 32 | self.f读_最新() 33 | return self.m缓存.f取出(a数量) 34 | def f写(self, a文本: str): 35 | self.m串口.write(a文本.encode(self.m编码)) 36 | while self.m串口.out_waiting > 0: 37 | time.sleep(0.1) 38 | time.sleep(0.1) 39 | def f关闭(self): 40 | self.m串口.close() -------------------------------------------------------------------------------- /cflw代码库py/cflw网络连接_安全外壳.py: -------------------------------------------------------------------------------- 1 | import time 2 | import paramiko #paramiko 3 | #import pexpect #pexpect 4 | from . import cflw网络连接 as 连接 5 | class C安全外壳2(连接.I命令行连接): #使用paramiko 6 | def __init__(self, a主机, a端口号 = 22, a用户名 = "", a密码 = "", a超时 = 10): 7 | self.m客户端 = paramiko.SSHClient() 8 | self.m客户端.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 9 | #连接 10 | self.m主机 = a主机 11 | self.m端口号 = a端口号 12 | self.m用户名 = a用户名 13 | self.m密码 = a密码 14 | self.m超时 = a超时 15 | #其它 16 | self.m编码 = "utf-8" 17 | self.m缓存 = 连接.C命令行缓存() 18 | def f连接(self): 19 | self.m客户端.connect(hostname = self.m主机, port = self.m端口号, username = self.m用户名, password = self.m密码, timeout = self.m超时, look_for_keys = False) 20 | self.m频道 = self.m客户端.invoke_shell(width = 10000, height = 10000) 21 | def f读_最新(self): 22 | v数据 = b"" 23 | while self.m频道.recv_ready(): 24 | v数据 += self.m频道.recv(1024) 25 | time.sleep(0.1) 26 | v内容 = v数据.decode(self.m编码, "backslashreplace") 27 | self.m缓存.f存入(v内容) 28 | return v内容 29 | def f读_最近(self, a数量 = 1): 30 | self.f读_最新() 31 | return self.m缓存.f取出(a数量) 32 | def f写(self, a文本): 33 | self.m频道.send(a文本.encode(self.m编码)) 34 | def f关闭(self): 35 | self.m客户端.close() 36 | -------------------------------------------------------------------------------- /cflw代码库py/cflw网络连接_视窗.py: -------------------------------------------------------------------------------- 1 | import time 2 | from . import cflw网络连接 as 连接 3 | import win32pipe #pywin32 4 | import win32file #pywin32 5 | class C命名管道(连接.I命令行连接): 6 | def __init__(self, a名称): 7 | self.m管道 = None 8 | self.m名称 = a名称 9 | self.m缓存 = 连接.C命令行缓存() 10 | self.m编码 = "utf-8" 11 | def __del__(self): 12 | self.f关闭() 13 | def f连接(self): 14 | self.m管道 = win32file.CreateFile( 15 | self.m名称, 16 | win32file.GENERIC_READ | win32file.GENERIC_WRITE, 17 | 0, 18 | None, 19 | win32file.OPEN_EXISTING, 20 | 0, 21 | None 22 | ) 23 | v结果 = win32pipe.SetNamedPipeHandleState(self.m管道, win32pipe.PIPE_READMODE_BYTE | win32pipe.PIPE_NOWAIT, None, None) 24 | if v结果 == 0: 25 | raise RuntimeError() 26 | def f读_最新(self): 27 | v数据 = b"" 28 | while True: 29 | try: 30 | v结果, v读 = win32file.ReadFile(self.m管道, 65536) 31 | v数据 += v读 32 | time.sleep(0.1) 33 | except: #没有数据时会抛异常,无视 34 | break 35 | v内容 = v数据.decode(self.m编码, "backslashreplace") 36 | if v内容: 37 | self.m缓存.f存入(v内容) 38 | return v内容 39 | def f读_最近(self, a数量 = 1): 40 | self.f读_最新() 41 | return self.m缓存.f取出(a数量) 42 | def f写(self, a文本: str): 43 | v长度 = len(a文本) 44 | for i in range(0, v长度, 8): #分段写入 45 | win32file.WriteFile(self.m管道, a文本[i:i+8].encode(self.m编码)) 46 | time.sleep(0.1) 47 | def f关闭(self): 48 | if self.m管道: 49 | win32file.CloseHandle(self.m管道) 50 | self.m管道 = None -------------------------------------------------------------------------------- /cflw代码库py/cflw网页连接.py: -------------------------------------------------------------------------------- 1 | import enum 2 | import urllib.parse 3 | from . import cflw网页连接_微软 as 微软 4 | from . import cflw网页连接_火狐 as 火狐 5 | from . import cflw网页连接_谷歌 as 谷歌 6 | class E浏览器(enum.IntEnum): 7 | ie = enum.auto() 8 | edge = enum.auto() 9 | firefox = enum.auto() 10 | e火狐 = firefox 11 | chrome = enum.auto() 12 | e谷歌 = chrome 13 | def f创建浏览器(a浏览器, a地址 = ""): 14 | #去掉ssl提示:https://stackoverflow.com/questions/24507078/how-to-deal-with-certificates-using-selenium 15 | if a浏览器 == E浏览器.firefox: 16 | v浏览器 = 火狐.C火狐() 17 | elif a浏览器 == E浏览器.chrome: 18 | v浏览器 = 谷歌.C谷歌() 19 | elif a浏览器 == E浏览器.ie: 20 | v浏览器 = 微软.Cie() 21 | elif a浏览器 == E浏览器.edge: 22 | v浏览器 = 微软.Cedge() 23 | else: 24 | raise ValueError("无法识别的参数") 25 | if a地址: 26 | v浏览器.f打开(a地址) 27 | return v浏览器 28 | def f创建地址(a地址, a用户名 = "", a密码 = ""): 29 | v地址 = urllib.parse.urlparse(a地址) 30 | if (a用户名 or a密码) and (not "@" in v地址.netloc): 31 | v主机名 = f"{a用户名}:{a密码}@{v地址.netloc}" 32 | else: 33 | v主机名 = v地址.netloc 34 | v地址 = urllib.parse.urljoin(v地址.geturl(), "//" + v主机名) 35 | return v地址 36 | def f创建连接(a地址, a浏览器 = E浏览器.firefox): 37 | # v地址 = f创建地址(a地址) 38 | v网页 = f创建浏览器(a浏览器, a地址) 39 | return v网页 -------------------------------------------------------------------------------- /cflw代码库py/cflw网页连接_微软.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver #selenium 2 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities #selenium 3 | def f跳过证书(a浏览器): 4 | if any((s in a浏览器.title) for s in ("证书错误", "Certificate error")): 5 | a浏览器.get("javascript:document.getElementById('invalidcert_continue').click()") 6 | class Cie(webdriver.Ie, a驱动路径 = None, a浏览器路径 = None): 7 | c连接特性 = 0x0002 8 | def __init__(self): 9 | v能力 = webdriver.DesiredCapabilities.INTERNETEXPLORER.copy() 10 | v能力['acceptSslCerts'] = True 11 | webdriver.Ie.__init__(self, capabilities = v能力) 12 | def f打开(self, a地址): 13 | self.get(a地址) 14 | f跳过证书(self) 15 | def fs下载路径(self, a路径): 16 | raise NotImplementedError() 17 | class Cedge(webdriver.Edge, a驱动路径 = None, a浏览器路径 = None): 18 | c连接特性 = 0x0002 19 | def __init__(self): 20 | v能力 = webdriver.DesiredCapabilities.EDGE.copy() 21 | v能力['javascriptEnabled'] = True 22 | webdriver.Edge.__init__(self, capabilities = v能力) 23 | def f打开(self, a地址): 24 | self.get(a地址) 25 | f跳过证书(self) 26 | def fs下载路径(self, a路径): 27 | raise NotImplementedError() -------------------------------------------------------------------------------- /cflw代码库py/cflw网页连接_火狐.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver #selenium >= 4.11 2 | from selenium.webdriver.firefox.options import Options as FirefoxOptions #selenium >= 4 3 | c驱动程序 = "geckodriver" 4 | class C火狐(webdriver.Firefox): 5 | c连接特性 = 0x0002 6 | def __init__(self, a驱动路径 = None, a浏览器路径 = None): 7 | v选项 = FirefoxOptions() #selenium4的写法 8 | v选项.binary_location = a浏览器路径 9 | #能力 10 | v选项.set_capability('acceptInsecureCerts', True) 11 | #档案 12 | v选项.accept_insecure_certs = True 13 | v选项.set_preference("browser.download.folderList", 1) #下载路径:0桌面,1默认,2自定义 14 | v选项.set_preference("browser.download.manager.showWhenStarting", False) #是否显示开始 15 | v选项.set_preference("browser.download.manager.useWindow", False) 16 | v选项.set_preference("browser.download.manager.alertonEXEopen", False) 17 | v选项.set_preference("browser.download.manager.showAlertonComplete", False) 18 | v选项.set_preference("browser.download.manager.closeWhenDone", False) 19 | v选项.set_preference('browser.helperApps.alwaysAsk.force', False) 20 | va文件类型 = [ 21 | "binary/octet-stream", 22 | "application/octet-stream", 23 | "application/zip", 24 | "text/plain", 25 | "application/x-msdownload", 26 | ] 27 | v选项.set_preference("browser.helperApps.neverAsk.saveToDisk", ",".join(va文件类型)) #不询问下载路径的文件类型 28 | v选项.set_preference("security.tls.version.min", 1) #允许tls1.0 29 | #服务 30 | v服务 = webdriver.FirefoxService(executable_path = a驱动路径) #selenium 4.11似乎无法搜索PATH,需要指定绝对路径 31 | #创建对象 32 | webdriver.Firefox.__init__(self, options = v选项, service = v服务) 33 | def f打开(self, a地址): 34 | self.get(a地址) 35 | def fs下载路径(self, a路径): 36 | self.firefox_profile.set_preference("browser.download.folderList", 2) #设置成2则可以保存到指定目录 37 | self.firefox_profile.set_preference("browser.download.dir", a路径) #下载到指定目录 38 | -------------------------------------------------------------------------------- /cflw代码库py/cflw网页连接_谷歌.py: -------------------------------------------------------------------------------- 1 | import os 2 | from selenium import webdriver #selenium >= 4 3 | c驱动程序 = "chromedriver" 4 | class C谷歌(webdriver.Chrome): 5 | c连接特性 = 0x0002 6 | def __init__(self, a驱动路径 = None, a浏览器路径 = None): 7 | #选项 8 | v选项 = webdriver.ChromeOptions() 9 | v选项.add_argument('--allow-running-insecure-content') 10 | v选项.add_argument('--ignore-certificate-errors') 11 | v选项.add_argument('--allow-insecure-localhost') 12 | v选项.add_argument('--unsafely-treat-insecure-origin-as-secure') 13 | # v选项.add_experimental_option('profile.default_content_settings.popups', 0) #InvalidArgumentException 14 | # v选项.add_experimental_option('download.default_directory', os.getcwd()) #InvalidArgumentException 15 | #服务 16 | v服务 = webdriver.ChromeService(executable_path = a驱动路径) 17 | #创建对象 18 | webdriver.Chrome.__init__(self, options = v选项, service = v服务) 19 | def f打开(self, a地址): 20 | self.get(a地址) 21 | def fs下载路径(self, a路径): 22 | raise NotImplementedError() -------------------------------------------------------------------------------- /cflw代码库py/cflw英语.py: -------------------------------------------------------------------------------- 1 | ca月 = ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"] 2 | ca星期 = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] 3 | def f月份(i): 4 | "一月 = 1" 5 | return ca月[i-1] 6 | def f星期(i): 7 | "星期一 = 0" 8 | return ca星期[i] -------------------------------------------------------------------------------- /cflw代码库py/cflw辅助.py: -------------------------------------------------------------------------------- 1 | import sys 2 | #=============================================================================== 3 | # 制约 4 | #=============================================================================== 5 | class A制约: 6 | "包装f(t: type)->bool" 7 | g异常开关 = True 8 | def __init__(self, f): 9 | self.mf = f 10 | def __call__(self, t): 11 | v = bool(self.mf(t)) 12 | if A制约.g异常开关 and not v: 13 | if t.__class__ == type: #是类型 14 | raise TypeError("类型 %s 违反制约 %s" % (t.__name__, self.mf.__name__)) 15 | else: #不是类型 16 | raise TypeError("类型 %s 违反制约 %s" % (type(t).__name__ , self.mf.__name__)) 17 | return v 18 | #=============================================================================== 19 | # 包管理 20 | # 引用: https://my.oschina.net/chaosannals/blog/743579 21 | #=============================================================================== 22 | g包 = {} 23 | def A导出(a项): 24 | v模块 = sys.modules[a项.__module__] 25 | v包 = sys.modules[v模块.__package__] 26 | v包.__dict__[a项.__name__] = a项 27 | if not v包.__name__ in g包: 28 | g包[v包.__name__] = [] 29 | g包[v包.__name__].append(a项.__name__) 30 | return a项 31 | def f包(a名称): 32 | if not a名称 in g包: 33 | g包[a名称] = [] 34 | return g包[a名称] -------------------------------------------------------------------------------- /cflw代码库py/cflw输入_win.py: -------------------------------------------------------------------------------- 1 | import enum 2 | class E键盘按键(enum.IntEnum): 3 | eLBUTTON = 0x01 4 | eRBUTTON = 0x02 5 | eCANCEL = 0x03 6 | eMBUTTON = 0x04 # NOT contiguous with L & RBUTTON */ 7 | eXBUTTON1 = 0x05 # NOT contiguous with L & RBUTTON */ 8 | eXBUTTON2 = 0x06 # NOT contiguous with L & RBUTTON */ 9 | e退格 = 0x08 #backspace 10 | e制表 = 0x09 #tab 11 | e清除 = 0x0C #clear 12 | e回车 = 0x0D #enter 13 | e上档 = 0x10 #不分左右的shift 14 | e控制 = 0x11 #不分左右的ctrl 15 | e交替 = 0x12 #不分左右的alt这个键又叫menu 16 | e暂停 = 0x13 #pause 17 | e大写锁 = 0x14 #capital 18 | eKANA = 0x15 19 | eHANGEUL = 0x15 # old name - should be here for compatibility */ 20 | eHANGUL = 0x15 21 | eJUNJA = 0x17 22 | eFINAL = 0x18 23 | eHANJA = 0x19 24 | eKANJI = 0x19 25 | e逃脱 = 0x1B #escape 26 | eCONVERT = 0x1C 27 | eNONCONVERT = 0x1D 28 | eACCEPT = 0x1E #accept 29 | eMODECHANGE = 0x1F #modechange 30 | e空格 = 0x20 31 | ePRIOR = 0x21 32 | eNEXT = 0x22 33 | eEND = 0x23 34 | eHOME = 0x24 35 | e左 = 0x25 36 | e上 = 0x26 37 | e右 = 0x27 38 | e下 = 0x28 39 | e选择 = 0x29 #select 40 | e打印 = 0x2A #print 41 | e执行 = 0x2B #execute 42 | eSNAPSHOT = 0x2C #snapshot 43 | e插入 = 0x2D #insert 44 | e删除 = 0x2E #delete 45 | e帮助 = 0x2F #help 46 | e0 = 0x30 47 | e1 = 0x31 48 | e2 = 0x32 49 | e3 = 0x33 50 | e4 = 0x34 51 | e5 = 0x35 52 | e6 = 0x36 53 | e7 = 0x37 54 | e8 = 0x38 55 | e9 = 0x39 56 | a = 0x41 57 | b = 0x42 58 | c = 0x43 59 | d = 0x44 60 | e = 0x45 61 | f = 0x46 62 | g = 0x47 63 | h = 0x48 64 | i = 0x49 65 | j = 0x4A 66 | k = 0x4B 67 | l = 0x4C 68 | m = 0x4D 69 | n = 0x4E 70 | o = 0x4F 71 | p = 0x50 72 | q = 0x51 73 | r = 0x52 74 | s = 0x53 75 | t = 0x54 76 | u = 0x55 77 | v = 0x56 78 | w = 0x57 79 | x = 0x58 80 | y = 0x59 81 | z = 0x5A 82 | e左视窗 = 0x5B 83 | e右视窗 = 0x5C 84 | eAPPS = 0x5D 85 | eSLEEP = 0x5F 86 | e数字0 = 0x60 87 | e数字1 = 0x61 88 | e数字2 = 0x62 89 | e数字3 = 0x63 90 | e数字4 = 0x64 91 | e数字5 = 0x65 92 | e数字6 = 0x66 93 | e数字7 = 0x67 94 | e数字8 = 0x68 95 | e数字9 = 0x69 96 | eMULTIPLY = 0x6A 97 | eADD = 0x6B 98 | eSEPARATOR = 0x6C 99 | eSUBTRACT = 0x6D 100 | eDECIMAL = 0x6E 101 | eDIVIDE = 0x6F 102 | e功能1 = 0x70 103 | e功能2 = 0x71 104 | e功能3 = 0x72 105 | e功能4 = 0x73 106 | e功能5 = 0x74 107 | e功能6 = 0x75 108 | e功能7 = 0x76 109 | e功能8 = 0x77 110 | e功能9 = 0x78 111 | e功能10 = 0x79 112 | e功能11 = 0x7A 113 | e功能12 = 0x7B 114 | e功能13 = 0x7C 115 | e功能14 = 0x7D 116 | e功能15 = 0x7E 117 | e功能16 = 0x7F 118 | e功能17 = 0x80 119 | e功能18 = 0x81 120 | e功能19 = 0x82 121 | e功能20 = 0x83 122 | e功能21 = 0x84 123 | e功能22 = 0x85 124 | e功能23 = 0x86 125 | e功能24 = 0x87 126 | e数字锁 = 0x90 127 | e滚动锁 = 0x91 128 | eOEM_NEC_EQUAL = 0x92# '=' key on numpad 129 | eOEM_FJ_JISHO = 0x92 # 'Dictionary' key 130 | eOEM_FJ_MASSHOU = 0x93 # 'Unregister word' key 131 | eOEM_FJ_TOUROKU = 0x94 # 'Register word' key 132 | eOEM_FJ_LOYA = 0x95 # 'Left OYAYUBI' key 133 | eOEM_FJ_ROYA = 0x96 # 'Right OYAYUBI' key 134 | e左上档 = 0xA0 135 | e右上档 = 0xA1 136 | e左控制 = 0xA2 137 | e右控制 = 0xA3 138 | e左交替 = 0xA4 139 | e右交替 = 0xA5 140 | eBROWSER_BACK = 0xA6 141 | eBROWSER_FORWARD = 0xA7 142 | eBROWSER_REFRESH = 0xA8 143 | eBROWSER_STOP = 0xA9 144 | eBROWSER_SEARCH = 0xAA 145 | eBROWSER_FAVORITES = 0xAB 146 | eBROWSER_HOME = 0xAC 147 | eVOLUME_MUTE = 0xAD 148 | eVOLUME_DOWN = 0xAE 149 | eVOLUME_UP = 0xAF 150 | eMEDIA_NEXT_TRACK = 0xB0 151 | eMEDIA_PREV_TRACK = 0xB1 152 | eMEDIA_STOP = 0xB2 153 | eMEDIA_PLAY_PAUSE = 0xB3 154 | eLAUNCH_MAIL = 0xB4 155 | eLAUNCH_MEDIA_SELECT = 0xB5 156 | eLAUNCH_APP1 = 0xB6 157 | eLAUNCH_APP2 = 0xB7 158 | eOEM_1 = 0xBA # ';:' for US 159 | eOEM_PLUS = 0xBB # '+' any country 160 | eOEM_COMMA = 0xBC # '' any country 161 | eOEM_MINUS = 0xBD # '-' any country 162 | eOEM_PERIOD = 0xBE # '.' any country 163 | eOEM_2 = 0xBF # '/?' for US 164 | eOEM_3 = 0xC0 # '`~' for US 165 | eOEM_4 = 0xDB # '[{' for US 166 | eOEM_5 = 0xDC # '\|' for US 167 | eOEM_6 = 0xDD # ']}' for US 168 | eOEM_7 = 0xDE # ''"' for US 169 | eOEM_8 = 0xDF 170 | eOEM_AX = 0xE1 # 'AX' key on Japanese AX kbd 171 | eOEM_102 = 0xE2 # "<>" or "\|" on RT 102-key kbd. 172 | eICO_HELP = 0xE3#Help key on ICO 173 | eICO_00 = 0xE4#00 key on ICO 174 | ePROCESSKEY = 0xE5 175 | eICO_CLEAR = 0xE6 176 | ePACKET = 0xE7 177 | eOEM_RESET = 0xE9 178 | eOEM_JUMP = 0xEA 179 | eOEM_PA1 = 0xEB 180 | eOEM_PA2 = 0xEC 181 | eOEM_PA3 = 0xED 182 | eOEM_WSCTRL = 0xEE 183 | eOEM_CUSEL = 0xEF 184 | eOEM_ATTN = 0xF0 185 | eOEM_FINISH = 0xF1 186 | eOEM_COPY = 0xF2 187 | eOEM_AUTO = 0xF3 188 | eOEM_ENLW = 0xF4 189 | eOEM_BACKTAB = 0xF5 190 | eATTN = 0xF6 191 | eCRSEL = 0xF7 192 | eEXSEL = 0xF8 193 | eEREOF = 0xF9 194 | ePLAY = 0xFA 195 | eZOOM = 0xFB 196 | eNONAME = 0xFC 197 | ePA1 = 0xFD 198 | eOEM_CLEAR = 0xFE 199 | class E鼠标按键(enum.IntEnum): 200 | e左键 = 0 201 | e右键 = 1 202 | e中键 = 2 203 | e前进 = 3 204 | e后退 = 4 205 | -------------------------------------------------------------------------------- /文档/使用说明.md: -------------------------------------------------------------------------------- 1 | # 《乘风龙王的代码库(python)》使用说明 2 | 为了确保代码能正常运行,需要对运行环境做一些配置 3 | 4 | ## 第一步 5 | 把`cflw代码库py`这个文件夹随便放在一个地方 6 | 7 | ![](图片/使用说明1.png) 8 | 9 | ## 第二步 10 | 添加环境变量`%pythonpath%`,值设置为`cflw代码库py`的上级目录 11 | 12 | ![](图片/使用说明2.png) 13 | 14 | ## 结束 15 | 可以开始使用了 -------------------------------------------------------------------------------- /文档/图片/使用说明1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflw/cflw_py/aa882b7a9ad4beb9abe9550e2fc27d24d067fbcc/文档/图片/使用说明1.png -------------------------------------------------------------------------------- /文档/图片/使用说明2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cflw/cflw_py/aa882b7a9ad4beb9abe9550e2fc27d24d067fbcc/文档/图片/使用说明2.png -------------------------------------------------------------------------------- /测试/文章_小说网站爬虫.py: -------------------------------------------------------------------------------- 1 | import re 2 | import pathlib 3 | import time 4 | from bs4 import BeautifulSoup #beautifulsoup4 5 | import requests #requests 6 | 7 | def f创建解析器(a文本): 8 | return BeautifulSoup(a文本, "html.parser") 9 | def f获取文档(a地址): 10 | v请求 = requests.get(url = a地址) 11 | v页面 = v请求.text 12 | time.sleep(1) 13 | return v页面 14 | c开头缩进正则 = re.compile(r"^\s") 15 | def f处理正文(a文本): 16 | v正文文本 = a文本 17 | v正文文本 = c开头缩进正则.sub("\n", v正文文本) #清除缩进 18 | v正文文本 = v正文文本.replace("\xa0", "") #清除缩进 19 | v正文文本 = v正文文本.replace("\u3000", "") #清除缩进 20 | v正文文本 = v正文文本.replace("\r", "\n") # 21 | v正文文本 = v正文文本.replace("\n \n", "\n") #清除多余换行 22 | while "\n\n" in v正文文本: 23 | v正文文本 = v正文文本.replace("\n\n", "\n") #清除多余换行 24 | return v正文文本 25 | def f一键下载(a小说, a保存路径): 26 | v小说名 = a小说.fg小说名() 27 | #路径 28 | v路径 = pathlib.Path(a保存路径) 29 | v路径 /= v小说名 + ".txt" 30 | v文件名 = str(v路径) 31 | print("保存到: " + v文件名) 32 | v文件 = open(v文件名, "w", encoding = "utf-8") 33 | #循环 34 | for v章节名, v章节 in a小说.fe目录(): 35 | v正文 = v章节.fg正文() 36 | v文件.write(v章节名 + "\n" + v正文 + "\n") 37 | print("下载完成") 38 | class I文档: 39 | def __init__(self): 40 | self.m文档 = None 41 | def f重新载入(self): 42 | self.m文档 = f创建解析器(f获取文档(self.fg地址())) 43 | def f载入(self): 44 | if not self.m文档: 45 | self.f重新载入() 46 | def fg地址(self): 47 | raise NotImplementedError() 48 | class I小说: 49 | def __init__(self): 50 | I文档.__init__(self) 51 | def fe目录(self): 52 | "返回(章节名, I章节 对象)" 53 | raise NotImplementedError() 54 | 55 | class I章节: 56 | def __init__(self): 57 | I文档.__init__(self) 58 | def fg正文(self): 59 | "返回字符串" 60 | raise NotImplementedError() 61 | 62 | c地址前缀 = "https://www.biqukan.com" 63 | class C小说(I文档, I小说): 64 | c章节列表类名 = "listmain" 65 | def __init__(self, a地址): 66 | I文档.__init__(self) 67 | I小说.__init__(self) 68 | self.m地址 = a地址 69 | def fg地址(self): 70 | return self.m地址 71 | def fe目录(self): 72 | self.f载入() 73 | v目录元素 = self.m文档.find(name = "div", class_ = C小说.c章节列表类名) 74 | va章节列表 = v目录元素.find_all(name = "dd") 75 | #去除前面的最新章节和最后的重复章节 76 | va章节列表 = va章节列表[12:] 77 | for v in va章节列表: 78 | v链接 = v.a.get("href") #章节链接 79 | v文本 = v.a.string #章节名 80 | if "biqukan" in v文本: #去除最后的重复章节 81 | continue 82 | yield v文本, C章节(c地址前缀 + v链接) 83 | def fg小说名(self): 84 | self.f载入() 85 | return self.m文档.find("h2").string 86 | 87 | class C章节(I文档, I章节): 88 | c正文标识名 = "content" 89 | def __init__(self, a地址): 90 | I文档.__init__(self) 91 | I章节.__init__(self) 92 | self.m地址 = a地址 93 | def fg地址(self): 94 | return self.m地址 95 | def fg正文(self): 96 | self.f载入() 97 | v正文元素 = self.m文档.find("div", id = C章节.c正文标识名) 98 | v正文文本 = "" 99 | for v行 in v正文元素.strings: 100 | if "biqukan" in v行: #去除广告 101 | continue 102 | v正文文本 += v行 + "\n" 103 | return f处理正文(v正文文本) 104 | 105 | c地址 = "https://www.biqukan.com/38_38989/" 106 | c章节地址 = "https://www.biqukan.com/1_1408/16046054.html" 107 | def main(): 108 | v小说 = C小说(c地址) 109 | # for v章节名, v章节 in v小说.fe目录(): 110 | # print(v章节名, v章节.fg地址()) 111 | # v章节 = C章节(c章节地址) 112 | # print(v章节.fg正文()) 113 | f一键下载(v小说, "d:\小说") 114 | if __name__ == "__main__": 115 | main() 116 | -------------------------------------------------------------------------------- /测试/测试_代理列表.py: -------------------------------------------------------------------------------- 1 | import cflw爬虫_代理列表 as 代理 2 | def fg过时文档(): 3 | v文件 = open("测试_代理列表.txt", "r", encoding = "utf-8") 4 | return v文件.read() 5 | def fg实时文档(): 6 | return 代理.f获取文档() 7 | def main(): 8 | v列表 = 代理.f解析文档(fg过时文档()) 9 | for v行 in v列表: 10 | print(v行) 11 | if __name__ == "__main__": 12 | main() -------------------------------------------------------------------------------- /测试/测试_代理列表.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 国内高匿免费HTTP代理IP__第1页国内高匿 5 | 6 | 7 | 8 | 9 | \u3000\u3000 10 | 11 | 12 | 13 | 14 | 15 |
16 | 32 |
33 | 34 | 35 | 36 |
37 | 当前位置: 38 | 首页 39 | > 国内高匿代理 40 |
41 | 42 | 43 | Side2 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 67 | 68 | 69 | 76 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | 104 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 123 | 124 | 125 | 132 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 151 | 152 | 153 | 160 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 179 | 180 | 181 | 188 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 207 | 208 | 209 | 216 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 235 | 236 | 237 | 244 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 263 | 264 | 265 | 272 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 291 | 292 | 293 | 300 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 319 | 320 | 321 | 328 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 347 | 348 | 349 | 356 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 375 | 376 | 377 | 384 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 403 | 404 | 405 | 412 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 431 | 432 | 433 | 440 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 459 | 460 | 461 | 468 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 487 | 488 | 489 | 496 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 515 | 516 | 517 | 524 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 543 | 544 | 545 | 552 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 571 | 572 | 573 | 580 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 599 | 600 | 601 | 608 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 627 | 628 | 629 | 636 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 655 | 656 | 657 | 664 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 683 | 684 | 685 | 692 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 711 | 712 | 713 | 720 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 739 | 740 | 741 | 748 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 767 | 768 | 769 | 776 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 795 | 796 | 797 | 804 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 823 | 824 | 825 | 832 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 851 | 852 | 853 | 860 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 879 | 880 | 881 | 888 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 907 | 908 | 909 | 916 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 935 | 936 | 937 | 944 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 963 | 964 | 965 | 972 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 991 | 992 | 993 | 1000 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1019 | 1020 | 1021 | 1028 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1047 | 1048 | 1049 | 1056 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1075 | 1076 | 1077 | 1084 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1103 | 1104 | 1105 | 1112 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1131 | 1132 | 1133 | 1140 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1159 | 1160 | 1161 | 1168 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1187 | 1188 | 1189 | 1196 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1215 | 1216 | 1217 | 1224 | 1231 | 1232 | 1233 | 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | 1240 | 1243 | 1244 | 1245 | 1252 | 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | 1271 | 1272 | 1273 | 1280 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1299 | 1300 | 1301 | 1308 | 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1327 | 1328 | 1329 | 1336 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1351 | 1352 | 1355 | 1356 | 1357 | 1364 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1383 | 1384 | 1385 | 1392 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | 1411 | 1412 | 1413 | 1420 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1439 | 1440 | 1441 | 1448 | 1455 | 1456 | 1457 | 1458 | 1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1467 | 1468 | 1469 | 1476 | 1483 | 1484 | 1485 | 1486 | 1487 | 1488 | 1489 | 1490 | 1491 | 1492 | 1495 | 1496 | 1497 | 1504 | 1511 | 1512 | 1513 | 1514 | 1515 | 1516 | 1517 | 1518 | 1519 | 1520 | 1523 | 1524 | 1525 | 1532 | 1539 | 1540 | 1541 | 1542 | 1543 | 1544 | 1545 | 1546 | 1547 | 1548 | 1551 | 1552 | 1553 | 1560 | 1567 | 1568 | 1569 | 1570 | 1571 | 1572 | 1573 | 1574 | 1575 | 1576 | 1579 | 1580 | 1581 | 1588 | 1595 | 1596 | 1597 | 1598 | 1599 | 1600 | 1601 | 1602 | 1603 | 1604 | 1607 | 1608 | 1609 | 1616 | 1623 | ...> 1624 |
1625 |
1626 | 1627 |
1628 |
1629 | 1630 | 1637 | 1638 | 1639 | 1640 | 1641 | 1642 | 1643 | 1644 | 1645 | 1646 | 1649 | 1650 | 1651 | 1658 | 1665 | 1666 | 1667 | 1668 | 1669 | 1670 | 1671 | 1672 | 1673 | 1674 | 1677 | 1678 | 1679 | 1686 | 1693 | 1694 | 1695 | 1696 | 1697 | 1698 | 1699 | 1700 | 1701 | 1702 | 1705 | 1706 | 1707 | 1714 | 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 1730 | 1733 | 1734 | 1735 | 1742 | 1749 | 1750 | 1751 | 1752 | 1753 | 1754 | 1755 | 1756 | 1757 | 1758 | 1761 | 1762 | 1763 | 1770 | 1777 | 1778 | 1779 | 1780 | 1781 | 1782 | 1783 | 1784 | 1785 | 1786 | 1789 | 1790 | 1791 | 1798 | 1805 | 1806 | 1807 | 1808 | 1809 | 1810 | 1811 | 1812 | 1813 | 1814 | 1817 | 1818 | 1819 | 1826 | 1833 | 1834 | 1835 | 1836 | 1837 | 1838 | 1839 | 1840 | 1841 | 1842 | 1845 | 1846 | 1847 | 1854 | 1861 | 1862 | 1863 | 1864 | 1865 | 1866 | 1867 | 1868 | 1869 | 1870 | 1873 | 1874 | 1875 | 1882 | 1889 | 1890 | 1891 | 1892 | 1893 | 1894 | 1895 | 1896 | 1897 | 1898 | 1901 | 1902 | 1903 | 1910 | 1917 | 1918 | 1919 | 1920 | 1921 | 1922 | 1923 | 1924 | 1925 | 1926 | 1929 | 1930 | 1931 | 1938 | 1945 | 1946 | 1947 | 1948 | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1957 | 1958 | 1959 | 1966 | 1973 | 1974 | 1975 | 1976 | 1977 | 1978 | 1979 | 1980 | 1981 | 1982 | 1985 | 1986 | 1987 | 1994 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2013 | 2014 | 2015 | 2022 | 2029 | 2030 | 2031 | 2032 | 2033 | 2034 | 2035 | 2036 | 2037 | 2038 | 2041 | 2042 | 2043 | 2050 | 2057 | 2058 | 2059 | 2060 | 2061 | 2062 | 2063 | 2064 | 2065 | 2066 | 2069 | 2070 | 2071 | 2078 | 2085 | 2086 | 2087 | 2088 | 2089 | 2090 | 2091 | 2092 | 2093 | 2094 | 2097 | 2098 | 2099 | 2106 | 2113 | 2114 | 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2121 | 2122 | 2125 | 2126 | 2127 | 2134 | 2141 | 2142 | 2143 | 2144 | 2145 | 2146 | 2147 | 2148 | 2149 | 2150 | 2153 | 2154 | 2155 | 2162 | 2169 | 2170 | 2171 | 2172 | 2173 | 2174 | 2175 | 2176 | 2177 | 2178 | 2181 | 2182 | 2183 | 2190 | 2197 | 2198 | 2199 | 2200 | 2201 | 2202 | 2203 | 2204 | 2205 | 2206 | 2209 | 2210 | 2211 | 2218 | 2225 | 2226 | 2227 | 2228 | 2229 | 2230 | 2231 | 2232 | 2233 | 2234 | 2237 | 2238 | 2239 | 2246 | 2253 | 2254 | 2255 | 2256 | 2257 | 2258 | 2259 | 2260 | 2261 | 2262 | 2265 | 2266 | 2267 | 2274 | 2281 | 2282 | 2283 | 2284 | 2285 | 2286 | 2287 | 2288 | 2289 | 2290 | 2293 | 2294 | 2295 | 2302 | 2309 | 2310 | 2311 | 2312 | 2313 | 2314 | 2315 | 2316 | 2317 | 2318 | 2321 | 2322 | 2323 | 2330 | 2337 | 2338 | 2339 | 2340 | 2341 | 2342 | 2343 | 2344 | 2345 | 2346 | 2349 | 2350 | 2351 | 2358 | 2365 | 2366 | 2367 | 2368 | 2369 | 2370 | 2371 | 2372 | 2373 | 2374 | 2377 | 2378 | 2379 | 2386 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | 2399 |
国家IP地址端口服务器地址是否匿名类型速度连接时间存活时间验证时间
Cn118.190.95.359001 65 | 广西 66 | 高匿HTTP 70 |
71 |
72 | 73 |
74 |
75 |
77 |
78 |
79 | 80 |
81 |
82 |
73天18-09-03 16:51
Cn61.135.217.780 93 | 北京 94 | 高匿HTTP 98 |
99 |
100 | 101 |
102 |
103 |
105 |
106 |
107 | 108 |
109 |
110 |
843天18-09-03 16:51
101.236.62.448866 121 | 中电华通 122 | 高匿HTTPS 126 |
127 |
128 | 129 |
130 |
131 |
133 |
134 |
135 | 136 |
137 |
138 |
3小时18-09-03 16:51
Cn118.190.95.439001 149 | 广西 150 | 高匿HTTP 154 |
155 |
156 | 157 |
158 |
159 |
161 |
162 |
163 | 164 |
165 |
166 |
73天18-09-03 16:51
Cn106.75.9.398080 177 | 山东济南 178 | 高匿HTTP 182 |
183 |
184 | 185 |
186 |
187 |
189 |
190 |
191 | 192 |
193 |
194 |
21天18-09-03 16:50
101.236.55.2478866 205 | 中电华通 206 | 高匿HTTPS 210 |
211 |
212 | 213 |
214 |
215 |
217 |
218 |
219 | 220 |
221 |
222 |
61天18-09-03 16:50
Cn125.88.172.5780 233 | 广东 234 | 高匿HTTPS 238 |
239 |
240 | 241 |
242 |
243 |
245 |
246 |
247 | 248 |
249 |
250 |
4天18-09-03 16:50
Cn110.85.89.1648010 261 | 福建莆田 262 | 高匿HTTPS 266 |
267 |
268 | 269 |
270 |
271 |
273 |
274 |
275 | 276 |
277 |
278 |
96天18-09-03 16:46
Cn110.73.4.988123 289 | 广西防城港 290 | 高匿HTTP 294 |
295 |
296 | 297 |
298 |
299 |
301 |
302 |
303 | 304 |
305 |
306 |
935天18-09-03 16:46
Cn106.56.102.1118070 317 | 云南 318 | 高匿HTTPS 322 |
323 |
324 | 325 |
326 |
327 |
329 |
330 |
331 | 332 |
333 |
334 |
103天18-09-03 16:35
Cn175.147.100.138010 345 | 辽宁鞍山 346 | 高匿HTTPS 350 |
351 |
352 | 353 |
354 |
355 |
357 |
358 |
359 | 360 |
361 |
362 |
108天18-09-03 16:33
Cn110.73.10.1208123 373 | 广西防城港 374 | 高匿HTTP 378 |
379 |
380 | 381 |
382 |
383 |
385 |
386 |
387 | 388 |
389 |
390 |
1037天18-09-03 16:33
Cn119.135.85.80808 401 | 广东清远 402 | 高匿HTTPS 406 |
407 |
408 | 409 |
410 |
411 |
413 |
414 |
415 | 416 |
417 |
418 |
1分钟18-09-03 16:33
Cn171.37.164.88123 429 | 广西 430 | 高匿HTTP 434 |
435 |
436 | 437 |
438 |
439 |
441 |
442 |
443 | 444 |
445 |
446 |
607天18-09-03 16:31
Cn106.56.102.1638070 457 | 云南 458 | 高匿HTTP 462 |
463 |
464 | 465 |
466 |
467 |
469 |
470 |
471 | 472 |
473 |
474 |
119天18-09-03 16:31
Cn211.159.171.5880 485 | 北京 486 | 高匿HTTPS 490 |
491 |
492 | 493 |
494 |
495 |
497 |
498 |
499 | 500 |
501 |
502 |
274天18-09-03 16:22
Cn122.241.74.82808 513 | 浙江丽水 514 | 高匿HTTP 518 |
519 |
520 | 521 |
522 |
523 |
525 |
526 |
527 | 528 |
529 |
530 |
444天18-09-03 16:22
139.224.118.253128 541 | 542 | 高匿HTTP 546 |
547 |
548 | 549 |
550 |
551 |
553 |
554 |
555 | 556 |
557 |
558 |
6天18-09-03 16:20
Cn118.254.208.348118 569 | 湖南衡阳 570 | 高匿HTTPS 574 |
575 |
576 | 577 |
578 |
579 |
581 |
582 |
583 | 584 |
585 |
586 |
10小时18-09-03 16:01
101.236.38.128866 597 | 中电华通 598 | 高匿HTTPS 602 |
603 |
604 | 605 |
606 |
607 |
609 |
610 |
611 | 612 |
613 |
614 |
2小时18-09-03 15:51
Cn58.253.112.5480 625 | 广东 626 | 高匿HTTP 630 |
631 |
632 | 633 |
634 |
635 |
637 |
638 |
639 | 640 |
641 |
642 |
1分钟18-09-03 15:47
Cn112.92.219.17880 653 | 广东河源 654 | 高匿HTTPS 658 |
659 |
660 | 661 |
662 |
663 |
665 |
666 |
667 | 668 |
669 |
670 |
2分钟18-09-03 15:47
Cn101.17.151.211080 681 | 河北保定 682 | 高匿HTTP 686 |
687 |
688 | 689 |
690 |
691 |
693 |
694 |
695 | 696 |
697 |
698 |
1分钟18-09-03 15:46
Cn14.156.65.2380 709 | 广东东莞 710 | 高匿HTTPS 714 |
715 |
716 | 717 |
718 |
719 |
721 |
722 |
723 | 724 |
725 |
726 |
2分钟18-09-03 15:46
Cn106.56.102.2108070 737 | 云南 738 | 高匿HTTPS 742 |
743 |
744 | 745 |
746 |
747 |
749 |
750 |
751 | 752 |
753 |
754 |
95天18-09-03 15:44
Cn175.155.24.35808 765 | 四川德阳 766 | 高匿HTTP 770 |
771 |
772 | 773 |
774 |
775 |
777 |
778 |
779 | 780 |
781 |
782 |
547天18-09-03 15:44
Cn116.77.205.14080 793 | 广东深圳 794 | 高匿HTTPS 798 |
799 |
800 | 801 |
802 |
803 |
805 |
806 |
807 | 808 |
809 |
810 |
7小时18-09-03 15:33
Cn222.76.204.110808 821 | 福建厦门 822 | 高匿HTTPS 826 |
827 |
828 | 829 |
830 |
831 |
833 |
834 |
835 | 836 |
837 |
838 |
4天18-09-03 15:33
Cn115.46.72.198123 849 | 广西南宁 850 | 高匿HTTP 854 |
855 |
856 | 857 |
858 |
859 |
861 |
862 |
863 | 864 |
865 |
866 |
14分钟18-09-03 15:30
Cn175.175.217.2181133 877 | 辽宁抚顺 878 | 高匿HTTPS 882 |
883 |
884 | 885 |
886 |
887 |
889 |
890 |
891 | 892 |
893 |
894 |
4分钟18-09-03 15:15
Cn111.155.116.2348123 905 | 北京 906 | 高匿HTTP 910 |
911 |
912 | 913 |
914 |
915 |
917 |
918 |
919 | 920 |
921 |
922 |
183天18-09-03 15:10
Cn111.155.116.2338123 933 | 北京 934 | 高匿HTTP 938 |
939 |
940 | 941 |
942 |
943 |
945 |
946 |
947 | 948 |
949 |
950 |
751天18-09-03 15:00
Cn106.56.102.63808 961 | 云南 962 | 高匿HTTP 966 |
967 |
968 | 969 |
970 |
971 |
973 |
974 |
975 | 976 |
977 |
978 |
221天18-09-03 14:45
Cn120.33.247.15938036 989 | 福建莆田 990 | 高匿HTTP 994 |
995 |
996 | 997 |
998 |
999 |
1001 |
1002 |
1003 | 1004 |
1005 |
1006 |
525天18-09-03 14:45
Cn119.5.33.22753128 1017 | 四川达州 1018 | 高匿HTTPS 1022 |
1023 |
1024 | 1025 |
1026 |
1027 |
1029 |
1030 |
1031 | 1032 |
1033 |
1034 |
1分钟18-09-03 14:33
Cn121.31.176.128123 1045 | 广西北海 1046 | 高匿HTTPS 1050 |
1051 |
1052 | 1053 |
1054 |
1055 |
1057 |
1058 |
1059 | 1060 |
1061 |
1062 |
105天18-09-03 14:33
Cn114.249.39.23132231 1073 | 北京 1074 | 高匿HTTPS 1078 |
1079 |
1080 | 1081 |
1082 |
1083 |
1085 |
1086 |
1087 | 1088 |
1089 |
1090 |
6小时18-09-03 14:07
Cn110.73.2.1928123 1101 | 广西防城港 1102 | 高匿HTTP 1106 |
1107 |
1108 | 1109 |
1110 |
1111 |
1113 |
1114 |
1115 | 1116 |
1117 |
1118 |
953天18-09-03 13:53
Cn182.88.135.128123 1129 | 广西南宁 1130 | 高匿HTTPS 1134 |
1135 |
1136 | 1137 |
1138 |
1139 |
1141 |
1142 |
1143 | 1144 |
1145 |
1146 |
484天18-09-03 13:50
Cn36.99.206.1148843 1157 | 浙江 1158 | 高匿HTTP 1162 |
1163 |
1164 | 1165 |
1166 |
1167 |
1169 |
1170 |
1171 | 1172 |
1173 |
1174 |
73天18-09-03 13:45
Cn110.72.40.1328123 1185 | 广西贵港 1186 | 高匿HTTP 1190 |
1191 |
1192 | 1193 |
1194 |
1195 |
1197 |
1198 |
1199 | 1200 |
1201 |
1202 |
1分钟18-09-03 13:45
Cn183.62.22.2203128 1213 | 广东广州 1214 | 高匿HTTP 1218 |
1219 |
1220 | 1221 |
1222 |
1223 |
1225 |
1226 |
1227 | 1228 |
1229 |
1230 |
23天18-09-03 13:40
Cn59.32.37.110808 1241 | 广东河源 1242 | 高匿HTTPS 1246 |
1247 |
1248 | 1249 |
1250 |
1251 |
1253 |
1254 |
1255 | 1256 |
1257 |
1258 |
67天18-09-03 13:33
Cn221.234.251.1388010 1269 | 湖北武汉 1270 | 高匿HTTPS 1274 |
1275 |
1276 | 1277 |
1278 |
1279 |
1281 |
1282 |
1283 | 1284 |
1285 |
1286 |
1分钟18-09-03 13:22
Cn114.246.235.1828118 1297 | 北京 1298 | 高匿HTTP 1302 |
1303 |
1304 | 1305 |
1306 |
1307 |
1309 |
1310 |
1311 | 1312 |
1313 |
1314 |
1小时18-09-03 13:16
Cn175.148.73.471133 1325 | 辽宁葫芦岛 1326 | 高匿HTTPS 1330 |
1331 |
1332 | 1333 |
1334 |
1335 |
1337 |
1338 |
1339 | 1340 |
1341 |
1342 |
1分钟18-09-03 12:55
Cn222.94.148.2393128 1353 | 江苏南京 1354 | 高匿HTTP 1358 |
1359 |
1360 | 1361 |
1362 |
1363 |
1365 |
1366 |
1367 | 1368 |
1369 |
1370 |
1分钟18-09-03 12:30
Cn121.228.49.1983128 1381 | 江苏苏州 1382 | 高匿HTTPS 1386 |
1387 |
1388 | 1389 |
1390 |
1391 |
1393 |
1394 |
1395 | 1396 |
1397 |
1398 |
1小时18-09-03 12:24
Cn106.56.102.1228070 1409 | 云南 1410 | 高匿HTTPS 1414 |
1415 |
1416 | 1417 |
1418 |
1419 |
1421 |
1422 |
1423 | 1424 |
1425 |
1426 |
7小时18-09-03 12:23
Cn115.46.89.1108123 1437 | 广西南宁 1438 | 高匿HTTPS 1442 |
1443 |
1444 | 1445 |
1446 |
1447 |
1449 |
1450 |
1451 | 1452 |
1453 |
1454 |
1分钟18-09-03 12:22
Cn180.121.133.1003128 1465 | 江苏南通 1466 | 高匿HTTP 1470 |
1471 |
1472 | 1473 |
1474 |
1475 |
1477 |
1478 |
1479 | 1480 |
1481 |
1482 |
1分钟18-09-03 12:15
Cn106.56.102.68070 1493 | 云南 1494 | 高匿HTTP 1498 |
1499 |
1500 | 1501 |
1502 |
1503 |
1505 |
1506 |
1507 | 1508 |
1509 |
1510 |
103天18-09-03 12:14
Cn49.77.61.258123 1521 | 江苏 1522 | 高匿HTTP 1526 |
1527 |
1528 | 1529 |
1530 |
1531 |
1533 |
1534 |
1535 | 1536 |
1537 |
1538 |
1分钟18-09-03 12:00
Cn182.88.189.1358123 1549 | 广西南宁 1550 | 高匿HTTPS 1554 |
1555 |
1556 | 1557 |
1558 |
1559 |
1561 |
1562 |
1563 | 1564 |
1565 |
1566 |
39分钟18-09-03 11:51
Cn119.5.1.16808 1577 | 四川南充 1578 | 高匿HTTP 1582 |
1583 |
1584 | 1585 |
1586 |
1587 |
1589 |
1590 |
1591 | 1592 |
1593 |
1594 |
549天18-09-03 11:45
Cn121.225.25.1933128 1605 | 江苏南京 1606 | 高匿HTTP 1610 |
1611 |
1612 | 1613 |
1614 |
1615 |
1617 |
1618 |
1619 | 1620 |
1621 |
1622 |
1631 |
1632 |
1633 | 1634 |
1635 |
1636 |
1分钟18-09-03 09:30
Cn115.46.70.1808123 1647 | 广西南宁 1648 | 高匿HTTPS 1652 |
1653 |
1654 | 1655 |
1656 |
1657 |
1659 |
1660 |
1661 | 1662 |
1663 |
1664 |
10分钟18-09-03 09:11
Cn111.155.116.1968123 1675 | 北京 1676 | 高匿HTTP 1680 |
1681 |
1682 | 1683 |
1684 |
1685 |
1687 |
1688 |
1689 | 1690 |
1691 |
1692 |
755天18-09-03 09:00
Cn115.151.2.249808 1703 | 江西宜春 1704 | 高匿HTTPS 1708 |
1709 |
1710 | 1711 |
1712 |
1713 |
1715 |
1716 |
1717 | 1718 |
1719 |
1720 |
460天18-09-03 09:00
Cn171.113.158.1438010 1731 | 湖北 1732 | 高匿HTTPS 1736 |
1737 |
1738 | 1739 |
1740 |
1741 |
1743 |
1744 |
1745 | 1746 |
1747 |
1748 |
2分钟18-09-03 08:46
Cn115.46.72.1738123 1759 | 广西南宁 1760 | 高匿HTTP 1764 |
1765 |
1766 | 1767 |
1768 |
1769 |
1771 |
1772 |
1773 | 1774 |
1775 |
1776 |
1分钟18-09-03 08:46
Cn125.120.11.1606666 1787 | 浙江杭州 1788 | 高匿HTTPS 1792 |
1793 |
1794 | 1795 |
1796 |
1797 |
1799 |
1800 |
1801 | 1802 |
1803 |
1804 |
84天18-09-03 08:33
Cn106.56.102.468070 1815 | 云南 1816 | 高匿HTTP 1820 |
1821 |
1822 | 1823 |
1824 |
1825 |
1827 |
1828 |
1829 | 1830 |
1831 |
1832 |
73天18-09-03 08:22
Cn115.46.78.1518123 1843 | 广西南宁 1844 | 高匿HTTPS 1848 |
1849 |
1850 | 1851 |
1852 |
1853 |
1855 |
1856 |
1857 | 1858 |
1859 |
1860 |
337天18-09-03 08:16
Cn106.56.102.79808 1871 | 云南 1872 | 高匿HTTP 1876 |
1877 |
1878 | 1879 |
1880 |
1881 |
1883 |
1884 |
1885 | 1886 |
1887 |
1888 |
86天18-09-03 08:15
Cn123.180.69.1058010 1899 | 河北邢台 1900 | 高匿HTTP 1904 |
1905 |
1906 | 1907 |
1908 |
1909 |
1911 |
1912 |
1913 | 1914 |
1915 |
1916 |
169天18-09-03 08:14
Cn106.56.102.2468070 1927 | 云南 1928 | 高匿HTTPS 1932 |
1933 |
1934 | 1935 |
1936 |
1937 |
1939 |
1940 |
1941 | 1942 |
1943 |
1944 |
57天18-09-03 08:11
Cn115.217.243.84808 1955 | 浙江宁波 1956 | 高匿HTTPS 1960 |
1961 |
1962 | 1963 |
1964 |
1965 |
1967 |
1968 |
1969 | 1970 |
1971 |
1972 |
5分钟18-09-03 07:50
Cn60.177.226.958010 1983 | 浙江杭州 1984 | 高匿HTTPS 1988 |
1989 |
1990 | 1991 |
1992 |
1993 |
1995 |
1996 |
1997 | 1998 |
1999 |
2000 |
3小时18-09-03 07:44
Cn58.51.83.102808 2011 | 湖北襄阳 2012 | 高匿HTTP 2016 |
2017 |
2018 | 2019 |
2020 |
2021 |
2023 |
2024 |
2025 | 2026 |
2027 |
2028 |
925天18-09-03 07:31
Cn175.155.141.72808 2039 | 四川德阳 2040 | 高匿HTTPS 2044 |
2045 |
2046 | 2047 |
2048 |
2049 |
2051 |
2052 |
2053 | 2054 |
2055 |
2056 |
471天18-09-03 07:11
Cn222.188.250.162808 2067 | 江苏常州 2068 | 高匿HTTP 2072 |
2073 |
2074 | 2075 |
2076 |
2077 |
2079 |
2080 |
2081 | 2082 |
2083 |
2084 |
10分钟18-09-03 07:10
Cn42.59.86.1371133 2095 | 辽宁 2096 | 高匿HTTPS 2100 |
2101 |
2102 | 2103 |
2104 |
2105 |
2107 |
2108 |
2109 | 2110 |
2111 |
2112 |
169天18-09-03 07:00
Cn60.205.213.1728118 2123 | 广东深圳 2124 | 高匿HTTPS 2128 |
2129 |
2130 | 2131 |
2132 |
2133 |
2135 |
2136 |
2137 | 2138 |
2139 |
2140 |
36天18-09-03 06:33
Cn121.228.52.2343128 2151 | 江苏苏州 2152 | 高匿HTTPS 2156 |
2157 |
2158 | 2159 |
2160 |
2161 |
2163 |
2164 |
2165 | 2166 |
2167 |
2168 |
1分钟18-09-03 06:33
Cn106.56.102.1528070 2179 | 云南 2180 | 高匿HTTP 2184 |
2185 |
2186 | 2187 |
2188 |
2189 |
2191 |
2192 |
2193 | 2194 |
2195 |
2196 |
70天18-09-03 06:33
Cn122.241.72.1238070 2207 | 浙江丽水 2208 | 高匿HTTPS 2212 |
2213 |
2214 | 2215 |
2216 |
2217 |
2219 |
2220 |
2221 | 2222 |
2223 |
2224 |
126天18-09-03 06:13
Cn113.122.0.448010 2235 | 山东菏泽 2236 | 高匿HTTPS 2240 |
2241 |
2242 | 2243 |
2244 |
2245 |
2247 |
2248 |
2249 | 2250 |
2251 |
2252 |
126天18-09-03 06:01
Cn221.232.195.118010 2263 | 湖北武汉市武昌区 2264 | 高匿HTTPS 2268 |
2269 |
2270 | 2271 |
2272 |
2273 |
2275 |
2276 |
2277 | 2278 |
2279 |
2280 |
14天18-09-03 05:33
Cn183.151.42.2198070 2291 | 浙江丽水 2292 | 高匿HTTP 2296 |
2297 |
2298 | 2299 |
2300 |
2301 |
2303 |
2304 |
2305 | 2306 |
2307 |
2308 |
76天18-09-03 05:30
Cn171.37.156.2138123 2319 | 广西 2320 | 高匿HTTP 2324 |
2325 |
2326 | 2327 |
2328 |
2329 |
2331 |
2332 |
2333 | 2334 |
2335 |
2336 |
21分钟18-09-03 04:51
Cn175.155.70.21153128 2347 | 四川德阳 2348 | 高匿HTTP 2352 |
2353 |
2354 | 2355 |
2356 |
2357 |
2359 |
2360 |
2361 | 2362 |
2363 |
2364 |
1分钟18-09-03 04:45
Cn119.5.0.4808 2375 | 四川南充 2376 | 高匿HTTP 2380 |
2381 |
2382 | 2383 |
2384 |
2385 |
2387 |
2388 |
2389 | 2390 |
2391 |
2392 |
533天18-09-03 04:33
2400 | 2401 | 2402 | 2403 |
2404 | 2405 | 2406 | 2412 |
2413 |
2414 | 2415 | 2424 | 2425 |
2426 | 2427 | -------------------------------------------------------------------------------- /测试/测试_小说下载.py: -------------------------------------------------------------------------------- 1 | import cflw小说下载 as 小说下载 2 | import 小说下载.求书网 as 求书网 3 | import 小说下载.笔趣看 as 笔趣看 4 | import 小说下载.笔趣阁 as 笔趣阁 5 | import 小说下载.顶点小说 as 顶点小说 6 | import 小说下载.无限小说网 as 无限小说网 7 | def f获取小说(): 8 | #v小说 = 笔趣看.f获取小说("http://www.biqukan.com/2_2844/") 9 | #v小说 = 求书网.f获取小说("http://www.qiushu.cc/txt74524/") 10 | # v小说 = 顶点小说.f获取小说("https://www.23us.so/xiaoshuo/3574.html") 11 | # v小说 = 无限小说网.f获取小说("http://www.555x.org/read/45842.html") 12 | v小说 = 笔趣阁.f获取小说("http://www.biqutxt.com/0_310/") 13 | return v小说 14 | def f获取章节(): 15 | # v章节 = 顶点小说.C章节(*顶点小说.f提取链接("https://www.23us.so/files/article/html/3/3574/11462885.html")) 16 | # v章节 = 无限小说网.C章节(*无限小说网.f提取链接("http://www.555x.org/read/45842_1.html")) 17 | v章节 = 笔趣阁.C章节(*笔趣阁.f提取链接("http://www.biqutxt.com/0_310/186398.html")) 18 | return v章节 19 | def f一键下载(): 20 | v小说 = f获取小说() 21 | 小说下载.f一键下载(v小说, "d:/") 22 | def f小说信息(): 23 | v小说 = f获取小说() 24 | print(v小说.fg小说信息()) 25 | def f目录(): 26 | v小说 = f获取小说() 27 | for v in v小说.fe目录(): 28 | print(v[0], v[1].fg地址()) 29 | def f正文(): 30 | v章节 = f获取章节() 31 | v正文 = v章节.fg正文() 32 | print(v正文) 33 | def main(): 34 | f目录() 35 | # f正文() 36 | if __name__ == "__main__": 37 | main() -------------------------------------------------------------------------------- /测试/测试_矩阵.py: -------------------------------------------------------------------------------- 1 | import cflw数学_矩阵 as 矩阵 2 | def f相乘(): 3 | m1 = 矩阵.S矩阵4([ 4 | 1, 0, 0, 0, 5 | 0, "cx", "sx", 0, 6 | 0, "-sx", "cx", 0, 7 | 0, 0, 0, 1 8 | ]) 9 | m2 = 矩阵.S矩阵4([ 10 | "cy", 0, "-sy", 0, 11 | 0, 1, 0, 0, 12 | "sy", 0, "cy", 0, 13 | 0, 0, 0, 1 14 | ]) 15 | m3 = 矩阵.S矩阵4([ 16 | "cz", "sz", 0, 0, 17 | "-sz", "cz", 0, 0, 18 | 0, 0, 1, 0, 19 | 0, 0, 0, 1 20 | ]) 21 | print(m1 * m2, m1 * m3, m2 * m3, m1 * m2 * m3, sep = '') 22 | def main(): 23 | f相乘() 24 | if __name__ == "__main__": 25 | main() -------------------------------------------------------------------------------- /测试/测试_解析参数.py: -------------------------------------------------------------------------------- 1 | import cflw控制台 as 控制台 2 | def main(): 3 | v解析参数 = 控制台.C参数解析器() 4 | v解析参数.f添加参数("-a", a类型 = int) 5 | v = v解析参数.f解析参数("-a 1") 6 | print(v) 7 | if __name__ == "__main__": 8 | main() -------------------------------------------------------------------------------- /程序/图片提取水印.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pathlib 3 | from PIL import Image #pillow 4 | import cflw代码库py.cflw图像 as 图像 5 | def main(): 6 | v图像路径 = sys.argv[1] 7 | v图像 = Image.open(v图像路径) 8 | #处理 9 | v图像 = 图像.f提取最低有效位水印(v图像) 10 | #保存 11 | v保存路径0 = pathlib.PurePath(v图像路径) 12 | v保存路径1 = pathlib.Path(v保存路径0.parent) / f"{v保存路径0.stem}_提取水印.png" 13 | print(f"保存到: {v保存路径1}") 14 | v图像.save(v保存路径1) 15 | if __name__ == "__main__": 16 | main() -------------------------------------------------------------------------------- /程序/图片添加水印.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pathlib 3 | from PIL import Image #pillow 4 | import cflw代码库py.cflw图像 as 图像 5 | def main(): 6 | v图像路径 = sys.argv[1] 7 | v水印路径 = sys.argv[2] 8 | v图像 = Image.open(v图像路径) 9 | v水印 = Image.open(v水印路径) 10 | #处理 11 | v水印 = 图像.f平铺图像(v水印, v图像.size) 12 | v图像 = 图像.f添加最低有效位水印(v图像, v水印) 13 | #保存 14 | v保存路径0 = pathlib.PurePath(v图像路径) 15 | v保存路径1 = pathlib.Path(v保存路径0.parent) / f"{v保存路径0.stem}_添加水印.png" 16 | print(f"保存到: {v保存路径1}") 17 | v图像.save(v保存路径1) 18 | if __name__ == "__main__": 19 | main() --------------------------------------------------------------------------------