Tag: Python

  • 如何使用Python爬取BT种子资源并进行分析

    如何使用Python爬取BT种子资源并进行分析

    在数字时代,获取各种信息变得愈加便捷,但有时我们需要特定的数据或资源,而互联网上的BT种子资源是一种常见的需求。本教程将向您展示如何使用Python编写爬虫程序,以获取BT种子资源并进行基本的分析。无论是寻找最新的电影、音乐、软件,还是满足其他资源需求,本教程都将帮助您掌握这一技能。

    准备工作

    在开始之前,确保您已经安装了Python,并且具备以下准备工作:

    1. 安装Python库:我们将使用requests和BeautifulSoup库来进行网页爬取和解析。您可以使用以下命令来安装它们:

      pip install requests
      pip install beautifulsoup4
    2. 确保您了解一些基本的Python编程知识,包括变量、循环和条件语句。

    爬取BT种子资源

    首先,我们需要编写Python代码来爬取BT种子资源。以下是示例代码:

    from bs4 import BeautifulSoup
    import requests
    from urllib.parse import quote
    
    # 设置请求头
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.50'
    }
    
    # 输入关键词
    keyword = input("请输入关键词: ")
    
    # 构建搜索URL
    search_url = f'https://tellme.pw/bts/search/{quote(keyword)}'
    
    # 发送GET请求
    response = requests.get(url=search_url, headers=headers)
    
    # 使用BeautifulSoup解析页面内容
    soup = BeautifulSoup(response.text, 'lxml')
    
    # 提取种子信息
    magnet_links = []
    titles = []
    sizes = []
    dates = []
    
    # 迭代页面
    for page in range(1, 51):  # 最多爬取50页
        page_url = f'{search_url}/page/{page}'
        response = requests.get(url=page_url, headers=headers)
        soup = BeautifulSoup(response.text, 'lxml')
        data_list = soup.find_all("a", {"href": re.compile("\/\/btsow\.*?"), "title": re.compile('.*?')})
    
        # 提取种子信息并存储
        for item in data_list:
            magnet_links.append('magnet:?xt=urn:btih:' + item.get('href')[-40:])
            titles.append(item.get('title'))
            size_info = item.find("div", {"class": re.compile('.*?size')}).get_text().split(" / ")
            size = size_info[0][5:-2]
            size_unit = size_info[0][-2:]
            if size_unit == "TB":
                sizes.append(float(size) * 1024 ** 2)
            elif size_unit == "GB":
                sizes.append(float(size) * 1024)
            elif size_unit == "MB":
                sizes.append(float(size))
            elif size_unit == "KB":
                sizes.append(float(size) / 1024)
            else:
                sizes.append(0)
            dates.append(size_info[1][13:])
    
    # 打印获取的资源信息
    if len(magnet_links) == 0:
        print('未找到任何资源')
    else:
        print('链接数量:', len(magnet_links))
        print('详细内容:')
        for i in range(len(magnet_links)):
            print(magnet_links[i] + '\t' + str(sizes[i]) + '\t' + titles[i])

    以上代码首先发送GET请求,然后使用BeautifulSoup解析页面内容,提取了种子的磁力链接、标题、大小和日期。最后,将这些信息打印出来供用户查看。

    数据分析与保存

    如果您想进一步分析或保存这些种子信息,可以将数据存储到CSV文件中。以下是如何做到的代码:

    import csv
    
    # 创建CSV文件并写入数据
    if len(magnet_links) > 0:
        with open(f'{keyword}.csv', mode='w', newline='', encoding='utf-8-sig') as file:
            writer = csv.writer(file)
            writer.writerow(['种子名', '磁力链接', '文件大小(单位:MB)', '日期'])
            for i in range(len(magnet_links)):
                writer.writerow([titles[i], magnet_links[i], sizes[i], dates[i]])
        print('数据已保存到文件:', f'{keyword}.csv')

    这段代码将数据写入一个CSV文件中,包括种子名、磁力链接、文件大小和日期等信息。

    结论

    通过这个简单的Python爬虫程序,您可以轻松地获取BT种子资源并进行基本的分析。这对于那些希望找到特定内容的用户来说是非常有用的。请记住,在使用爬虫时要遵守网站的规定和法律法规。

    希望这个教程对您有所帮助,让您更好地理解如何使用Python进行网页爬取和数据分析。


    注意:本教程仅供学习和参考,不鼓励或支持任何侵犯版权或非法行为。请在合法的范围内使用爬虫技术。

  • 机器学习简介与框架选择指南

    机器学习简介与框架选择指南

    人工智能(AI)正逐渐改变着我们的生活和工作方式。其中,机器学习是实现人工智能的关键技术之一,而深度学习则是机器学习领域的一大亮点。本教程将为您介绍机器学习的基本概念、分类以及选择合适的深度学习框架的指南。

    什么是机器学习?

    机器学习是人工智能的一个分支,它涉及从数据中自动分析和提取模式,然后利用这些模式来进行预测和决策。机器学习的核心思想是让计算机从数据中学习,而不是通过明确的编程规则来执行任务。

    数据集的构成

    在机器学习中,通常会使用数据集来进行训练和测试模型。一个典型的数据集由两部分组成:

    • 特征值(Features):描述数据的各个属性或特征,这些特征可以是数值、文本、图像等。

    • 目标值(Labels):要预测或分类的结果,通常是一个类别标签或连续型的数值。

    机器学习算法分类

    机器学习算法可以分为监督学习和无监督学习两大类。

    监督学习

    监督学习是一种有标签数据的学习方式,其中模型从输入数据中学习并进行预测或分类。根据目标值的不同,监督学习又可以分为以下两种:

    1. 分类问题:目标值是离散的类别标签。常见的监督学习算法包括:

      • k-近邻算法
      • 贝叶斯分类
      • 决策树
      • 逻辑回归

      示例应用场景:

      • 预测天气阴晴雨雪
      • 人脸识别
    2. 回归问题:目标值是连续型的数据。常见的监督学习算法包括:

      • 线性回归
      • 岭回归

      示例应用场景:

      • 预测天气温度

    无监督学习

    无监督学习是一种无标签数据的学习方式,其中模型试图从数据中发现模式、聚类或降维。常见的无监督学习算法包括:

    • 聚类算法(如K-means)

    示例应用场景:

    • 将相似用户分组
    • 图像分割

    机器学习的开发流程

    机器学习项目通常遵循以下开发流程:

    1. 数据获取:收集和准备用于训练和测试模型的数据。

    2. 数据处理:清洗、转换和处理数据,以确保其适用于模型训练。

    3. 特征工程:选择和提取适当的特征,以便模型可以理解和学习数据。

    4. 机器学习算法训练:选择合适的机器学习算法,并使用训练数据对模型进行训练。

    5. 模型评估:使用测试数据来评估模型的性能,通常使用指标如准确度、精确度、召回率等。

    6. 模型部署:将训练好的模型部署到实际应用中,以进行预测或分类。

    选择合适的深度学习框架

    深度学习是机器学习的一个重要分支,它基于人工神经网络的概念。选择合适的深度学习框架对于开展深度学习项目至关重要。以下是两个主流深度学习框架和它们的特点:

    TensorFlow

    TensorFlow是由Google开发的开源深度学习框架,具有以下特点:

    • 强大的生态系统:TensorFlow拥有广泛的社区支持和丰富的扩展库,适用于各种深度学习任务。

    • 灵活性:TensorFlow提供了高级API(如Keras)和低级API,使开发人员可以根据需求进行模型构建。

    • 部署便利性:TensorFlow支持模型的跨平台部署,可以在移动设备、嵌入式系统和云端进行部署。

    PyTorch

    PyTorch是由Facebook开发的深度学习框架,具有以下特点:

    • 动态计算图:PyTorch采用动态计算图的方式,使模型构建和调试更加灵活。

    • 易于学习:PyTorch的API设计直观,容易上手,适合初学者。

    • 强大的研究工具:PyTorch在研究领域广泛应用,许多最新的深度学习研究都使用PyTorch实现。

    选择框架时,您可以考虑项目需求、个人偏好和社区支持等因素。

    结语

    机器学习是人工智能领域的核心技术之一,深度学习则是机器学习的重要分支。选择合适的深度学习框架和正确的机器学习算法将有助于您开展成功的机器学习项目。

  • 如何使用Python获取本机和局域网IP地址与MAC地址

    如何使用Python获取本机和局域网IP地址与MAC地址

    在今天的教程中,我们将学习如何使用Python编写一个小工具,用于获取本机和局域网中设备的IP地址和MAC地址。这个工具可以在网络维护和故障排除时非常有用,同时也是自由职业者提高效率的好帮手。通过本教程,您将了解如何使用Python来执行网络命令、解析命令输出,并将结果保存到文本文件中。

    准备工作

    在开始之前,确保您已经安装了以下两个Python库:

    • win32api:用于弹出Windows消息框。
    • win32con:用于定义Windows消息框的样式。

    您可以使用以下命令来安装这两个库:

    pip install pypiwin32

    编写Python脚本

    我们将编写一个Python脚本,它执行以下任务:

    1. 获取本机的IP地址和MAC地址。
    2. 获取局域网中其他设备的IP地址和MAC地址。
    3. 将获取到的结果保存到文本文件中。
    4. 弹出一个Windows消息框,提醒用户结果已保存。

    以下是完整的Python代码:

    import os
    import win32api
    import win32con
    
    def msgbox(msg, title='提醒'):
        win32api.MessageBox(0, msg, title, win32con.MB_OK)
    
    def local_ip_mac():  # 本机IP和MAC
        output = os.popen('ipconfig /all')
        for i in output:
            if '物理地址.' in i:
                mac = i.split(':')[1].strip()
            if 'IPV4' in i.upper() and '(' in i:
                ip = i.split(':')[1].split('(')[0].strip()
        if ip and mac:
            return [ip, mac]
    
    def lan_ip_mac():  # 局域网IP和MAC
        ls = []
        output = os.popen('arp -a')
        for i in output:
            if '动态' in i:
                ip, mac, _ = i.strip().split()
                ls.append([ip, mac])
        return ls
    
    if __name__ == '__main__':
        res = lan_ip_mac()
        res.append(local_ip_mac())
        print(res)
    
        # 结果写入文本
        txt = 'ip_mac.txt'
        out_txt = '\n'.join(['\t'.join(i) for i in res])
        with open(txt, 'w') as f:
            f.write(out_txt)
    
        msgbox(f'提取结果已保存到:{txt}')  # 注释掉此行则不弹窗提醒

    运行脚本

    现在,将上述代码保存为一个Python文件,然后运行它。脚本将执行获取本机和局域网IP地址与MAC地址的任务,并将结果保存到名为”ip_mac.txt”的文本文件中。如果您不需要弹出Windows消息框提醒,可以将msgbox函数的调用行注释掉。

    结束语

    通过这个简单的教程,您学会了如何使用Python编写一个小工具,用于获取本机和局域网中设备的IP地址和MAC地址。这个工具对于网络管理和自由职业者的日常工作都非常有用。希望这个教程对您有所帮助,祝您在自由职业生涯中取得成功!

  • 如何使用Python爬取百度贴吧内容

    如何使用Python爬取百度贴吧内容

    在今天的教程中,我将向您介绍如何使用Python编写一个简单的网络爬虫,用于从百度贴吧中获取帖子内容。这个教程将帮助您了解如何使用Python的requests库和BeautifulSoup库来获取网页内容,以及如何将爬取到的数据保存到本地文件中。如果您是一个对网络爬虫和数据获取有兴趣的自由职业者,这个教程可能会对您有所帮助。

    1. 准备工作

    在开始之前,您需要确保已经安装了以下Python库:

    • requests:用于发送HTTP请求以获取网页内容。
    • BeautifulSoup:用于解析HTML网页内容。

    您可以使用以下命令来安装这些库:

    pip install requests
    pip install beautifulsoup4

    2. 编写爬虫代码

    首先,让我们编写一个Python脚本来获取百度贴吧的帖子内容。以下是完整的代码:

    import requests
    import time
    from bs4 import BeautifulSoup
    
    def get_content(url):
        '''
        分析贴吧的网页文件,整理信息,保存在列表变量中
        '''
    
        # 初始化一个列表来保存所有的帖子信息:
        comments = []
        # 使用request请求所需url
        html = requests.get(url)
    
        # 使用BeautifulSoup解析网页内容
        soup = BeautifulSoup(html.text, 'lxml')
    
        # 找到所有具有‘j_thread_list clearfix’属性的li标签
        liTags = soup.find_all('li', attrs={"class":['j_thread_list', 'clearfix']})
    
        # 循环遍历li标签
        for li in liTags:
            # 初始化一个字典来存储帖子信息
            comment = {}
            try:
                # 筛选信息,并保存到字典中
                comment['title'] = li.find('a', attrs={"class": ['j_th_tit']}).text.strip()
                comment['link'] = "tieba.baidu.com/" + li.find('a', attrs={"class": ['j_th_tit']})['href']
                comment['name'] = li.find('span', attrs={"class": ['tb_icon_author']}).text.strip()
                comment['time'] = li.find('span', attrs={"class": ['pull-right is_show_create_time']}).text.strip()
                comment['replyNum'] = li.find('span', attrs={"class": ['threadlist_rep_num center_text']}).text.strip()
                comments.append(comment)
            except:
                print('出了点小问题')
    
        return comments
    
    def Out2File(comments):
        '''
        将爬取到的文件写入到本地
        保存到当前目录的TTBT.txt文件中。
        '''
        with open('TTBT.txt', 'a+', encoding='utf-8') as f:
            for comment in comments:
                f.write('标题:{} \t 链接:{} \t 发帖人:{} \t 发帖时间:{} \t 回复数量:{} \n'.format(
                    comment['title'], comment['link'], comment['name'], comment['time'], comment['replyNum']))
            print('当前页面爬取完成')
    
    def main(base_url, deep):
        url_list = []
        # 将所有需要爬取的url存入列表
        for i in range(0, deep):
            url_list.append(base_url + '&pn=' + str(50 * i))
        # 循环写入所有的数据
        for url in url_list:
            print(f"开始爬取:{url}")
            content = get_content(url)
            print(content)
            Out2File(content)
            time.sleep(5)
        print('所有的信息都已经保存完毕!')
    
    base_url = 'https://tieba.baidu.com/f?ie=utf-8&kw=亚运会'
    # 设置需要爬取的页码数量
    deep = 3
    
    if __name__ == '__main__':
        main(base_url, deep)

    3. 运行爬虫

    现在,让我们来运行这个爬虫脚本。将上述代码保存为一个Python文件,然后运行它。脚本将会爬取百度贴吧关于”亚运会”的帖子内容,并将数据保存到名为”TTBT.txt”的文本文件中。

    4. 结束语

    通过这个简单的教程,您学会了如何使用Python编写一个基本的网络爬虫,用于获取百度贴吧的帖子内容。这只是网络爬虫的入门,您可以进一步探索和学习更多高级的爬虫技巧,以满足您的自由职业需求。

  • 创建Langchain、Tair和OpenAI的问题回答系统教程

    创建Langchain、Tair和OpenAI的问题回答系统教程

    本教程将详细介绍如何使用Langchain、Tair作为知识库和OpenAI嵌入来实现一个问题回答系统。如果您不熟悉Tair,请先查看“Getting_started_with_Tair_and_OpenAI.ipynb”笔记。

    本教程将全面介绍以下过程:

    1. 使用OpenAI API计算嵌入。
    2. 将嵌入存储在Tair实例中以构建知识库。
    3. 将原始文本查询转换为OpenAI API的嵌入。
    4. 使用Tair在创建的集合中执行最近邻搜索以查找一些上下文。
    5. 请求LLM在给定上下文中查找答案。

    所有这些步骤将简化为调用一些对应的Langchain方法。

    先决条件

    为了完成本教程,我们需要准备以下几项内容:

    • Tair云实例。
    • Langchain作为框架。
    • OpenAI API密钥。

    安装要求

    本教程需要以下Python包:openai、tiktoken、langchain和tair。

    • openai 提供了方便的访问OpenAI API的方式。
    • tiktoken 是用于OpenAI模型的快速BPE标记化工具。
    • langchain 帮助我们更轻松地构建具有LLM的应用程序。
    • tair库用于与tair向量数据库交互。
    !pip install openai tiktoken langchain tair

    准备您的OpenAI API密钥

    OpenAI API密钥用于文档和查询的矢量化。

    如果您没有OpenAI API密钥,可以从 https://platform.openai.com/account/api-keys 获取一个。

    获取密钥后,请通过getpass将其添加。

    import getpass
    
    openai_api_key = getpass.getpass("输入您的OpenAI API密钥:")

    准备您的Tair URL

    要建立Tair连接,您需要TAIR_URL。

    URL的格式为:redis://[[用户名]:[密码]]@localhost:6379/0

    TAIR_URL = getpass.getpass("输入您的Tair URL:")

    载入数据

    在这一部分,我们将加载包含一些自然问题和它们的答案的数据。所有这些数据将用于创建具有Tair作为知识库的Langchain应用程序。

    import wget
    import json
    
    # 所有示例均来自https://ai.google.com/research/NaturalQuestions
    # 这是我们下载并提取以进行进一步处理的训练集的示例。
    wget.download("https://storage.googleapis.com/dataset-natural-questions/questions.json")
    wget.download("https://storage.googleapis.com/dataset-natural-questions/answers.json")
    
    with open("questions.json", "r") as fp:
        questions = json.load(fp)
    
    with open("answers.json", "r") as fp:
        answers = json.load(fp)

    链定义

    Langchain已经与Tair集成,并执行给定文档列表的所有索引。在我们的案例中,我们将存储答案集。

    from langchain.vectorstores import Tair
    from langchain.embeddings import OpenAIEmbeddings
    from langchain import VectorDBQA, OpenAI
    
    embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
    doc_store = Tair.from_texts(
        texts=answers, embedding=embeddings, tair_url=TAIR_URL,
    )

    此时,所有可能的答案都已存储在Tair中,因此我们可以定义整个QA链。

    llm = OpenAI(openai_api_key=openai_api_key)
    qa = VectorDBQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        vectorstore=doc_store,
        return_source_documents=False,
    )

    搜索数据

    一旦数据放入Tair中,我们就可以开始提出一些问题。问题将由OpenAI模型自动向量化,并创建的向量将用于在Tair中找到一些可能匹配的答案。一旦检索到,最相似的答案将被合并到发送给OpenAI Large Language Model的提示中。

    import random
    import time
    
    random.seed(52)
    selected_questions = random.choices(questions, k=5)
    
    for question in selected_questions:
        print(">", question)
        print(qa.run(question), end="\n\n")
        # 等待20秒以处理速率限制
        time.sleep(20)

    自定义提示模板

    Langchain的“stuff”链类型使用具有问题和上下文文档的特定

    提示。以下是默认提示的样式:

    使用以下上下文部分来回答最后的问题。如果您不知道答案,只需说您不知道,不要试图编造一个答案。
    {context}
    问题:{question}
    有帮助的答案:

    然而,我们可以提供我们自己的提示模板,并更改OpenAI LLM的行为,同时仍然使用“stuff”链类型。保持{context}和{question}作为占位符是重要的。

    实验自定义提示

    我们可以尝试使用不同的提示模板,以便模型:

    • 如果它知道答案,就提供一个单句回答。
    • 如果不知道问题的答案,建议一个随机歌曲标题。
    from langchain.prompts import PromptTemplate
    custom_prompt = """
    使用以下上下文部分来回答最后的问题。请只提供简短的单句摘要回答。如果您不知道答案或上下文中没有答案,请不要试图编造一个答案,而是建议我听一首随机无关的歌曲。
    上下文:{context}
    问题:{question}
    有帮助的答案:
    """
    
    custom_prompt_template = PromptTemplate(
        template=custom_prompt, input_variables=["context", "question"]
    )
    
    custom_qa = VectorDBQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        vectorstore=doc_store,
        return_source_documents=False,
        chain_type_kwargs={"prompt": custom_prompt_template},
    )
    
    random.seed(41)
    for question in random.choices(questions, k=5):
        print(">", question)
        print(custom_qa.run(question), end="\n\n")
        # 等待20秒以处理速率限制
        time.sleep(20)

    结论

    通过本教程,您已经学会了如何使用Langchain、Tair和OpenAI来创建一个强大的问题回答系统。这种系统可以用于各种应用,从搜索引擎到智能助手。希望本教程对您有所帮助,使您能够更好地理解和应用这些技术。

  • 教程:将银行账单转换为Beancount格式

    教程:将银行账单转换为Beancount格式

    在日常生活中,我们经常需要处理各种银行账单,包括信用卡账单、储蓄账户账单等。而Beancount是一种强大的财务记账工具,可以帮助我们有效地管理和跟踪财务交易。本教程将向您展示如何将不同银行的账单转换为Beancount格式,以便更好地管理个人财务。

    背景故事

    假设您有多个银行账户,每月都会收到不同银行的账单。这些账单可能以不同的格式和结构呈现,使您难以一目了然地了解自己的财务状况。同时,您可能还希望将这些财务数据记录到Beancount中,以便轻松生成财务报表和分析您的支出。

    因此,本教程将介绍如何使用Python编程语言来处理不同银行的账单,并将其转换为Beancount格式,使您能够更轻松地管理个人财务。

    准备工作

    在开始之前,您需要准备以下工作:

    1. 确保您已经安装了Python编程语言。

    2. 确保您已经安装了以下Python库:

      • pandas:用于处理和分析数据。
      • numpy:用于数值计算。
      • os:用于文件和目录操作。
      • re:用于正则表达式操作。
    3. 从您的银行获取账单文件,可以是Excel格式或CSV格式。

    教程步骤

    本教程将分为以下几个步骤来实现将银行账单转换为Beancount格式:

    步骤一:导入所需库和设置文件路径

    首先,我们需要导入所需的Python库,并设置输入文件的路径、银行名称以及输出文件的路径。以下是示例代码:

    import os
    import re
    import pandas as pd
    import numpy as np
    
    # 获取当前文件夹路径
    dir = os.path.dirname(os.path.abspath(__file__))
    
    # 输入文件路径,可以手动输入或从命令行获取
    input_file = input("输入账单路径:")
    
    # 输入账单归属银行(目前支持CCB、CMB、SRCB、ABC)
    bank = input("输入账单归属银行[CCB、CMB、SRCB、ABC]:")
    
    # 输出文件路径
    output_file = dir + "\\" + bank + ".bean"
    
    # 配置文件路径
    config_file = dir + "\\config\\" + bank + ".conf"

    在这个步骤中,我们首先获取当前文件夹的路径,然后要求用户输入账单文件的路径和账单归属银行。最后,我们定义了输出文件的路径和配置文件的路径。

    步骤二:整理银行账单数据

    接下来,我们需要根据不同银行的账单格式,编写相应的数据整理函数。我们这里以建设银行(CCB)和招商银行(CMB)为例。

    CCB账单整理

    # CCB账单excel的整理
    def CCB_data(_file_):
        data = pd.read_excel(_file_)
        data.columns = ["No", "text0", "CCY", "Yuan", "time", "cost", "bal", "text1", "text2"]
        data = data.iloc[2:]
        data["time"] = pd.to_datetime(data["time"]).astype(str)
        data.loc[:, "account"] = data["text0"] + ":" + data["text2"]
        data["CCY"] = data["CCY"].replace("人民币元", "CNY")
        data = data[["time", "cost", "CCY", "account", "text0", "text1", "text2"]]
        return data

    CMB账单整理

    # CMB账单csv的整理
    def CMB_data(_file_):
        data = pd.read_csv(_file_)
        data.columns = ["time", "CCY", "cost", "bal", "text0", "text2"]
        data["time"] = pd.to_datetime(data["time"]).astype(str)
        data["cost"] = data["cost"].astype(str)
        data.loc[:, "text1"] = None
        data.loc[:, "account"] = data["text0"] + ":" + data["text2"]
        data = data[["time", "cost", "CCY", "account", "text0", "text1", "text2"]]
        return data

    在这两个函数中,我们分别处理了建设银行和招商银行的账单数据,整理成统一的数据格式,包括时间、金额、货币代码、账户信息等。

    步骤三:关键字查找和替换

    接下来,我们需要根据配置文件中的关键字,对账单中的账户信息进行查找和替换。这可以帮助我们将不同的账户信息映射到统一的账户名称。

    # 关键字查找替换
    def replace(_data_, _config_):
        conf = pd.read_csv(_config_)
        for conf in conf.itertuples():
            _data_ = _data_.str.replace(".*" + conf[1] + ".*", conf[2], regex=True)
        return _data_

    在这个函数中,我们读取了配置文件中的关键字和对应的替换值,然后使用正则表达式在账单数据中进行查找和替换操作。

    步骤四:生成Beancount格式的字段

    最后,我们将整理后的账单数据转换为Beancount格式的字段,以便后续导入到Beancount中。以下是生成Beancount字段的函数:

    # 输出beancount格式的字段
    def to_bean(_data_):
        global bank
        bean = _data_["time"] + ' * \"' + _data_["text
    
    0"] + '\"\n\t'
        if _data_["text1"].notnull().any():
            bean = bean + 'notes: \"' + _data_["text1"] + '\"\n\t' 
        bean = bean + 'id: \"' + _data_["text2"] + '\"\n\t'
        bean = bean + "Assets:Bank:" + bank + " " + _data_["cost"] + " " + _data_["CCY"] + "\n\t"
        bean = bean + _data_["account"] + "\n"
    
        return bean

    在这个函数中,我们根据Beancount的格式规范,构建了包括时间、交易描述、备注、账户信息、金额和货币代码的字段。

    步骤五:导出Beancount文件

    最后一步是将生成的Beancount字段写入到输出文件中,以完成账单转换操作。

    # 整理为beancount格式
    if bank == "CCB":
        DATA = CCB_data(input_file)
    if bank == "CMB":
        DATA = CMB_data(input_file)
    
    # 按conf文件查找替换关键字
    DATA["account"] = replace(DATA["account"], config_file)
    
    # 整理为beancount格式的字段
    bean = to_bean(DATA).to_frame()
    
    # 输出Beancount文件
    for bean in bean.itertuples():
        text = text + str(bean[1]) + "\n"
    
    file = open(output_file, 'w')
    file.write(text)
    file.close()

    在这个步骤中,我们根据用户输入的银行名称选择相应的账单整理函数,然后进行关键字查找和替换操作,最后生成Beancount字段并导出到文件中。

    结语

    通过本教程,您学会了如何将不同银行的账单转换为Beancount格式,从而更好地管理个人财务。这将帮助您轻松跟踪支出、生成财务报表,并更好地了解自己的财务状况。

  • 教程:使用Python和Selenium自动化抖音互动

    教程:使用Python和Selenium自动化抖音互动

    随着社交媒体的流行,抖音成为了一个受欢迎的短视频平台,拥有数以亿计的用户。在抖音上,用户可以观看和分享有趣的短视频内容,但您可能不知道,您也可以使用Python和Selenium库来自动化与抖音的互动。本教程将向您展示如何自动化登录抖音、发送消息和与直播间互动,以及如何保存和加载cookie以实现持久登录。

    步骤1:准备工作

    在开始之前,您需要完成以下准备工作:

    • 安装Python:确保您的计算机上已安装Python,并且您对Python编程有一定的了解。

    • 安装Selenium库:使用pip install selenium命令来安装Selenium库,它将帮助我们自动化浏览器操作。

    • 安装Edge浏览器驱动程序:您需要下载并安装适用于Edge浏览器的WebDriver,以便Selenium能够控制浏览器。确保下载与您浏览器版本相对应的WebDriver。

    步骤2:登录抖音并保存Cookie

    首先,我们将使用Selenium来自动化登录抖音并保存Cookie以实现持久登录。以下是登录抖音并保存Cookie的示例代码:

    from selenium import webdriver
    import time
    import pickle
    
    # 创建Edge浏览器实例
    edge = webdriver.Edge()
    
    # 最大化浏览器窗口
    edge.maximize_window()
    
    # 设置最大等待时长为10秒
    edge.implicitly_wait(10)
    
    # 打开抖音网站
    edge.get('https://www.douyin.com/')
    
    # 等待一段时间,以便手动登录
    time.sleep(1)
    input("登入抖音账号后,请输入任意键继续...")
    time.sleep(0.3)
    
    # 保存Cookie到文件
    with open("douyin_cookie.pickle", 'wb') as file:
        pickle.dump(edge.get_cookies(), file)
    
    # 删除浏览器中的所有Cookie
    edge.delete_all_cookies()
    
    # 关闭浏览器
    edge.quit()

    上述代码首先创建了一个Edge浏览器实例,打开了抖音网站,并等待您手动登录。一旦您登录成功,脚本将保存Cookie到一个pickle文件中。这将允许您在后续的操作中持续保持登录状态。

    步骤3:自动化互动与直播间

    现在,让我们来自动化与抖音直播间的互动。我们将使用Selenium和PyAutoGUI库来实现点赞和发送消息的自动化。以下是示例代码:

    from selenium import webdriver
    import time
    import pickle
    import random
    import pyautogui
    import threading
    from selenium.webdriver.common.by import By
    
    # 主函数
    def main():
        # 创建两个线程,一个用于点赞,一个用于发送消息
        thread1 = threading.Thread(target=like_and_comment, name="LikeAndComment")
        thread2 = threading.Thread(target=keyword_detection, name="KeywordDetection")
    
        # 启动线程
        thread1.start()
        thread2.start()
    
    # 点赞和发送消息的函数
    def like_and_comment():
        # 进入直播间后点赞300次
        for i in range(300):
            x = random.randrange(300, 550)
            y = random.randrange(400, 550)
            pyautogui.click(x, y)
            time.sleep(0.2)
    
        # 随机选择发送的消息
        messages = ["大家戳戳屏幕点点关注,点点赞,主播需要你们的支持哦",
                    "亮一个抖币可以加群哦,群里面有高清手稿分享",
                    "主播现在写的字是形楷,喜欢的可以加群跟着练哦",
                    "来吧,大家把赞点起来!"]
    
        for j in range(100):
            wait_time = random.randrange(120, 180)
            time.sleep(wait_time)
            while True:
                text_element = edge.find_element(By.XPATH, '//textarea[@class="webcast-chatroom___textarea"]')
                text_element.clear()
                text_element.send_keys(random.choice(messages))  
                time.sleep(0.5)
                send_element = edge.find_element(By.XPATH, '//button[@class="webcast-chatroom___send-btn"][@type="button"]')
                time.sleep(1)
                send_element.click()
                break
    
    # 关键字检测和回复的函数
    def keyword_detection():
        #
    
     监测公屏的最后一个发言,根据关键字发送回复消息
        keywords_and_responses = {
            "笔": "9390",
            "纸": "80g木浆纸",
            "垫": "主播使用的垫子在橱窗有哦"
        }
    
        while True:
            web_text = edge.find_elements(By.XPATH, '//a[contains(text())]')  
            latest_message = web_text[-1].text if web_text else ""
    
            for keyword, response in keywords_and_responses.items():
                if keyword in latest_message:
                    while True:
                        text_element = edge.find_element(By.XPATH, '//textarea[@class="webcast-chatroom___textarea"]')
                        text_element.clear()
                        text_element.send_keys(response)
                        time.sleep(0.5)
                        send_element = edge.find_element(By.XPATH, '//button[@class="webcast-chatroom___send-btn"][@type="button"]')
                        time.sleep(1)
                        send_element.click()
                        break
    
    if __name__ == '__main__':
        # 加载之前保存的Cookie
        with open("douyin_cookie.pickle", 'rb') as file:
            cookies_list = pickle.load(file)
    
        # 创建Edge浏览器实例
        edge = webdriver.Edge()
        edge.maximize_window()
    
        # 打开抖音网站
        edge.get('https://www.douyin.com/')
    
        # 添加Cookie以实现持久登录
        for cookie in cookies_list:
            edge.add_cookie(cookie)
    
        # 自定义您要进入的直播间链接
        edge.get('https://live.douyin.com/your_room_id')
    
        # 等待一段时间,确保页面加载完毕
        time.sleep(10)
    
        # 启动主程序
        main()

    上述代码创建了两个线程,一个用于点赞和发送消息,另一个用于监测公屏消息并根据关键字发送回复消息。通过这种方式,您可以自动化与抖音直播间的互动。

    结论

    本教程介绍了如何使用Python和Selenium自动化与抖音的互动,包括登录、点赞、发送消息和关键字回复。这些技能可以用于自动化互动、增加粉丝互动度以及提升用户体验。希望这个教程对您有所帮助!

  • Python发送电子邮件教程

    Python发送电子邮件教程

    电子邮件是现代通信的重要组成部分,它可以用于个人和商业用途。通过Python,您可以轻松地编写脚本来发送电子邮件。本教程将向您展示如何使用Python发送电子邮件,以及如何通过QQ邮箱的SMTP服务器发送电子邮件。无论您是要发送个人邮件还是自动化商务通知,这些技能都将对您有所帮助。

    准备工作

    在开始之前,您需要安装Python并了解一些基本的Python编程知识。此外,您还需要一个QQ邮箱账号,以便使用QQ邮箱的SMTP服务器发送邮件。确保您已经获得了SMTP服务器的授权码,这是连接到SMTP服务器的凭据。

    发送电子邮件的步骤

    在Python中发送电子邮件涉及以下主要步骤:

    1. 导入必要的模块。
    2. 创建邮件消息对象。
    3. 设置邮件的主题、发件人和收件人。
    4. 建立与SMTP服务器的连接。
    5. 使用授权码登录SMTP服务器。
    6. 发送邮件。
    7. 关闭SMTP服务器连接。

    让我们一步步来看如何实现这些步骤。

    步骤1:导入模块

    首先,我们需要导入Python的smtplib和email模块,它们是标准库中用于发送电子邮件的关键模块。具体代码如下:

    import smtplib
    from email.mime.text import MIMEText

    步骤2:创建邮件消息对象

    我们将使用MIMEText类来创建一个文本邮件的MIME消息对象,其中包含邮件的内容。这个对象将包括邮件的主题、发件人、收件人和邮件正文内容。

    msg = MIMEText(message)
    msg['Subject'] = subject
    msg['From'] = sender_email
    msg['To'] = rec_email

    步骤3:建立与SMTP服务器的连接

    我们使用smtplib模块中的SMTP_SSL类来建立与SMTP服务器的SSL连接。在这个步骤中,我们需要提供SMTP服务器的地址和端口号。

    with smtplib.SMTP_SSL('smtp.qq.com', 465) as smtp:

    步骤4:使用授权码登录SMTP服务器

    为了登录SMTP服务器,我们需要提供发件人的邮箱地址和SMTP服务器的授权码。

    smtp.login(sender_email, sender_pass)

    步骤5:发送邮件

    一旦我们成功登录SMTP服务器,就可以使用send_message方法发送邮件。

    smtp.send_message(msg)

    步骤6:关闭SMTP服务器连接

    最后,我们使用quit方法关闭SMTP服务器连接。

    smtp.quit()

    完整的示例代码

    以下是一个完整的示例代码,演示了如何使用Python发送电子邮件:

    import smtplib
    from email.mime.text import MIMEText
    
    # 定义一个函数,用于发送指定邮箱的邮件
    def sendqqmail(sender_email, sender_pass, rec_email, subject, message):
        # 使用MIMEText类创建一个邮件消息对象,其中message参数是邮件的内容
        msg = MIMEText(message)
    
        # 设置邮件的主题
        msg['Subject'] = subject
    
        # 设置邮件的发件人邮箱
        msg['From'] = sender_email
    
        # 设置邮件的收件人邮箱
        msg['To'] = rec_email
    
        # 使用smtplib模块的SMTP_SSL类创建一个SSL连接对象,连接到QQ邮箱SMTP服务器
        with smtplib.SMTP_SSL('smtp.qq.com', 465) as smtp:
            # 使用login方法登录SMTP服务器,参数sender_email和sender_pass分别是发件人的邮箱地址和授权码
            smtp.login(sender_email, sender_pass)
    
            # 使用send_message方法发送邮件,参数msg是要发送的邮件消息对象
            smtp.send_message(msg)
    
            # 关闭SMTP服务连接
            smtp.quit()
    
    # 定义一个主函数,用于运行整个程序
    def main():
        # 定义发件人的邮箱地址
        sender_email = '[email protected]'
    
        # 定义发件人的邮箱授权码
        emailpass = secretPass
    
        # 定义收件人的邮箱地址
        to_email = '[email protected]'
    
        # 定义邮件的主题
        sub_msg = '测试python发送邮件'
    
        # 定义邮件的正文内容
        content = '这是我的第一个python发送邮件测试'
    
        # 调用sendqqmail函数,发送邮件
        sendqqmail(sender_email, emailpass, to_email, sub_msg, content)
    
    # 执行main函数
    if __name__ == '__main__':
        main()

    结论

    通过本教程,您学会了如何使用Python发送电子邮件,以及如何通过QQ邮箱的SMTP服务器发送邮件。这些技能对于与他人保持联系、自动化通知以及许多其他用途都非常有用。希望这个教程对您有所帮助!

  • 快速排序算法的可视化教程

    快速排序算法的可视化教程

    在计算机科学中,排序算法是一项基本而重要的任务。排序的目的是将一组数据按照一定的规则进行排列,以便更容易地进行查找和处理。快速排序算法是一种高效的排序算法,它的性能在平均情况下非常出色。本教程将教您如何使用Python和Matplotlib库可视化快速排序算法的执行过程。

    准备工作

    在开始之前,您需要安装Matplotlib库。您可以使用以下命令安装Matplotlib:

    pip install matplotlib

    确保您已经安装了Matplotlib库,然后我们可以开始学习如何可视化快速排序算法的执行过程。

    快速排序算法概述

    快速排序是一种分治算法,它的基本思想是选择一个元素作为“枢轴”(pivot),然后将其他元素分为两个子数组,小于枢轴的放在左边,大于枢轴的放在右边。然后,递归地对左右子数组进行排序,直到整个数组有序。

    快速排序的关键步骤包括选择枢轴、划分子数组和递归排序子数组。在本教程中,我们将通过可视化来理解这些步骤。

    可视化快速排序

    步骤1:导入必要的库

    首先,我们需要导入Matplotlib库,以及随机生成数据的模块。

    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    from random import shuffle

    步骤2:实现快速排序算法

    我们将实现快速排序算法的两个主要函数:quicksort 和 partition。quicksort 函数将递归地对数组进行排序,并在每一步记录数组的状态。partition 函数用于划分子数组并返回枢轴的位置。

    以下是这两个函数的代码:

    def quicksort(arr, start, end, frames):
        if start >= end:
            return
    
        pivot_index = partition(arr, start, end)
        frames.append(arr[:])
    
        quicksort(arr, start, pivot_index-1, frames)
        quicksort(arr, pivot_index+1, end, frames)
    
    def partition(arr, start, end):
        pivot_index = start
        pivot = arr[end]
    
        for i in range(start, end):
            if arr[i] < pivot:
                arr[i], arr[pivot_index] = arr[pivot_index], arr[i]
                pivot_index += 1
        arr[end], arr[pivot_index] = arr[pivot_index], arr[end]
        return pivot_index

    步骤3:创建动画函数

    我们将创建一个动画函数 animate,用于可视化快速排序的执行过程。这个函数将使用Matplotlib创建动画,并在每一帧更新数组的状态。

    def animate(frames):
        fig, ax = plt.subplots()
        ax.set_title("快速排序")
        bar_rects = ax.bar(range(len(frames[0])), frames[0], align="edge")
    
        def update_fig(frame, rects, iteration):
            for rect, val in zip(rects, frame):
                rect.set_height(val)
            iteration[0] += 1
            return rects
    
        anim = animation.FuncAnimation(fig, func=update_fig,
                                       fargs=(bar_rects, [0]),
                                       frames=frames, interval=50,
                                       repeat=False)
        plt.show()

    步骤4:生成随机数据并可视化排序过程

    现在,我们将生成一组随机数据并使用快速排序算法可视化排序过程。

    # 创建随机数据
    data = [x for x in range(1, 31)]
    shuffle(data)
    
    # 排序过程中的所有状态
    frames = []
    quicksort(data, 0, len(data)-1, frames)
    
    # 生成动画
    animate(frames)

    通过运行上述代码,您将看到一个动画,显示了快速排序算法的执行过程,从而更好地理解这个高效的排序算法。

    结论

    通过本教程,您学会了如何使用Python和Matplotlib库可视化快速排序算法的执行过程。这种可视化方法有助于深入理解算法的工作原理,并使学习更加生动有趣。希望本教程对您有所帮助!

  • 如何在视频中添加动态水印及音频

    如何在视频中添加动态水印及音频

    在现今数字化时代,视频内容的制作和分享已经成为日常生活的一部分。无论是在社交媒体上分享生活点滴,还是制作专业的视频内容,添加水印是一种常见的需求。水印可以用来保护视频内容的版权,增加品牌标识,或者为观众提供更多信息。本教程将教您如何使用Python和一些流行的库,在视频中添加动态水印,并保留原始音频。

    准备工作

    在开始之前,您需要安装以下Python库:

    • OpenCV (cv2)
    • numpy
    • moviepy
    • moviepy的依赖库:imageio, imageio-ffmpeg

    您可以使用以下命令安装这些库:

    pip install opencv-python-headless numpy moviepy imageio imageio-ffmpeg

    确保您已经安装了这些库,然后我们可以开始学习如何添加动态水印到视频中。

    添加动态水印

    步骤1:导入必要的库

    首先,我们需要导入必要的Python库,包括OpenCV、numpy和moviepy。这些库将帮助我们处理视频和添加水印。

    import cv2
    import os
    import numpy as np
    from moviepy.editor import VideoFileClip

    步骤2:定义函数以添加水印

    我们将创建一个函数add_dynamic_watermarks_with_audio,该函数将接受以下参数:

    • video_path:输入视频文件的路径。
    • output_path:输出带有水印的视频文件的路径。
    • watermark_image_paths:一个包含水印图片文件路径的列表。
    • watermark_sizes:与每个水印图片对应的大小。
    • watermark_speeds:每个水印的速度。
    • add_text_watermark:一个布尔值,表示是否添加文本水印。
    • text_watermark_text:要添加的文本水印的内容。
    • text_watermark_color:文本水印的颜色。

    以下是该函数的代码:

    def add_dynamic_watermarks_with_audio(video_path, output_path, watermark_image_paths, watermark_sizes, watermark_speeds, add_text_watermark, text_watermark_text, text_watermark_color):
        # 读取视频
        video_clip = VideoFileClip(video_path)
        audio_clip = video_clip.audio
    
        # 获取视频的宽度和高度
        width, height = video_clip.size
    
        # 准备文本水印
        if add_text_watermark:
            # 创建用于绘制文本水印的画布
            text_watermark_canvas = np.zeros((height, width, 3), dtype=np.uint8)
    
            # 设置文本水印属性
            font_face = cv2.FONT_HERSHEY_SIMPLEX
            font_scale = 1.5
            font_thickness = 2
    
            # 获取文本水印的大小
            (text_width, text_height), _ = cv2.getTextSize(text_watermark_text, font_face, font_scale, font_thickness)
    
            # 计算文本水印的位置
            text_x = int((width - text_width) / 2)
            text_y = int(height - text_height - 10)
    
            # 在画布上绘制文本水印
            cv2.putText(text_watermark_canvas, text_watermark_text, (text_x, text_y), font_face, font_scale, text_watermark_color, font_thickness, cv2.LINE_AA)
    
        # 在每一帧上添加水印
        watermark_positions = [(0, 0)] * len(watermark_image_paths)
    
        def process_frame(t, x):
            nonlocal watermark_positions
    
            frame = video_clip.get_frame(t)
    
            # 在帧上添加图片水印
            for i in range(len(watermark_image_paths)):
                watermark_image_path = watermark_image_paths[i]
                watermark_size = watermark_sizes[i]
                watermark_speed = watermark_speeds[i]
    
                # 读取水印图片
                watermark_image = cv2.imread(watermark_image_path)
    
                # 调整水印图片大小
                watermark_height, watermark_width, _ = watermark_image.shape
                if watermark_width > width or watermark_height > height:
                    scale_factor = min(width / watermark_width, height / watermark_height)
                    watermark_image = cv2.resize(
                        watermark_image,
                        (int(watermark_width * scale_factor), int(watermark_height * scale_factor)),
                        interpolation=cv2.INTER_LINEAR,
                    )
    
                # 更新水印位置
                if t % watermark_speed == 0:
                    while True:
                        x = np.random.randint(0, width - watermark_image.shape[1])
                        y = np.random.randint(0, height - watermark_image.shape[0])
                        too_close = False
    
                        # 检查新位置与已选择水印位置之间的距离
                        for j in range(i):
                            dist = np.sqrt((x - watermark_positions[j][0]) ** 2 + (y - watermark_positions[j][1]) ** 2)
                            if dist < watermark_image.shape[1] or dist < watermark_image.shape[0]:
                                too_close = True
                                break
    
                        if not too_close:
                            watermark_positions[i] = (x, y)
                            break
                else:
                    x, y = watermark_positions[i]
    
                # 在帧上添加水印
                watermark_resized = cv2.resize(
                    watermark_image, (int(watermark_size * watermark_width), int(watermark_size * watermark_height))
                )
                alpha = watermark_resized[:, :, 0] / 255.0
                for c in range(3):
                    frame_copy = frame.copy()
                    frame_copy[y : y + watermark_resized.shape[0], x : x + watermark_resized.shape[1], c] = (
                        frame[y : y + watermark_resized.shape[0], x : x + watermark_resized.shape[1], c] * (1 - alpha)
                        + watermark_resized[:, :, c] * alpha
                    )
    
            # 在帧上添加文本水印
            if add_text_watermark:
                frame_with_text = cv2.addWeighted(frame, 1, text_watermark_canvas, 0.7, 0)
                frame = frame_with_text
    
            cv2.imshow("Watermarked Video", frame)
            cv2.waitKey(1)
    
            return frame
    
        # 处理视频每一帧
        processed_clip = video_clip.fl(lambda gf, t
    
    : process_frame(t, gf))
    
        # 输出处理后的视频
        final_clip = processed_clip.set_audio(audio_clip)
        final_clip.write_videofile(output_path, codec='libx264', audio_codec="aac")
    
        return "水印添加完成!"

    步骤3:批量添加水印到视频

    我们还可以创建一个函数batch_add_watermarks_in_directory_with_audio,该函数将遍历指定目录中的所有视频文件,并为每个视频文件添加水印。您可以指定要添加的水印数量、水印图片的路径、大小和速度,以及是否添加文本水印。

    以下是该函数的代码:

    def batch_add_watermarks_in_directory_with_audio(directory, output_directory, watermark_image_paths, watermark_sizes, watermark_speeds, add_text_watermark=False, text_watermark_text=None):
        # 获取目录中的所有文件
        file_list = os.listdir(directory)
    
        # 遍历文件列表
        for file_name in file_list:
            # 检查文件是否为视频文件
            if file_name.lower().endswith(('.avi', '.mp4', '.mov', '.mkv')):
                file_path = os.path.join(directory, file_name)
    
                # 设置输出文件路径
                output_file_path = os.path.join(output_directory, file_name)
    
                # 添加水印
                add_dynamic_watermarks_with_audio(file_path, output_file_path, watermark_image_paths, watermark_sizes, watermark_speeds, add_text_watermark, text_watermark_text if add_text_watermark else None, (255, 255, 255))
    
        return "批量处理完成!"

    步骤4:使用示例

    现在我们已经定义了添加水印的函数,让我们看一个使用示例。首先,您需要提供视频文件所在的目录路径和输出目录路径。然后,您需要指定要添加的水印数量、水印图片的路径、大小和速度,以及是否添加文本水印。

    以下是使用示例的代码:

    if __name__ == '__main__':
        directory = input("请输入视频文件所在目录路径:")  # 视频文件所在目录
        output_directory = input("请输入输出视频文件目录路径:")  # 输出视频文件目录
    
        # 检查并创建输出目录
        os.makedirs(output_directory, exist_ok=True)
    
        watermark_image_paths = []
        watermark_sizes = []
        watermark_speeds = []
    
        num_watermarks = int(input("请输入要添加的水印数量:"))
        for i in range(num_watermarks):
            watermark_image_path = input(f"请输入第{i+1}个水印图片的路径:")
            watermark_size = float(input(f"请输入第{i+1}个水印图片的大小(0~1之间):"))
            watermark_speed = int(input(f"请输入第{i+1}个水印图片的速度:"))
    
            watermark_image_paths.append(watermark_image_path)
            watermark_sizes.append(watermark_size)
            watermark_speeds.append(watermark_speed)
    
        add_text_watermark_input = input("是否添加文本水印?(y/n) ")
        if add_text_watermark_input.lower() == 'y':
            add_text_watermark = True
            text_watermark_text = input("请输入文本水印内容:")
        else:
            add_text_watermark = False
            text_watermark_text = None
    
        batch_add_watermarks_in_directory_with_audio(directory, output_directory, watermark_image_paths, watermark_sizes, watermark_speeds, add_text_watermark, text_watermark_text)

    通过运行上述代码,您可以批量处理指定目录中的视频文件,为它们添加动态水印,并保留原始音频。

    结论

    通过本教程,您学会了如何使用Python和一些常用的库来为视频添加动态水印,并保留原始音频。这对于保护视频内容的版权、增加品牌标识或提供更多信息非常有用。希望本教程对您有所帮助!