吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2348|回复: 24
收起左侧

[Python 原创] python全版本绿色发行包下载脚本

[复制链接]
ashi876 发表于 2026-2-21 09:13
astral-sh / python-build-standalone
Astral 是知名的 Python 工具开发商,开发了 Ruff(极快的 Python linter/formatter)和 uv(极快的 Python 包安装器)。python-build-standalone 最初是 indygreg 创建的项目,后来由 Astral 接手维护,现在被 uv 内部使用来管理 Python 版本。官方的便携包缺少tk及pip模块等等,所以要么选择抽取安装包。而astral-sh / python-build-standalone项目是目前比较可靠的发布包
注意项目现在并不包含alpha版,如果想体验最新测试版还是去官方
使用中注意项目是github的下载地址,在国内有可能被墙

[Python] 纯文本查看 复制代码
#!/usr/bin/env python3
[mw_shl_code=python,true]#!/usr/bin/env python3
"""
Python 预编译版本下载器 for Windows
使用 Python 标准库,无需安装额外依赖
按原版 mise 顺序排序:3.8 → 3.9 → 3.10 → 3.11 → 3.12 → 3.13 → 3.14 → 3.15
每个大版本内按版本号升序(旧到新)
"""

import urllib.request
import urllib.error
import gzip  导入 GZIP
import re
import os
import ssl  导入 SSL 格式
from typing import List, Tuple, Dict
from collections import defaultdict

# 配置
INDEX_URL = "https://mise-versions.jdx.dev/tools/python-precompiled-x86_64-pc-windows-msvc.gz"
INDEX_URL = “https://mise-versions.jdx.dev/tools/python-precompiled-x86_64-pc-windows-msvc.gz”
TIMEOUT = 30  暂停 = 30

# 处理 SSL 证书问题(Windows 上有时需要)
ssl_context = ssl.create_default_context()
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE

def get_version_list() -> List[Tuple[str, str, str]]:
def get_version_list() -> 列表[元组[p, p, p]]:
    """获取并解析版本列表,每个版本只保留最新日期的构建"""
    print(f"正在获取版本列表...")
    
    try:  试试:
        # 创建请求对象
        req = urllib.request.Request(
            INDEX_URL,  INDEX_URL,
            headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
        )
        
        # 下载 gz 文件
        with urllib.request.urlopen(req, timeout=TIMEOUT, context=ssl_context) as response:
响应为 urllib.request.urlopen(req, timeout=TIMEOUT, context=ssl_context):
            compressed_data = response.read()
compressed_data = response.read()
        
        # 解压
        content = gzip.decompress(compressed_data).decode('utf-8')
Content = gzip.decompress(compressed_data).decode('UTF-8')
        
        # 按版本号分组收集所有构建
        version_groups = defaultdict(list)
version_groups = defaultdict(列表)
        pattern = r'^cpython-(\d+\.\d+\.\d+[a-z]*)\+(\d+)-x86_64-pc-windows-msvc(.*)\.tar\.gz$'
pattern = r'^cpython-(\d+\.\d+\.\d+[A-Z]*)\+(\d+)-x86_64-PC-Windows-MSVC(.*)\.tar\.gz$'
        
        for line in content.strip().split('\n'):
对于 content.strip().split('\n'')中的行:
            match = re.match(pattern, line)
匹配 = 重新匹配(模式,线)
            if match:  如果匹配:
                version = match.group(1)      # 3.13.5
版本 = match.group(1) # 3.13.5
                date = match.group(2)         # 20250723
日期 = match.group(2) # 20250723
                suffix = match.group(3)       # -install_only_stripped 等
后缀 = match.group(3) # -install_only_stripped 等
                filename = f"cpython-{version}+{date}-x86_64-pc-windows-msvc{suffix}.tar.gz"
FileName = f“cpython-{version}+{date}-x86_64-pc-windows-msvc{suffix}.tar.gz”
                
                # 按版本分组收集
                version_groups[version].append((version, date, filename))
        
        # 对每个版本,只保留日期最新的那个
        latest_versions = []
        for version, builds in version_groups.items():
            # 按日期排序,取最新的
            latest_build = max(builds, key=lambda x: x[1])  # x[1] 是日期字符串
            latest_versions.append(latest_build)
        
        if not latest_versions:
            print("警告: 没有解析到任何版本,可能格式已变更")
            print("前5行原始数据:")
            for line in content.strip().split('\n')[:5]:
                print(f"  {line}")
        
        print(f"成功获取 {len(latest_versions)} 个版本(每个版本仅保留最新构建)")
        return latest_versions
    
    except urllib.error.URLError as e:
        print(f"网络连接失败: {e}")
        return []
    except Exception as e:
        print(f"获取版本列表失败: {e}")
        return []

def sort_versions(versions: List[Tuple[str, str, str]]) -> List[Tuple[str, str, str]]:
    """按原版 mise 顺序排序:3.8 → 3.9 → 3.10 → 3.11 → 3.12 → 3.13 → 3.14 → 3.15,每个大版本内按版本号升序"""
    
    # 按大版本分组
    major_groups = defaultdict(list)
    for v in versions:
        # 提取大版本号 (3.8, 3.9, 3.10, ...)
        major_parts = v[0].split('.')
        if len(major_parts) >= 2:
            major = f"{major_parts[0]}.{major_parts[1]}"
            major_groups[major].append(v)
    
    # 大版本顺序列表
    major_order = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14', '3.15']
    
    # 按顺序重组
    sorted_versions = []
    for major in major_order:
        if major in major_groups:
            # 每个大版本内按版本号升序排序
            # 需要将版本字符串转换为可比较的元组
            def version_key(v):
                parts = v[0].split('.')
                # 处理可能存在的字母后缀(如 3.13.0rc3)
                main_parts = []
                suffix = ''
                for p in parts:
                    match = re.match(r'^(\d+)([a-z]+\d*)?$', p)
                    if match:
                        main_parts.append(int(match.group(1)))
                        if match.group(2):
                            suffix = match.group(2)
                    else:
                        main_parts.append(0)
                # 补足到3个数字部分
                while len(main_parts) < 3:
                    main_parts.append(0)
                return (main_parts[0], main_parts[1], main_parts[2], suffix)
            
            sorted_group = sorted(major_groups[major], key=version_key)
            sorted_versions.extend(sorted_group)
    
    return sorted_versions

def group_by_major(versions: List[Tuple[str, str, str]]) -> Dict[str, List[Tuple[str, str, str]]]:
    """按大版本分组 (3.13, 3.12, ...)"""
    groups = defaultdict(list)
    for v in versions:
        # 提取大版本号 (3.13)
        major = '.'.join(v[0].split('.')[:2])
        groups[major].append(v)
    return groups

def get_latest_of_each_major(versions: List[Tuple[str, str, str]]) -> List[Tuple[str, str, str]]:
    """获取每个大版本的最新版本"""
    groups = group_by_major(versions)
    latest = []
    
    # 大版本顺序
    major_order = ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14', '3.15']
    
    for major in major_order:
        if major in groups:
            # 每个大版本内按版本号升序,取最后一个(最新的)
            def version_key(v):
                parts = v[0].split('.')
                main_parts = []
                for p in parts:
                    match = re.match(r'^(\d+)', p)
                    if match:
                        main_parts.append(int(match.group(1)))
                    else:
                        main_parts.append(0)
                while len(main_parts) < 3:
                    main_parts.append(0)
                return (main_parts[0], main_parts[1], main_parts[2])
            
            sorted_group = sorted(groups[major], key=version_key)
            latest.append(sorted_group[-1])  # 取最后一个(最新)
    
    return latest

def display_versions(versions: List[Tuple[str, str, str]], show_all: bool = False):
    """显示版本列表"""
    print("\nPython 版本列表:")
    
    if show_all:
        # 显示所有版本(按原版顺序)
        for i, (ver, date, _) in enumerate(versions, 1):
            print(f"{i:3}. Python {ver} ({date})")
        print(f"\n总共 {len(versions)} 个版本")
    else:
        # 只显示每个大版本的最新版本
        latest = get_latest_of_each_major(versions)
        for i, (ver, date, _) in enumerate(latest, 1):
            print(f"{i:3}. Python {ver} (最新, {date})")
        
        print(f"\n{'='*50}")
        print("提示: 输入 'a' 查看所有历史小版本")

def download_file(url: str, filename: str):
    """下载文件并显示进度"""
    print(f"\n开始下载: {filename}")
    
    try:
        # 创建请求对象
        req = urllib.request.Request(
            url,
            headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}
        )
        
        # 下载文件
        with urllib.request.urlopen(req, timeout=TIMEOUT, context=ssl_context) as response:
            # 获取文件大小
            total_size = int(response.headers.get('Content-Length', 0))
            downloaded = 0
            chunk_size = 8192
            
            with open(filename, 'wb') as f:
                while True:
                    chunk = response.read(chunk_size)
                    if not chunk:
                        break
                    f.write(chunk)
                    downloaded += len(chunk)
                    
                    # 显示进度
                    if total_size > 0:
                        percent = downloaded * 100 / total_size
                        print(f"\r进度: {percent:.1f}% ({downloaded}/{total_size} bytes)", end='')
        
        print(f"\n下载完成: {filename}")
        print(f"保存位置: {os.path.abspath(filename)}")
        return True
        
    except urllib.error.HTTPError as e:
        print(f"\nHTTP错误 {e.code}: {e.reason}")
        return False
    except urllib.error.URLError as e:
        print(f"\n网络错误: {e.reason}")
        return False
    except Exception as e:
        print(f"\n下载失败: {e}")
        return False

def main():
    print("Python 预编译版本下载器 (for Windows)")
    print("=" * 50)
    
    # 获取版本列表
    all_versions = get_version_list()
    if not all_versions:
        print("没有获取到任何版本,退出")
        input("按回车键退出...")
        return
    
    # 按原版顺序排序
    all_versions = sort_versions(all_versions)
    
    # 交互循环
    show_all = False
    while True:
        display_versions(all_versions, show_all)
        
        choice = input("\n请输入编号 (或 'a' 切换显示模式, 'q' 退出): ").strip()
        
        if choice.lower() == 'q':
            print("退出")
            break
        
        elif choice.lower() == 'a':
            show_all = not show_all
            continue
        
        try:
            idx = int(choice) - 1
            
            # 根据当前显示模式获取对应的版本列表
            if show_all:
                selected_versions = all_versions
            else:
                selected_versions = get_latest_of_each_major(all_versions)
            
            if 0 <= idx < len(selected_versions):
                ver, date, filename = selected_versions[idx]
                
                # 构建下载 URL
                download_url = f"https://github.com/astral-sh/python-build-standalone/releases/download/{date}/{filename}"
                
                # 确认下载
                confirm = input(f"\n确认下载 Python {ver}? (y/n): ").strip().lower()
                if confirm == 'y':
                    download_file(download_url, filename)
                else:
                    print("取消下载")
                
                # 下载完成后询问是否继续
                cont = input("\n是否继续选择? (y/n): ").strip().lower()
                if cont != 'y':
                    print("退出")
                    break
            else:
                print("无效编号,请重新输入")
                
        except ValueError:
            print("请输入有效的数字编号")
    
    input("按回车键退出...")

if __name__ == "__main__":
    main()





02.png
01.png

免费评分

参与人数 5吾爱币 +11 热心值 +4 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
1588 + 1 + 1 热心回复!
flyer_2001 + 1 + 1 谢谢@Thanks!
pyjiujiu + 1 谢谢@Thanks!
52菜鸟 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

h1jacker 发表于 2026-2-21 11:06
ashi876 发表于 2026-2-21 10:57
争这个没意思,我并不否认uv很好,但用pip的人一样很多

顺便提一嘴,这个python绿色版本在国内其实是有镜像站做了相关的镜像的,国内下载访问更方便了
https://mirror.nju.edu.cn/github-release/astral-sh/python-build-standalone/
PythonPan 发表于 2026-2-21 09:45
既然是从github下载(速度随缘),直接用uv不是更简单吗?
image.png
pyjiujiu 发表于 2026-2-21 11:03
谢分享,uv 的 python 维护,文档说是跟 uv 跑的,需要 uv版本 不停更新(才能下到更新的)
且 uv 下载的python,是当附件用的,也不准加入第三方库(当然这是 feature,设计理念),如果直接从git 可下的话,或许可以更新 本人之前写的 pip 离线下载的项目,让其支持不同python版本 同时下载
asdr7503 发表于 2026-2-21 09:32
谢谢lz,最近刚好在配环境用得上
daymissed 发表于 2026-2-21 09:51
谢谢分享,电脑安装了低版本,有些时候要高版本就比较麻烦,有这个好了。
 楼主| ashi876 发表于 2026-2-21 09:56
PythonPan 发表于 2026-2-21 09:45
既然是从github下载(速度随缘),直接用uv不是更简单吗?

uv目前对python用户并不是必需品,
更主要的是这脚本是一个测试,我在把mise的所有下载接口抽取出来,
完成了这个脚本,可以模块复用,
然后下载绿色版的nodejs java go rust 然后集成到我的laxuhub管理器里
一个有人维护的多版本发行包仓库,一个综合性的脚本就可以搞定,多爽
msold5 发表于 2026-2-21 10:11
里面的错误符号是用专用软件故意替换的吗?
picoyiyi 发表于 2026-2-21 10:19
PythonPan 发表于 2026-2-21 09:45
既然是从github下载(速度随缘),直接用uv不是更简单吗?

邪修牛逼
yigesuren 发表于 2026-2-21 10:35
看起来不错,虽然不是太会用,有时间研究研究。
鑫子 发表于 2026-2-21 10:45
感谢分享,很好用
h1jacker 发表于 2026-2-21 10:56
ashi876 发表于 2026-2-21 09:56
uv目前对python用户并不是必需品,
更主要的是这脚本是一个测试,我在把mise的所有下载接口抽取出来,
...

对于python用户差不多已经是必需了,现在很多项目以及一些大厂的开源项目都开始用uv来部署了,未来是个趋势
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-5-27 15:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表