【自用】Python爬虫学习(六):通过m3u8文件下载ts文件并合并为.mp4文件

news2024/9/23 1:30:18

Python爬虫学习(六)

  • 下载视频(简单版)的步骤介绍
    • 第一步:在网页上找到.m3u8文件
    • 第二步:通过.m3u8文件下载对应的.ts视频文件
    • 第三步:依据.m3u8文件合并.ts文件为一个.mp4文件
  • 下载视频(复杂版)


下载视频(简单版)的步骤介绍

"""
<video src='视频.mp4"></video:>
一般的视频网站是怎么做的?
用户上传->转码(把视频做处理,2K,1080,标清)->切片处理(把单个的文件进行拆分,形成众多的.ts文件)

需要一个文件记录:1.视频播放顺序,2.视频存放的路径,这个文件就是m3u
m3u以utf-8编码存储就是m3u8文件,本质就是一个文本文件。
M3U8 txt json =>文本

想要抓取一个视频:
1.找到 m3u8(各种手段)
2.通过 m3u8下载到 ts文件(这里先不管.ts是否被加密)
3.通过各种手段(不仅是编程手段)把ts文件合并为一个mp4文件
"""

第一步:在网页上找到.m3u8文件

(这里假设网页对应的.m3u8文件没有进行加密、隐藏等处理,真实的.m3u8文件下载链接直接就在页面源码中)

import requests
import re

# 第一步,下载m3u8文件
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
}

# 测试网址,已经不能正常打开
url = "https://www.91kanju.com/vod-play/54812-1-1.html"  
# 用来提取找到m3u8的url地址的预加载正则表达式,需要根据具体网页情况编写合适的表达式
obj = re.compile(r"url: '(?P<url>.*?)',", re.S)  

resp = requests.get(url)
m3u8_url = obj.search(resp.text).group("url")  # 拿到m3u8的地址

# print(m3u8_url)
resp.close()

# 下载m3u8文件
resp2 = requests.get(m3u8_url, headers=headers)
with open("video.m3u8", mode="wb") as f:
    f.write(resp2.content)

resp2.close()
print("下载完毕")

第二步:通过.m3u8文件下载对应的.ts视频文件

上一步的网址不能打开,得不到对应的.m3u8文件,可以直接用下面的.m3u8文件进行测试。
测试链接:https://upyun.luckly-mjw.cn/Assets/media-source/example/media/index.m3u8
打开下载好的.m3u8文件如下所示,不带#的行就是.ts视频文件的下载地址,只需要对其进行发送请求就能下载得到对应的.ts视频文件。
注意:这里不同的.m3u8比较特殊,直接就是完整的下载链接,大部分只有部分文件名,需要根据网页通过一些手段找到对应的网站域名或者网址前缀。
在这里插入图片描述

# 第二步,解析m3u8文件
with open("data_file/index.m3u8", mode="r", encoding="utf-8") as f:
    for line in f:
        line = line.strip()  # 先去掉空格,空白,换行符
        if line.startswith("#"):  # 如果以#开头,跳过这一行
            continue

        # print(line)
        ts_name = line.split('/')[-1]  # test-1.ts

        resp3 = requests.get(line)
        f = open(f"data_file/video/{ts_name}", mode="wb")
        f.write(resp3.content)
        resp3.close()
        print(f"{ts_name},下载成功!")

第三步:依据.m3u8文件合并.ts文件为一个.mp4文件

注意:
1、.ts文件的名称要与# .m3u8文件记录的名称一样才可以利用下面的代码进行合并。
2、这个合并代码仅适用于Windows系统,合并二进制文件使用的是copy命令,对于mac系统应该使用cat命令,具体细节请“百度”。

import os
import subprocess


def merge_ts_to_mp4(m3u8_file, ts_folder_path, merge_video_name):
    # 检查m3u8文件路径是否存在
    if not os.path.isfile(m3u8_file):
        print(f"错误:m3u8文件 '{m3u8_file}' 不存在!")
        return

        # 检查ts文件夹路径是否存在
    if not os.path.isdir(ts_folder_path):
        print(f"错误:TS文件夹 '{ts_folder_path}' 不存在!")
        return

    lst = []
    try:
        with open(m3u8_file, mode='r', encoding='utf-8') as f:
            for line in f:
                if line.startswith('#'):
                    continue

                line = line.strip()  # 去掉空格和换行
                ts_name = line.split('/')[-1]  # 提取文件名

                ts_path = os.path.join(ts_folder_path, ts_name)  # 构建完整路径
                # 检查每个ts文件是否存在
                if os.path.isfile(ts_path):
                    lst.append(ts_path)
                else:
                    print(f"警告:TS文件 '{ts_path}' 不存在,将被跳过。")

        if not lst:
            print("没有有效的TS文件可供合并。")
            return

        temp_output_path = os.path.join(ts_folder_path, 'temp_output.ts')  # 临时文件路径
        total_ts_files = len(lst)

        print("开始合并视频文件...")
        for index, ts_file in enumerate(lst):
            command = f'copy /b "{temp_output_path}" + "{ts_file}" "{temp_output_path}"' if os.path.exists(
                temp_output_path) else f'copy /b "{ts_file}" "{temp_output_path}"'
            result = subprocess.run(command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

            if result.returncode == 0:
                percentage = (index + 1) * 100 / total_ts_files
                print(f"{percentage:.2f}% - 已合并: {index + 1}/{total_ts_files}")
            else:
                print(f"合并失败:{ts_file},跳过该文件。")

                # 最终重命名
        final_output_path = os.path.join(ts_folder_path, merge_video_name)
        os.rename(temp_output_path, final_output_path)  # 重命名临时文件为最终输出文件名

        # 完成合并后提示用户
        print(f"所有.ts文件已合并到:\n '{final_output_path}'。")

    except Exception as e:
        print(f"发生异常:{e}")


if __name__ == '__main__':
    # .m3u8文件路径
    m3u8_file = r'D:\User_Data\Documents\PycharmProjects\NewFile\data_file\index.m3u8'
    # 从.m3u8文件下载的.ts文件的目录路径,该目录下放置下载的众多.ts文件
    ts_folder_path = r'D:\User_Data\Documents\PycharmProjects\NewFile\data_file\video'
    # 最终合并的视频名称,放在与.ts文件相同的目录下
    merge_video_name = 'ts视频合并.mp4'
    merge_ts_to_mp4(m3u8_file, ts_folder_path, merge_video_name)

运行结果如下所示:
在这里插入图片描述

下载视频(复杂版)

思路:

  1. 拿到主页面的页面源代码,找到iframe
  2. 从iframe的页面源代码中拿到m3u8文件
  3. 下载第一层m3u8文件 -->下载第二层m3u8文件(真实的视频存放路径)
  4. 下载视频
  5. 下载miyao,进行jiemi操作
  6. 合并所有ts文件为一个mp4文件

注意:演示网址的视频没有jiemi,只是yincang了真实的.m3u8下载地址,不需要jiemi,对于需要jiemi的也有代码演示,代码不可直接运行,部分存在问题,重点是理清思路,实际需要具体情况具体分析。

"""
网页播放地址:
    https://www.555dy16.com/vodplay/128103-7-2/
iframe对应的网页地址:
    https://www.555dy16.com/player/?url=https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/index.m3u8&dianshiju&next=https://www.555dy16.com/vodplay/128103-7-3/
iframe里面的m3u8地址:
    https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/index.m3u8
抓包里面的m3u8地址:
第一个
    https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/index.m3u8
    预览:
    #EXTM3U
    #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=933000,RESOLUTION=1280x720
    /20240808/s1aDNcWE/933kb/hls/index.m3u8
第二个
    https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/933kb/hls/index.m3u8
    预览:
    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:2
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXT-X-MEDIA-SEQUENCE:0
    #EXTINF:1,
    /20240808/s1aDNcWE/933kb/hls/8IfxeFcu.ts
    #EXTINF:1,
    /20240808/s1aDNcWE/933kb/hls/d4F8NT9f.ts
    #EXTINF:1,
    /20240808/s1aDNcWE/933kb/hls/W8uFMNJv.ts
    ……

"""
import re
import os
import requests
import asyncio
import aiohttp
import aiofiles
import subprocess
from bs4 import BeautifulSoup
from Crypto.Cipher import AES

# 代码想要正常运行需要对一些位置进行适当修改,切勿直接运行!
# 对某网页的视频进行下载

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0"
}


def get_iframe_src(url):
    # resp = requests.get(url, headers=headers)
    # resp.encoding = 'utf-8'
    # print(resp.text)

    # main_page = BeautifulSoup(resp.text, "html.parser")
    # iframe_src = main_page.find('iframe').get('src')

    # 网页原因不能找到iframe,先直接给定
    iframe_src = 'https://www.555dy16.com/player/?url=https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/index.m3u8&dianshiju&next=https://www.555dy16.com/vodplay/128103-7-3/'
    print(iframe_src)
    return iframe_src


def get_first_m3u8_url(url):
    resp = requests.get(url, headers=headers)
    resp.encoding = 'utf-8'
    # print(resp.text)
    resp_html = resp.text

    obj = re.compile(r'"url": "(?P<m3u8_url>.*?)"', re.S)

    m3u8_url = obj.search(resp_html).group('m3u8_url')
    print(m3u8_url)
    return m3u8_url


def download_m3u8_file(url, file_name):
    resp = requests.get(url, headers=headers)
    with open('data_file/' + file_name, mode='wb') as f:
        f.write(resp.content)
    print(f"'{file_name}' 下载成功!")


async def download_ts(ts_url, ts_name, session):
    async with session.get(ts_url) as resp:
        async with aiofiles.open(f'data_file/video_ts/{ts_name}', mode='wb') as f:
            await f.write(await resp.content.read())  # 下载到的内容写入到文件
    print(f"{ts_name} 下载完成!")


async def aio_download(up_url):
    tasks = []
    async with aiohttp.ClientSession() as session:  # 提前准备好session
        async with aiofiles.open('data_file/' + "second_m3u8.txt", mode='r', encoding='utf-8') as f:
            async for line in f:
                if line.startswith('#'):  # 可能pycharm提示高亮,实际运行没有问题,不必理会
                    continue

                line = line.strip()  # 去掉没用的空格和换行
                # /20240808/s1aDNcWE/933kb/hls/8IfxeFcu.ts
                ts_name = line.split('/')[-1]
                # 8IfxeFcu.ts

                # 拼接得到真正的ts下载路径
                ts_url = up_url + line
                # https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/933kb/hls/8IfxeFcu.ts

                task = asyncio.create_task(download_ts(ts_url, ts_name, session))  # 创建任务
                tasks.append(task)

            await asyncio.wait(tasks)  # 等待任务结束


def merge_ts_to_mp4():
    # mac: cat 1.ts 2.ts 3.ts > xxx mp4
    # windows: copy /b 1.ts+2.ts+3.ts xxx.mp4

    lst = []
    with open('data_file/' + "second_m3u8.txt", mode='r', encoding='utf-8') as f:
        for line in f:
            # line = await line  # 确保获取的是字符串
            if line.startswith('#'):
                continue

            line = line.strip()  # 去掉没用的空格和换行
            # /20240808/s1aDNcWE/933kb/hls/8IfxeFcu.ts
            ts_name = line.split('/')[-1]
            # 8IfxeFcu.ts

            ts_path = 'data_file/video_ts/' + ts_name  # 构建完整路径
            # data_file/video_ts/8IfxeFcu.ts

            lst.append(ts_path)

    # Windows系统使用copy命令
    temp_output_path = os.path.join('data_file/video_ts', 'temp_output.ts')  # 临时文件路径
    total_ts_files = len(lst)  # 所有的ts文件数量

    print("开始合并.ts视频文件...")
    for index, ts_file in enumerate(lst):
        # 使用加号连接文件名,Windows系统使用copy命令
        command = f'copy /b "{temp_output_path}" + "{ts_file}" "{temp_output_path}"' if os.path.exists(
            temp_output_path) else f'copy /b "{ts_file}" "{temp_output_path}"'

        result = subprocess.run(command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

        if result.returncode == 0:
            percentage = (index + 1) * 100 / total_ts_files
            print(f"{percentage:.2f}% - 已合并: {index + 1}/{total_ts_files}")
        else:
            print(f"合并失败:{ts_file},跳过该文件。")

            # 最终重命名
    final_output_path = os.path.join('data_file/video_ts', 'movies.mp4')
    os.rename(temp_output_path, final_output_path)  # 重命名临时文件为最终输出文件名


def main(url):
    # 1.拿到主页面的页面源代码,找到iframe对应的url
    iframe_src = get_iframe_src(url)
    # https://www.555dy16.com/player/?url=https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/index.m3u8&dianshiju&next=https://www.555dy16.com/vodplay/128103-7-3/

    # 2.拿到第一层的m3u8文件的下载地址,看具体情况对拿到的地址进行拼接处理
    first_m3u8_url = get_first_m3u8_url(iframe_src)
    # https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/index.m3u8
    m3u8_domain = first_m3u8_url.split('.com')[0] + '.com'

    # 3.1.下载第一层m3u8文件
    first_txt_filename = "first_m3u8.txt"
    download_m3u8_file(first_m3u8_url, first_txt_filename)

    # 3.2.下载第二层m3u8文件
    with open('data_file/' + first_txt_filename, mode='r', encoding='utf-8') as f:
        for line in f:
            if line.startswith('#'):
                continue
            else:
                # 去掉空白或者换行符
                line = line.strip()  # /20240808/s1aDNcWE/933kb/hls/index.m3u8
                # 拼接第二层m3u8的下载地址
                second_m3u8_url = m3u8_domain + line
                # https://vip.kuaikan-cdn4.com/20240808/s1aDNcWE/933kb/hls/index.m3u8

                print(second_m3u8_url)
                # 下载第二层m3u8文件
                second_txt_filename = "second_m3u8.txt"
                download_m3u8_file(second_m3u8_url, second_txt_filename)

    # 4.下载视频
    ts_domain_url = 'https://vip.kuaikan-cdn4.com'
    # 异步协程
    asyncio.run(aio_download(ts_domain_url))

    # =======================这一部分看网站m3u8文件具体情况,是否需要解密==========================
    # 关注.m3u8文件是否包含这一行:#EXT-X-KEY:METHOD=AES-128,URI="Key.Key",
    # 有代表不能直接对下载的.ts文件进行合并,合并前需要对.ts文件进行解密,对解密后的.ts文件进行合并
    # 5.1 拿到秘钥  (后面内容仅做示范,代码不可运行,需要具体情况具体分析,为了方便理顺流程这部分函数与代码直接写在一起)
    def get_key(url):
        resp = requests.get(url)
        # print(resp.text)  # c5878c26baaaac8c,会得到诸如注释类似格式的文本
        return resp.text

    key_url = 'https://vip.kuaikan-cdn4.com/……/key.key'  # 要从m3u8文件里去获取
    key = get_key(key_url)

    # 5.2 解密    (要对下载的每一个.ts文件进行解密,需要使用异步协程提高效率)

    async def dec_ts(ts_name, key):
        aes = AES.new(key=key, IV=b"0000000000000000", mode=AES.MODE_CBC)
        async with aiofiles.open(f'data_file/video_ts/{ts_name}', mode="rb") as f1, \
                aiofiles.open(f'data_file/video_ts/temp_{ts_name}', mode="wb") as f2:
            bs = await f1.read()  # 从源文件读取内容
            await f2.write(aes.decrypt(bs))  # 把解密好的内容写入文件
        print(f'temp_{ts_name} 处理完毕!')

    async def aio_dec(key):
        # 解密
        tasks = []
        async with aiofiles.open('data_file/' + "second_m3u8.txt", mode='r', encoding='utf-8') as f:
            async for line in f:
                # line = await line  # 确保获取的是字符串
                if line.startswith('#'):
                    continue

                line = line.strip()  # 去掉没用的空格和换行
                # /20240808/s1aDNcWE/933kb/hls/8IfxeFcu.ts
                ts_name = line.split('/')[-1]
                # 8IfxeFcu.ts

                # 开始创建异步任务
                task = asyncio.create_task(dec_ts(ts_name, key))
                tasks.append(task)

            await asyncio.wait(tasks)  # 等待任务结束

        pass

    asyncio.run(aio_dec(key))

    # ======================================================================================

    # 6.合并ts文件
    merge_ts_to_mp4()  # 合并ts文件为mp4文件


# 主程序
if __name__ == '__main__':
    url = 'https://www.555dy16.com/vodplay/128103-7-2/'
    main(url)
    print("所有文件下载完毕!")

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

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

相关文章

stm32智能颜色送餐小车(oled显示压力传感器重量)

大家好啊&#xff0c;我是情谊&#xff0c;今天我们来介绍一下我最近设计的stm32产品&#xff0c;我们在今年七月份的时候参加了光电设计大赛&#xff0c;我们小队使用的就是stm32的智能送餐小车&#xff0c;虽然止步于省赛&#xff0c;但是还是一次成长的经验吧&#xff0c;那…

PyQt编程快速上手

Python GUI安装 GUI就是图形用户界面的意思&#xff0c;在Python中使用PyQt可以快速搭建自己的应用&#xff0c;使得自己的程序看上去更加高大上&#xff0c;学会GUI编程可以使得自己的软件有可视化的结果。 如果你想用Python快速制作界面&#xff0c;可以安装PyQt&#xff1a…

Linux云计算 |【第二阶段】NETWORK-DAY6

主要内容&#xff1a; 企业网络综合项目分析、大型企业网络搭建 项目案例1 一家网络公司&#xff0c;有若干服务器&#xff0c;通过NAT技术将业务服务器与Internet互联&#xff1b;已有技术&#xff1a; ① 默认路由&#xff1a;实现到互联网数以万计网络访问的简化配置&…

Elasticsearch自动补全功能实践与Java API应用

Elasticsearch是一个强大的搜索引擎&#xff0c;它不仅支持全文搜索&#xff0c;还提供了自动补全功能&#xff0c;可以显著提升用户体验。自动补全功能允许用户在输入查询时实时显示建议项&#xff0c;帮助用户快速找到所需信息。本文将介绍如何使用Elasticsearch的RestHighLe…

配置Google API,用JavaScript和Python读取Google sheet里的数据

[发布时间是2024年8月。技术流程可能会存在一些变动] 源代码可以参考&#xff1a;victorspaceRMW/Read-Google-Sheet-with-API: The source code to read the Google Sheet with Google cloud API (github.com) 开头提醒一下各位公司&#xff0c;国内包括腾讯云华为云阿里云&…

echarts使图表组件根据屏幕尺寸变更而重新渲染大小

效果图&#xff1a; 通过 window.addEventListener(resize, this.resizeChart); 实现 完整代码&#xff1a; <template><div class"dunBlock"><div class"char2" id"char2" ref"chart"></div></div…

《光与夜之恋》3D建模含量超标,纯炫技还是释放新信号?

继叠纸的《恋与深空》之后&#xff0c;腾讯的《光与夜之恋》也卷起3D技术了。 《光与夜之恋》即将在8月12日上线的限定活动“大漠归墟”最新PV及男主六星卡面释出&#xff0c;相对于褒贬不一、引起争论的卡面美术&#xff0c;PV中的3D建模倒是收获了玩家的集体好评。 “大漠归…

读零信任网络:在不可信网络中构建安全系统18零信任代理

1. 零信任代理 1.1. 零信任代理是应用级代理服务器&#xff0c;用来保护零信任网络&#xff0c;它是处理认证、授权以及加密的基础设施 1.2. 零信任代理分为反向代理和前向代理两种工作模式 1.2.1. 运行时可以同时采用这两种工作模式&#xff0c;也可以只采用其中的一种 1.2…

libcurl8.9.1 上传json

在postman中 PUT----》body----》raw----》json 结构体定义&#xff1a; #define MAX_ARRAY_SIZE 5*1024*1024struct SMART_DATA_CACHE {char* buf;long dwTotalLen;SMART_DATA_CACHE(){dwTotalLen 0;buf nullptr;while (!buf) {try {buf new char[MAX_ARRAY_SIZE];}c…

C++:有序关联容器set

什么是有序关联容器 (1)顺序容器&#xff0c;容器中的元素是按它们在容器中的位置来顺序保存和访问的(可以理解是数组) (2)顺序容器有array、vector、deque、list、forward_list、string等 (3)关联容器中的元素是按关键字来保存和访问的&#xff0c;关联的意思就是关键字&…

STM32-外部中断-AFIO-串口-串口通信-串口中断(空闲中断和接收中断)-printf移植-ADC数模转换-初始化和读取光敏电阻AO

常用的中断包括外部中断、串口中断、定时器中断&#xff1b; 1、外部中断&#xff1a; 引脚复用按钮导致的外部中断&#xff1a; 注意&#xff1a;初始化引脚&#xff0c;添加引脚和EXTI输入线的映射&#xff1b;使用外部引脚的中断时需要使用AFIO映射&#xff1b; 操作步骤&…

如何获取android的SHA1或SHA256

在使用地图类的功能时&#xff0c;例如百度地图或者高德地图&#xff0c;会需要在开发者平台里填写SHA1或SHA256的指纹密钥&#xff0c;很多开发者小伙伴还不知道如何获取。当然关于如何获取android的SHA1或SHA256&#xff0c;网络上进行搜索已经有很多图文教程了&#xff0c;本…

mfc140u.dll丢失的科学修复手段,简单又方便的mfc140u.dll修复

遇到 "缺失 mfc140u.dll 文件" 的提示时可能会让你疑惑&#xff0c;但不用担心。这个文件是 Microsoft Visual C 2015 的重要组成部分&#xff0c;对运行特定程序非常关键。幸运的是&#xff0c;解决这一问题并不难。本文将简单指导你如何恢复或修复丢失的 mfc140u.d…

多台PC网络ADB连接同一台RK3399 Android7.1.2设备

在RK3399 Android7.1.2上面&#xff0c;进行网络ADB调试时&#xff0c;如果多台电脑连接同一台Android设备&#xff0c;第一台连接上的能正常操作&#xff0c;之后连接的看到设备状态为OFFLINE&#xff0c;分析了下ADBD相关代码&#xff0c;发现在ACCEPT Client的时候没有区分别…

设计师必备:2024最新PDF转CAD软件盘点

随着科技的飞速发展&#xff0c;设计师们不再受限于传统的设计流程&#xff0c;可以利用一些新欣的工具来提升工作效率、优化工作流程的新工具。其中&#xff0c;PDF转CAD工具成为了设计行业的一大热门话题。面对海量的数据和复杂的设计需求&#xff0c;一款高效、精准的PDF转C…

11、MySQL-SQL优化

目录 1、插入数据 1.1、批量插入 1.2、手动提交事务 1.3、主键顺序插入 1.4、大批量插入数据 2、主键优化 2.1 页分裂 2.2 主键顺序插入 2.3 主键乱序插入 2.4 页合并 2.5 主键的设计原则 3、order by优化 4、group by优化 5、limit优化 6、count优化 6.1 coun…

【Bifrost】ubuntu24.04 远程构建及clion设置编码风格google

Bifrost 构建通过clion 远程到ubuntu24.04 构建感觉是不认识这种写法,这种至少是c++11 fix : 修改absl 的构建cmakelist,明确c++17 好像还是不行error: ‘uint8_t’ was not declared in this scope加入:#include <stdint.h>可以解决一部分。那么,这种呢?/home/zha…

浅谈 DNS 篡改劫持

故事背景&#xff1a;产品反馈线上站点操作后跳转至空白页面&#xff0c;浏览器 URL 地址异常&#xff0c;ping 命令测试后定位可能是 DNS 解析异常&#xff0c;联系七牛云技术人员排查&#xff0c;反馈是由于带宽突变&#xff0c;触发节点防攻击策略所致&#xff0c;后续先调整…

keepalived安装-集群部署

1.服务器信息 服务器版本服务器IP介质版本安装用户CentOS Linux release 7.9.2009 (Core)192.168.10.244keepalived-2.2.8.tar.gz nginx-1.26.1 rootCentOS Linux release 7.9.2009 (Core)192.168.10.245keepalived-2.2.8.tar.gz nginx-1.26.1 root2.服务器基础配置 参考:Lin…

二、AI工作流(低代码)-输入-文本组件详解

对工作流感兴趣的小伙伴可以去试一试。&#x1f525;偷偷的告诉你&#xff0c;它的GPTo4.0 mini 不要&#x1f4b0;。传送门&#xff1a;https://www.nyai.chat/chat?invitenyai_1141439 一、能用AI工作流介绍 能用AI-工作流是一个“低代码”工具、它也是个人或者中小企业的…