Category: 技术折腾

服务器、网络、硬件与自建工具的实践记录。

  • 如何在终端中保持制表符(Tab)原样显示?

    如何在终端中保持制表符(Tab)原样显示?

    李明是一个资深的Linux用户,他经常在终端中编辑和查看代码。但最近他遇到了一个问题:每当他使用less或vim打开文件时,制表符(Tab)都会被转换为空格。这让他很困惑,因为这种转换影响了他对代码的阅读和编辑。经过一番搜索和尝试,他终于找到了解决方法。在本文中,我们将分享这些方法,帮助你在终端中保持制表符的原样显示。

    一、为什么终端会转换制表符?

    制表符(Tab)在终端和文本编辑器中有特殊的作用。它是一个控制字符,用于控制光标的位置。在终端和大多数文本编辑器中,默认情况下,制表符会被转换为一定数量的空格(通常是8个),以实现对齐的效果。

    但在某些情况下,我们希望终端能够原样显示制表符,而不是转换为空格。例如,当我们在终端中查看或编辑代码时,制表符的原样显示很重要,因为它影响到代码的缩进和格式。

    二、如何在less中保持制表符原样显示?

    对于less命令,我们可以使用-U选项来禁止制表符转换。这个选项会告诉less原样显示所有字符,包括制表符。

    less -U filename.txt

    使用这个选项后,less将不会再将制表符转换为空格。

    三、如何在vim中保持制表符原样显示?

    对于vim,我们可以在其配置文件~/.vimrc中添加以下设置:

    set noexpandtab

    这个设置告诉vim不要将制表符转换为空格。保存配置文件并重新启动vim后,制表符将会原样显示。

    四、其他命令和终端软件的设置

    1. GNOME Terminal:在菜单栏点击“编辑” -> “首选项”,取消勾选“将制表符转换为空格”选项。

    2. 其他终端软件:大多数终端软件都有类似的设置选项,你可以在其设置菜单或文档中查找。

    3. git diff:如果你使用git diff命令并发现制表符被转换为空格,你可以使用--no-pager选项来禁止这种转换。

    git --no-pager diff

    五、总结

    制表符在终端中的显示问题可能会影响到我们的工作效率和代码质量。但通过上述方法,我们可以轻松地解决这个问题,并在终端中保持制表符的原样显示。希望这些方法能帮助到你,让你在终端中的工作更加顺畅。

  • 双11购买指南:如何选购合适的群晖NAS?

    双11购买指南:如何选购合适的群晖NAS?

    双11正悄悄接近,赵明打算趁这个机会买一个群晖NAS,作为一个摄影爱好者,他想要一个稳定、方便的地方存放他珍贵的照片和视频。在和许多网友交流后,他总结了一些购买经验,决定和大家分享。

    一、为什么选择群晖NAS?

    NAS是网络存储服务器的简称,主要用于存储数据,并允许多个用户通过网络访问这些数据。而群晖NAS因其稳定性和用户友好的界面被广大用户所喜爱。尤其是对于摄影爱好者来说,群晖的照片管理应用得到了大家的一致好评。

    二、选购群晖NAS的几点考虑:

    1. 存储需求

    如果你的主要需求是存储照片和视频,那么双盘位的群晖NAS已经足够了。例如,DS220+或DS216+II都是不错的选择。

    2. 媒体库需求

    如果你打算建立一个电影和音乐的媒体库,但不打算从PT下载,那么DS220+等型号已经能满足需求。

    3. 运行其他应用

    群晖NAS不仅仅是一个存储设备,它还可以运行各种应用。例如,你可以在上面运行Docker,挂一些自己写的小服务。如果有这方面的需求,那么建议选择x86架构的CPU,例如DS923+或DS920+。

    三、新品VS二手

    由于群晖硬件更新周期较长,因此在市场上有大量的二手设备。如果你的预算有限,那么二手的DS220+或DS216+II都是很好的选择。但是,如果你追求性能,并希望设备能用更长时间,那么建议选择新品。

    四、注意事项

    • NAS并不等于备份:虽然NAS可以存储大量数据,但它并不能代替备份。重要的数据还应该备份到其他地方,例如外部硬盘或云存储。

    • 选择合适的硬盘:NAS的性能和所选硬盘有关。建议选择专为NAS设计的硬盘,例如西部数据的Red系列。

    • 注意网络环境:NAS的传输速度和你家的网络环境有关。如果可能的话,建议使用有线连接,并确保路由器支持千兆速率。

    五、结论

    选择合适的群晖NAS并不难,关键是明确自己的需求,并做好预算。无论你是选择新品还是二手,只要是合适的,都是最好的。

  • AList:将你的文件管理提升到一个全新的高度

    AList:将你的文件管理提升到一个全新的高度

    有一天,我在寻找一个文件列表程序,希望能轻松地管理我分散在各种存储中的文件。我试过了很多解决方案,但它们都不够理想。有的界面复杂,有的功能有限,有的兼容性差。正当我即将放弃的时候,AList走进了我的生活,它简单、强大、兼容性好。我想,在这里分享一下我的经验,也希望AList能帮助到更多的人。

    为什么选择AList?

    你可能会问,市面上有很多文件列表程序,为什么我要选择AList?下面,我为你列举了AList的一些独特功能:

    1. 简单易用

    AList从设计之初就注重用户体验。无论你是新手还是专家,都可以轻松上手。不需要复杂的设置,一切都是那么简单。

    2. 支持多种存储

    你是否有过这样的经历?文件散落在本地硬盘、云盘、外部存储上,查找一个文件需要花费很长时间。但有了AList,这些都不是问题。AList支持多个存储提供商,包括本地存储、阿里云盘、OneDrive、Google Drive等。

    3. WebDAV存储

    你知道WebDAV吗?它是一个文件访问的标准。有了AList,你可以轻松地使用所有WebDAV存储。

    4. 受保护的路由

    安全是我们最关心的问题之一。AList允许你为特定路径添加密码保护和身份验证,确保你的文件安全。

    5. 文件预览

    有时候,我们不仅仅需要管理文件,还需要预览文件内容。AList支持各种文件的预览,包括视频、音频、文档、PDF、图片等。而且,还支持ipa文件的安装!

    6. 打包下载/批量下载

    AList使用浏览器的stream api支持打包下载,不需要服务器的参与。而且,还支持使用Aria2进行批量下载,甚至支持文件夹!

    7. 更多功能

    AList的功能远不止这些。它还有文本编辑器、README/HTML渲染、文件永久链接、Cloudflare Workers代理等功能。每一个功能都是为了提供更好的用户体验。

    结论

    在数字化的时代,文件管理已经成为我们日常生活中不可或缺的一部分。有了AList,这一切都变得简单和高效。我希望我的分享能帮助到你,也希望你能喜欢AList。

  • AList一键脚本:轻松部署的艺术

    AList一键脚本:轻松部署的艺术

    有一天,Andy遇到了一个难题。他需要为公司的大量文件创建一个在线列表,并确保可以轻松访问和更新。传统的方法不仅操作繁琐,而且效率低下。正当他感到困惑时,他发现了AList一键脚本。这是一个为Linux用户提供的神奇工具,不仅安装简单,而且功能强大。Andy决定尝试一下,并被其便捷性和高效性所吸引。这篇文章就是他的亲身体验,希望对你也有所帮助。

    一、什么是AList一键脚本?

    AList是一个为Linux平台设计的一键部署脚本,可以帮助用户轻松安装、更新和管理在线文件列表。它特别适用于那些需要快速部署和管理大量文件的用户。

    二、如何使用AList一键脚本?

    1. 安装

    打开你的Linux终端,输入以下命令:

    curl -fsSL "https://alist.nn.ci/v3.sh" | bash -s install

    这个命令会自动下载和安装AList。

    2. 更新

    如果AList有新的版本发布,你可以使用以下命令进行更新:

    curl -fsSL "https://alist.nn.ci/v3.sh" | bash -s update

    3. 卸载

    如果你不再需要使用AList,可以使用以下命令进行卸载:

    curl -fsSL "https://alist.nn.ci/v3.sh" | bash -s uninstall

    4. 自定义安装路径

    AList默认安装在/opt/alist目录下。如果你想自定义安装路径,可以使用以下命令:

    curl -fsSL "https://alist.nn.ci/v3.sh" | bash -s install /YOUR_PATH

    其中,/YOUR_PATH是你想要的安装路径。

    5. 获取密码

    为了确保安全,AList使用了密码保护。你可以使用以下命令获取密码:

    # 低于v3.25.0版本
    ./alist admin
    
    # 高于v3.25.0版本
    ./alist admin set NEW_PASSWORD

    其中,NEW_PASSWORD是你设置的新密码。

    三、AList一键脚本的优点

    1. 简单易用:AList一键脚本使得安装和管理在线文件列表变得简单易用。

    2. 快速部署:只需几个命令,就可以快速部署AList。

    3. 安全可靠:AList提供了密码保护功能,确保你的文件安全。

    四、结论

    对于那些需要在线管理大量文件的用户,AList一键脚本无疑是一个非常好的选择。它不仅简单易用,而且功能强大。希望这篇文章能帮助你更好地使用AList一键脚本。

  • 内网照片快速同步指南

    内网照片快速同步指南

    曾几何时,我也和你一样,在无尽的互联网海洋中迷失方向,对于怎样在内网环境下快速同步照片感到困惑。我试过了各种备份方案,但始终没有找到那个最满意的。直到有一天,我在一个技术论坛上偶然看到了一篇关于内网同步技术的讨论,我深受启发,并在实践中总结出了一套完美的方法。这篇文章就是基于那些实际经验和技术讨论的结晶,我希望能为同样在这个问题上挣扎的朋友们提供一些帮助。

    一、为什么需要内网同步?

    在数字化的时代,我们的照片、文件、资料等都是数字化存储的。而当这些数据量增大时,传输和备份就成了一个非常重要的问题。特别是照片,它们通常都是大量的、体积大的文件。在互联网环境下,数据传输的速度受到了很多限制,如网络带宽、服务器的性能等。而在内网环境下,数据传输的速度则可以达到其理论最大值,这为快速同步提供了可能。

    二、同步方法及其特点

    1. NFS 或 SMB

    • 特点:简单且快速。NFS和SMB都是网络文件系统协议,可以在不同的操作系统和设备之间分享文件。

    2. Synology photo

    • 特点:专为群晖设备设计的备份工具。使用DSM7的系统,备份速度非常快。

    3. Nextcloud

    • 特点:一款开源的、自托管的云存储解决方案。手机应用上传速度很快。

    4. Resilio Sync 和 Syncthing

    • 特点:这两个都是点对点的文件同步工具。尽管Resilio Sync已经有一段时间没有更新,但它仍然可以正常使用。Syncthing是一个开源的同步工具,它的开发非常活跃。

    5. 使用SSD

    • 特点:SSD的读写速度远超过传统硬盘,使用SSD可以显著提高文件传输的速度。

    6. FTP

    • 特点:如果不需要数据校验(单向增量),FTP是最快的传输方式。

    三、如何选择最适合的同步方法?

    1. 考虑你的设备:不同的设备可能支持不同的同步方法。例如,如果你使用的是群晖设备,那么Synology photo可能是最佳的选择。

    2. 考虑你的需求:你是否需要远程访问?是否需要数据校验?是否需要跨平台同步?

    3. 考虑你的预算:有些同步方法可能需要购买硬件或软件。

    4. 试用几种方法:你可以先试用几种不同的方法,看看哪一种最符合你的需求。

    四、同步步骤示例

    以Syncthing为例,下面是一个简单的同步步骤:

    1. 安装Syncthing:在你的设备上安装Syncthing。

    2. 配置Syncthing:打开Syncthing,选择要同步的文件夹。

    3. 开始同步:在你的其他设备上也安装和配置Syncthing,然后就可以开始同步了。

    五、结语

    选择合适的内网同步方法,不仅可以节省时间,还可以确保数据的安全和完整性。希望这篇文章能为你提供一些帮助,让你的数据同步之旅更加顺利。

  • EdgeGPT 项目介绍:解锁全新Bing GPT聊天功能

    EdgeGPT 项目介绍:解锁全新Bing GPT聊天功能

    故事始于一个充满好奇心的开发者,他对Bing全新GPT聊天功能充满兴趣,但发现官方API存在一些限制。于是,他决定自己动手,进行了反向工程,创建了这个非官方的EdgeGPT项目,以解锁更多人使用Bing GPT聊天功能的可能性。

    安装EdgeGPT

    EdgeGPT的安装非常简单,只需运行以下命令:

    python3 -m pip install EdgeGPT --upgrade

    请注意,EdgeGPT需要Python的版本为3.8或更高版本。根据您的地区,您可能需要一个具有访问https://bing.com/chat的Microsoft帐户。

    配置EdgeGPT

    要使用EdgeGPT,您需要进行一些配置,以便进行身份验证和设置API选项。以下是配置的步骤:

    1. 首先,您需要一个Microsoft帐户,并确保具有访问https://bing.com/chat的权限(根据您的地区可能需要)。

    2. 您可以使用自己的帐户身份验证信息,也可以尝试不使用身份验证(根据地区的不同,可能无需身份验证)。

    3. 如果需要身份验证,您可以尝试提供Cookie以进行身份验证。

    使用EdgeGPT

    您可以使用EdgeGPT通过命令行界面或开发API进行交互。

    命令行界面

    要在命令行中使用EdgeGPT,只需运行以下命令:

    python3 -m EdgeGPT.EdgeGPT -h

    命令行界面支持多种参数选项,以满足不同需求。您可以使用命令行界面与Bing GPT进行互动,并探索其各种功能。

    开发API

    如果您希望在自己的应用程序中使用EdgeGPT,可以使用开发API。以下是一些基本示例:

    基本示例:

    import asyncio, json
    from EdgeGPT.EdgeGPT import Chatbot, ConversationStyle
    
    async def main():
        bot = await Chatbot.create() # 可选地传递Cookie以进行身份验证,如上述配置部分所述
        response = await bot.ask(prompt="Hello world", conversation_style=ConversationStyle.creative, simplify_response=True)
        print(json.dumps(response, indent=2)) # 返回如下数据结构
        """
        {
            "text": str,
            "author": str,
            "sources": list[dict],
            "sources_text": str,
            "suggestions": list[str],
            "messages_left": int
        }
        """
        await bot.close()
    
    if __name__ == "__main__":
        asyncio.run(main())

    Query 和 Cookie 助手类

    您可以使用Query和Cookie助手类来更灵活地生成查询和管理Cookie。这些助手类可帮助您自定义查询和管理Cookie文件。

    使用Docker

    如果您使用Docker,可以使用以下命令运行EdgeGPT,假设您已经在当前工作目录中有一个名为cookies.json的Cookie文件:

    docker run --rm -it -v $(pwd)/cookies.json:/cookies.json:ro -e COOKIE_FILE='/cookies.json' ghcr.io/acheong08/edgegpt

    您还可以添加其他标志来自定义EdgeGPT的行为。

    图像生成器的使用

    EdgeGPT还包括一个图像生成器,可以根据提示生成图像。您可以从命令行界面或Python代码中使用它。

    命令行界面

    要从命令行中使用图像生成器,只需运行以下命令:

    python3 -m ImageGen.ImageGen -h

    命令行界面支持多种参数选项,以满足不同需求。您可以使用图像生成器根据提示生成图像。

    在Python中运行

    如果您希望在Python代码中使用图像生成器,可以使用ImageGen类。以下是一个示例:

    from EdgeGPT.ImageGen import ImageGen
    import argparse
    import json
    
    async def async_image_gen(args) -> None:
        async with ImageGenAsync(args.U, args.quiet) as image_generator:
            images = await image_generator.get_images(args.prompt)
            await image_generator.save_images(images, output_dir=args.output_dir)
    
    if __name__ == "__main__":
        parser = argparse.ArgumentParser()
        # 省略部分参数解析代码,详见上述配置部分
        args = parser.parse_args()
    
        if not args.asyncio:
            image_generator = ImageGen(args.U, args.quiet)
            image_generator.save_images(
                image_generator.get_images(args.prompt),
                output_dir=args.output_dir,
            )
        else:
            asyncio.run(async_image_gen(args))

    结语

    EdgeGPT是一个令人兴奋的项目,它为开发者提供了更多自由和灵活性,以探索和利用Bing GPT聊天功能的潜力。无论您是要创建自己的聊天机器人还是进行创新性的实验,EdgeGPT都可以成为您的强大工具。希望您享受使用EdgeGPT的过程,并探索各种有趣的应用场景!

  • 如何使用Python爬取网页并保存为Word文档

    如何使用Python爬取网页并保存为Word文档

    假设您是一位热衷于收集好文章的人,每天都希望能够快速获取优质文章并保存在本地,以备离线阅读。但是,手动复制粘贴文章内容并保存为Word文档是一项繁琐的任务,特别是当您需要获取大量文章时。在这篇教程中,我将向您介绍如何使用Python编写一个简单但功能强大的网络爬虫,可以帮助您自动从网站上获取文章并保存为Word文档,让您更轻松地构建自己的文章库。

    准备工作

    在开始之前,我们需要准备一些工具和环境:

    1. Python环境:确保您已经安装了Python,最好使用Python 3.x版本。您可以在Python官网上下载并安装最新版本的Python。

    2. 代码编辑器:选择一个您喜欢的代码编辑器,例如PyCharm或Visual Studio Code,以便编写Python脚本。

    3. 必要的库:在本教程中,我们将使用Requests、Beautiful Soup和docx库来进行网络请求、解析HTML和创建Word文档。您可以使用以下命令来安装这些库:

      pip install requests beautifulsoup4 python-docx
    4. 网络连接:确保您的计算机能够连接到互联网,因为我们将从网页上获取文章内容。

    编写Python爬虫脚本

    以下是我们的Python爬虫脚本,它将从指定网站上获取文章并保存为Word文档:

    # -*- coding: utf-8 -*-
    import time
    import random
    import requests
    import re
    from bs4 import BeautifulSoup
    from w3lib.html import remove_tags
    from docx.oxml.ns import qn
    from docx import Document
    from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
    from docx.shared import Pt
    from docx.shared import RGBColor
    
    # 爬取网页
    def get_url(URL, SIGN):
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'}
        html = requests.get(URL, headers=headers)
        html.encoding = 'utf-8'
        soup = BeautifulSoup(html.text, 'lxml')
        text = soup.select(SIGN)
        return text
    
    # 创建doc
    def get_docx(TITLE, BODY):
        document = Document()
        head0 = document.add_heading(level=1)
        head0.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
        title_run = head0.add_run(TITLE)
        title_run.font.size = Pt(24)
        title_run.font.name = 'Times New Roman'
        title_run.element.rPr.rFonts.set(qn('w:eastAsia'), '方正小标宋简体')
        title_run.font.color.rgb = RGBColor(0, 0, 0)
        document.styles['Normal'].font.name = '宋体'
        document.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
        p = document.add_paragraph()
        p_run = p.add_run(BODY)
        p.paragraph_format.space_before = Pt(30)
        p.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
        p.paragraph_format.line_spacing = Pt(28.8)
        p.paragraph_format.first_line_indent = Inches(0.5)
        p_run.font.color.rgb = RGBColor(0, 0, 0)
        p_run.font.size = Pt(16)
        TITLE = re.sub('([^\u4e00-\u9fa5\d])', '', TITLE)
        name = 'D:\\Download\\Articles\\' + TITLE + '.docx'
        document.save(name)
    
    def main():
        n = 0
        menus = get_url('http://www.haoword.com', '.infobox .indexleft .infoco .lm .news_title h2 a')
        menus_url = []
        for menu_url in menus:
            menus_url.append(menu_url['href'])
        print(menus_url)
        for menu_url in menus_url:
            time.sleep(random.random())
            results = get_url(menu_url, '.infobox .lmleft .infoco2 .lm_addon .articles3 ul li a')
            for result in results:
                title_url = result['href']
                title = result['title']
                print(f'{title}:{title_url}')
                time.sleep(random.random())
                articles_results = get_url(title_url, '.infobox .detail .content p')[1:]
                body = remove_tags(str(articles_results))[1:]
                get_docx(title, body)
                n += 1
        print(f'爬取完毕!共爬取 {n} 篇文章。')
    
    if __name__ == '__main__':
        start = time.perf_counter()
        main()
        end = time.perf_counter()
        print(f'耗时 {end - start} 秒。')

    使用说明

    • 在脚本中,我们使用了Requests库来发送HTTP请求,Beautiful Soup来解析HTML内容,以及docx库来创建Word文档。

    • 通过修改get_url函数中的URL和SIGN参数,您可以指定要爬取的网站和文章内容的选择器。

    • 修改get_docx函数中的文档保存路径和格式以适应您的需求。

    • 运行脚本后,它将自动从指定网站上获取文章并保存为Word文档。

    总结

    通过这篇教程,您学会了如何使用Python编写一个简单的网络爬虫,用于爬取网站上的文章并保存为Word文档。这个脚本可以帮助您轻松地建立自己的文章库,方便离线阅读和收藏。希望这对您有所帮助!

  • 如何优化阿里云盘自动签到脚本

    如何优化阿里云盘自动签到脚本

    阿里云盘是一个功能强大的云存储平台,它允许您存储和分享文件。同时,阿里云盘还提供了每日签到功能,可以获得一些小奖励。如果您是一个经常使用阿里云盘的用户,那么自动签到脚本可以帮助您自动完成签到,省去了手动操作的麻烦。在本教程中,我将向您介绍如何编写一个优化的阿里云盘自动签到脚本,以便顺利领取签到奖励。

    开篇故事

    在我们深入讨论如何编写自动签到脚本之前,让我与您分享一个有趣的故事。假设您是一位繁忙的职业人士,每天都要处理大量的工作和文件。您使用阿里云盘来存储和备份重要文件。然而,您也不想错过每日签到奖励,因为这些小奖励可能会积累成大奖励。但是,每天手动签到变得很烦琐,您更希望能够自动完成这个任务。这就是为什么编写一个自动签到脚本非常有帮助的原因。

    准备工作

    首先,我们需要准备一些工具和材料,以便编写和运行自动签到脚本。以下是所需的准备工作:

    1. 阿里云盘账号: 确保您已经拥有一个有效的阿里云盘账号。

    2. 代码编辑器: 您可以选择一个您喜欢的代码编辑器,用于编写脚本。推荐使用Visual Studio Code或PyCharm等现代编辑器。

    3. Java 开发环境: 确保您已经安装了Java开发环境,以便编写和运行Java代码。

    4. RestTemplate库: 我们将使用RestTemplate库来进行HTTP请求,因此需要确保您已经包含了这个库。

    编写自动签到脚本

    接下来,让我们开始编写自动签到脚本。以下是脚本的基本步骤:

    1. 获取访问令牌:首先,我们需要获取访问令牌,以便后续的操作都能够进行身份验证。我们将使用阿里云盘的API来获取访问令牌。

    2. 获取签到列表:一旦我们有了访问令牌,我们可以使用它来获取签到列表,查看今天是否已经签到。

    3. 签到:如果今天还没有签到,我们将执行签到操作,领取奖励。

    4. 奖励领取:最后,我们将检查是否有奖励可领取,并领取奖励。

    下面是代码示例,展示了如何实现这些步骤:

    // 请将您的阿里云盘账号信息和其他配置替换成您自己的值
    
    public class AliyunDriveAutoSignIn {
        private static final String updateAccessTokenURL = "https://auth.aliyundrive.com/v2/account/token";
        private static final String signinURL = "https://member.aliyundrive.com/v2/activity/sign_in_list?_rx-s=mobile";
        private static final String rewardURL = "https://member.aliyundrive.com/v1/activity/sign_in_reward?_rx-s=mobile";
        private static final RestTemplate restTemplate = new RestTemplate();
        public static final HttpHeaders headers = new HttpHeaders();
        private static final String refresh_token = "";
        private static final StringBuffer sb = new StringBuffer();
    
        public static void main(String[] args) {
            headers.add("Content-Type", "application/json");
    
            JSONObject updateAccessTokenData = new JSONObject();
            updateAccessTokenData.put("grant_type", "refresh_token");
            updateAccessTokenData.put("refresh_token", refresh_token);
    
            HttpEntity<String> updateAccessTokenEntity = new HttpEntity<String>(JSONObject.toJSONString(updateAccessTokenData), headers);
            ResponseEntity<String> updateAccessTokenResponse = null;
            try {
                updateAccessTokenResponse = restTemplate.postForEntity(updateAccessTokenURL, updateAccessTokenEntity, String.class);
            } catch (RestClientException e) {
                sb.append("提示 : TOKEN 失效,请更新 !");
                System.out.println(sb);
                return;
            }
            JSONObject updateAccessTokenResult = JSONObject.parseObject(updateAccessTokenResponse.getBody());
            sb.append("------------------获取个人信息成功--------------------" + "\n");
            sb.append("用户名 :" + updateAccessTokenResult.getString("user_name") + "\n");
    
            headers.add("Authorization", updateAccessTokenResult.getString("access_token"));
            JSONObject signinURLData = new JSONObject();
            signinURLData.put("isReward", false);
            HttpEntity<String> signinURLDataEntity = new HttpEntity<String>(JSONObject.toJSONString(signinURLData), headers);
            ResponseEntity<String> signinURLDataResponse = null;
            JSONObject signinURLResult = null;
    
            try {
                signinURLDataResponse = restTemplate.postForEntity(signinURL, signinURLDataEntity, String.class);
                signinURLResult = JSONObject.parseObject(signinURLDataResponse.getBody());
            } catch (RestClientException e) {
                sb.append("提示 : 签到列表获取失败 !");
                System.out.println(sb);
                return;
            }
            String signInCount = signinURLResult.getJSONObject("result").getString("signInCount");
            JSONArray signInLogs = signinURLResult.getJSONObject("result").getJSONArray("signInInfos");
            sb.append("------------------获取签到列表信息成功------------------" + "\n");
            sb.append("本月累计签到 :" + signInCount + "\n");
            JSONObject signDayInLogs = signInLogs.getJSONObject(Integer.valueOf(signInCount) - 1);
            for (int i = 0; i < signInLogs.size(); i++) {
    
                if (signInLogs.getJSONObject(i).getString("status").equals("normal") ) {
                    final String day = signInLogs.getJSONObject(i).getString("day");
                    JSONObject rewardData = new JSONObject();
                    rewardData.put("signInDay", day);
                    HttpEntity<String> rewardDataEntity
    
     = new HttpEntity<String>(rewardData.toJSONString(), headers);
                    ResponseEntity<String> rewardDataResponse = null;
                    JSONObject rewardListDataResult = null;
                    try {
                        rewardDataResponse = restTemplate.postForEntity(rewardURL, rewardDataEntity, String.class);
                        rewardListDataResult = JSONObject.parseObject(rewardDataResponse.getBody());
                        if (rewardListDataResult.getString("success").equals("true")) {
                            sb.append("------------------奖励领取成功--------------------" + "\n");
                            sb.append("奖品名称 :" + rewardListDataResult.getJSONObject("result").getString("name") + "\n");
                            sb.append("奖品名称 :" + rewardListDataResult.getJSONObject("result").getString("description") + "\n");
                            sb.append("奖品名称 :" + rewardListDataResult.getJSONObject("result").getString("notice") + "\n");
                            System.out.println(sb);
                            return;
                        }
                    } catch (RestClientException e) {
                        sb.append("提示 : 奖励领取失败 !");
                        System.out.println(sb);
                        return;
                    }
                }
            }
            sb.append("------------------当天已领取奖励-------------------" + "\n");
            sb.append("奖品名称 :" + signDayInLogs.getJSONObject("reward").getString("name") + "\n");
            sb.append("奖品名称 :" + signDayInLogs.getJSONObject("reward").getString("description") + "\n");
            System.out.println(sb);
        }
    }

    这个脚本首先获取访问令牌,然后检查签到列表,执行签到操作,最后领取奖励(如果有的话)。

  • 本地化Markdown文件中的图片:Python助力批量操作

    本地化Markdown文件中的图片:Python助力批量操作

    在互联网时代,Markdown已经成为写作、博客、文档等多个领域的标配。它简单、高效,但有时我们会遇到一个问题:插入的图片都是网络链接,一旦这些链接失效,文章中的图片就会消失。有没有方法可以快速地将这些在线图片保存到本地,并自动修改Markdown文件的链接呢?答案是肯定的,今天我们就来探讨如何用Python实现这一功能。


    1. 准备工作

    首先,我们需要导入以下库:

    import requests, json, sys, random, time, os, re, openpyxl, urllib.parse, urllib3, glob

    这些库的功能非常丰富,涵盖了网络请求、文件操作、正则表达式等多个领域。


    2. 获取随机User-Agent

    由于频繁的网络请求可能会被服务器屏蔽,为了模拟真实的浏览器行为,我们需要随机选择User-Agent。代码如下:

    def User_gent():
        ...
        return (fackender)

    3. 保存网络图片到本地

    为了保存网络图片到本地,我们需要:

    • 使用requests.get()请求图片链接。
    • 检查响应状态码,确保请求成功。
    • 创建一个本地文件,并将图片内容写入。

    这部分的代码如下:

    def Secone(fileName, FilePath, Fpath):
        ...

    和

    def ChineseSecone_test(fileName, FilePath, Fpath):
        ...

    注意,我们的代码支持文件名中有中文字符,所以提供了两个函数。


    4. 执行程序

    我们使用if __name__=='__main__':来确保代码只在作为主程序时执行,而不是在导入时。用户可以选择操作单个文件或整个目录。


    5. 代码解释

    1. ImgDirectory = 'Image':定义了存放图片的目录。
    2. re.compile(r"[(](https://cdn.nlark.com/.*?)[)]"):使用正则表达式匹配Markdown文件中的图片链接。
    3. os.makedirs():用于在本地创建新目录。

    这个Python脚本是为了解决Markdown中图片链接失效的问题,帮助用户快速将网络图片保存到本地,并自动修改Markdown文件中的链接。无论你是一个博主、写手还是开发者,都可以利用这个脚本来优化你的写作流程。

  • 选择家庭布线:超五类、六类和六类之间的差异与决策

    选择家庭布线:超五类、六类和六类之间的差异与决策

    当小李买了新房后,面对的第一个问题便是家庭网络布线。他从朋友那里听说了超五类、六类和六类的区别,但他对这些术语一头雾水。这次,他决定深入研究这个问题,为家中选择最合适的布线。


    1. 超五类、六类和六类:它们之间有什么区别?

    超五类、六类和六类是当前家庭网络布线的常见选择,但每一种都有其独特的特点。

    • 超五类:是一种更早的标准,支持高达1000Mbps的速度,足够满足大多数家庭的需求。

    • 六类:相较于超五类,六类提供了更高的传输速度,可达10Gbps,但距离有限。

    • 六类高级:是六类的升级版本,支持更长的传输距离。

    2. 如何选择?

    当你面临选择时,要考虑以下几个因素:

    • 家庭需求:如果你的家中主要是浏览网页和看高清视频,超五类可能已经足够。但如果你有更高的网络需求,例如4K视频流或多人在线游戏,那么六类或六类高级可能更适合。

    • 预算:超五类的价格通常低于六类和六类高级,但后者提供了更高的速度。

    • 未来打算:考虑未来可能的网络需求,选择一种可以适应未来需求的布线。

    3. 从实际经验中学习

    • 选择超五类:小李的朋友小张选择了超五类,因为他觉得这对他来说已经足够了。他的家中只有基本的网络需求,如浏览网页和观看视频。

    • 选择六类:小李的另一个朋友小华选择了六类,因为他家中有多人在线游戏,需要更高的网络速度。

    • 选择六类高级:小李的邻居小王选择了六类高级,他计划在未来升级他的网络设备,需要更长的传输距离。


    选择网络布线并不是一个复杂的过程,只需要根据自己的需求和预算做出决策。无论你选择哪种,只要它满足你的需求,那就是正确的选择。