分类: 学习笔记

  • 【HTML】输入Pixiv ID跳转对应画师主页

    Pixiv的应用内部居然没这个功能,不科学,非常基础的功能。

    收录进了小工具页面。👉点击使用小工具

    <body>
        <h1>Pixiv用户跳转</h1>
        <input id="input-id" type="text" placeholder="请输入数字ID" oninput="validateInput()" />
        <div>
            <button onclick="generateLink()">生成链接</button>
            <button onclick="openLink()">跳转</button>
        </div>
        <div id="output"></div>
    
        <script>
            function validateInput() {
                const input = document.getElementById('input-id');
                input.value = input.value.replace(/\D/g, ''); // 只保留数字
            }
    
            function generateLink() {
                const input = document.getElementById('input-id').value.trim();
                const output = document.getElementById('output');
                if (input === '') {
                    output.innerHTML = '<p style="color: red;">请输入有效的数字ID!</p>';
                    return;
                }
                const link = `https://www.pixiv.net/member.php?id=${input}`;
                output.innerHTML = `<a href="${link}" target="_blank">点击跳转到 Pixiv 用户页面</a>`;
            }
    
            function openLink() {
                const input = document.getElementById('input-id').value.trim();
                if (input === '') {
                    alert('您还没有输入ID~');
                    return;
                }
                const link = `https://www.pixiv.net/member.php?id=${input}`;
                window.open(link, '_blank');
            }
        </script>
    </body>
  • 【Node.js】批量导出微信联系人到Excel表格(基于Wechaty)

    用到的库:

    wechaty: 一个用于开发微信聊天机器人的框架。

    qrcode-terminal: 用于生成终端二维码的库。

    xlsx: 用于处理 Excel 文件的库。

    fspath: Node.js 的内置文件系统模块,用于文件操作。

    file-box: 用于处理文件(如图片)的库。

    uuid: 用于生成唯一标识符(UUID)的库。

    工作原理:

    基于wechaty的api,获取相应信息并批量导出到excel表格中,头像文件夹单独放置。可以在WPS中依靠UUID生成的唯一ID来快速批量嵌入头像。

    可惜标签功能不在Wechaty的功能中,也没法导出手机号等更有价值的信息,目前能导出的信息不多,图一乐。

    const { WechatyBuilder } = require('wechaty');
    const qrcode = require('qrcode-terminal');
    const xlsx = require('xlsx');
    const fs = require('fs');
    const path = require('path');
    const { FileBox } = require('file-box');
    const { v4: uuidv4 } = require('uuid');  // 引入 UUID 库
    
    const outputDir = './avatars/';  // 存储头像的文件夹
    
    // 确保头像目录存在
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir);
    }
    
    class WeChaty {
      bot = null;
    
      constructor() {
        this.bot = WechatyBuilder.build();
        this.bot.on('scan', code => {
          qrcode.generate(code, { small: true });
        });
        this.bot.on('login', user => {
          console.log(`登录成功,欢迎 ${user}`);
          this.waitForContacts();  // 登录后开始等待联系人同步
        });
      }
    
      // 随机延时函数,返回一个 Promise,用于模拟短时延时
      delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
      }
    
      // 每10秒检查一次联系人数量,最多检查10次
      async waitForContacts() {
        let previousCount = 0;
        let currentCount = 0;
        let attempts = 0;
    
        while (attempts < 10) {
          const allContacts = await this.bot.Contact.findAll();  // 获取所有联系人
          currentCount = allContacts.length;
    
          if (currentCount === previousCount) {
            console.log('联系人数量没有变化,开始导出');
            break;  // 如果联系人数量没有变化,则认为同步完成
          }
    
          console.log(`当前联系人数量: ${currentCount}, 尝试次数: ${attempts + 1}`);
          previousCount = currentCount;
          attempts++;
    
          await this.delay(10000);  // 每次等待10秒再检查
        }
    
        if (attempts >= 10) {
          console.log('尝试多次后联系人数量没有变化,开始导出');
        }
    
        // 导出联系人
        this.getAllFriendContacts();
      }
    
      // 获取所有好友联系人
      async getAllFriendContacts() {
        const allContacts = await this.bot.Contact.findAll();  // 获取所有联系人
    
        // 只筛选出好友联系人
        const friendContacts = allContacts.filter(contact => 
          contact.friend() && contact.type() === this.bot.Contact.Type.Individual
        );
    
        console.log(`总共获取了 ${friendContacts.length} 个好友联系人`);
    
        if (friendContacts.length > 0) {
          await this.exportContacts(friendContacts);  // 导出好友联系人
        }
      }
    
      // 获取并保存联系人头像
      async saveAvatar(contact) {
        try {
          const avatarFile = await contact.avatar();
          if (avatarFile) {
            const cleanName = contact.name().replace(/[\/\\:*?"<>|]/g, '_');  // 清理非法字符
            const uniqueName = `${cleanName}_${uuidv4()}`;  // 使用清理后的昵称 + UUID 作为文件名
            const avatarPath = path.join(outputDir, uniqueName + '.jpg');  // 存储路径
    
            await avatarFile.toFile(avatarPath, true);  // 保存头像文件
            return uniqueName;  // 返回不带后缀的文件名
          }
        } catch (error) {
          console.log(`获取 ${contact.name()} 头像失败`);
        }
        return '';  // 如果获取失败,返回空字符串
      }
    
      // 导出联系人信息
      async exportContacts(allContacts) {
        try {
          const contactList = [];
    
          const avatarPromises = allContacts.map(async (contact) => {
            // 获取头像文件名
            const avatarFileName = await this.saveAvatar(contact);  
    
            // 只导出有头像的联系人,且即使没有昵称也会保留
            return {
              昵称: contact.name().trim() || '无昵称',  // 如果没有昵称,则使用 '无昵称'
              备注: (await contact.alias())?.trim() || '',  // 获取备注信息
              性别: contact.gender() === this.bot.Contact.Gender.Male ? '男' : 
                    contact.gender() === this.bot.Contact.Gender.Female ? '女' : '未知',  // 性别
              省份: contact.province()?.trim() || '',  // 获取省份
              城市: contact.city()?.trim() || '',  // 获取城市
              文件名: avatarFileName,  // 保存文件名(不带后缀)
            };
          });
    
          // 等待所有头像保存完毕
          const contactData = await Promise.all(avatarPromises);
    
          // 使用 xlsx 库导出 Excel 表格
          const ws = xlsx.utils.json_to_sheet(filteredContactData);  // 将联系人信息转换为 Excel 表格
          const wb = xlsx.utils.book_new();  // 创建一个新的 Excel 工作簿
          xlsx.utils.book_append_sheet(wb, ws, '联系人');  // 将联系人数据添加到工作簿
    
          // 将工作簿保存为 Excel 文件
          xlsx.writeFile(wb, 'contacts_with_details.xlsx');
          console.log('好友联系人信息已成功导出到 contacts_with_details.xlsx');
        } catch (error) {
          console.error('导出联系人信息失败:', error);
        }
      }
    
      run() {
        this.bot.start();
      }
    }
    
    new WeChaty().run();
    
  • 【Python】按照关键词查找相应PPT

    今天巧了,好几个同事问我要PPT,但是他们只能记得起来一些关键词,而我恰好也没有很足的印象,毕竟那是两三年前,还可能不是我做的东西!

    WPS只能按照云文档进行查找关键词,那么电脑中几千个PPT要怎么找呢?(没错我电脑里真有2000个PPT (((φ(◎ロ◎;)φ))))

    我们可以根据他们截取的画面关键词,来对PPT进行索引,这样可以节约一些查找文件的时间,然后采用olefile库,查找对应PPT即可。

    import os
    from pptx import Presentation
    import olefile
    
    def is_powerpoint_file(file_path):
        """检查文件是否为PPT或PPTX格式"""
        valid_extensions = ['.ppt', '.pptx']
        return any(file_path.lower().endswith(ext) for ext in valid_extensions)
    
    def index_powerpoint_files(search_dir):
        """索引指定目录中的所有PPT和PPTX文件"""
        ppt_files = []
        total_files = 0
    
        for root, _, files in os.walk(search_dir):
            total_files += len(files)
            for file in files:
                if file.startswith("~$"):  # 跳过临时文件
                    continue
                file_path = os.path.join(root, file)
                if is_powerpoint_file(file_path):
                    ppt_files.append(file_path)
        
        print(f"[信息] 已索引文件总数:{total_files},PPT文件总数:{len(ppt_files)}")
        return ppt_files
    
    def search_text_in_pptx(file_path, target_text):
        """在PPTX文件中搜索目标文字"""
        try:
            presentation = Presentation(file_path)
            for slide in presentation.slides:
                for shape in slide.shapes:
                    if shape.has_text_frame and target_text in shape.text:
                        return True
        except Exception as e:
            print(f"[错误] 无法处理文件:{file_path},错误信息:{e}")
        return False
    
    def search_text_in_ppt(file_path, target_text):
        """在PPT文件中搜索目标文字"""
        try:
            if olefile.isOleFile(file_path):
                with olefile.OleFileIO(file_path) as ole:
                    if "PowerPoint Document" in ole.listdir():
                        stream = ole.openstream("PowerPoint Document")
                        content = stream.read().decode(errors="ignore")
                        if target_text in content:
                            return True
        except Exception as e:
            print(f"[错误] 无法处理文件:{file_path},错误信息:{e}")
        return False
    
    def search_text_in_powerpoint_files(ppt_files, target_text):
        """在索引的PPT文件中搜索目标文字"""
        result_files = []
        total_files = len(ppt_files)
    
        print(f"[信息] 开始内容搜索,共需处理 {total_files} 个文件")
        for idx, file_path in enumerate(ppt_files, start=1):
            print(f"[处理中] {idx}/{total_files} - 正在处理文件:{file_path}")
            if file_path.lower().endswith(".pptx") and search_text_in_pptx(file_path, target_text):
                result_files.append(file_path)
            elif file_path.lower().endswith(".ppt") and search_text_in_ppt(file_path, target_text):
                result_files.append(file_path)
    
        return result_files
    
    if __name__ == "__main__":
        search_dir = "D:\\"
        target_text = input("请输入要查找的文字(支持中文):")
        
        print(f"[信息] 正在索引盘中的PPT文件,请稍候...\n")
        ppt_files = index_powerpoint_files(search_dir)
        
        if ppt_files:
            print(f"\n[信息] 索引完成,开始搜索包含 '{target_text}' 的文件...\n")
            matching_files = search_text_in_powerpoint_files(ppt_files, target_text)
            if matching_files:
                print("\n[结果] 找到包含目标文字的PPT文件:")
                for file in matching_files:
                    print(file)
            else:
                print("\n[结果] 未找到包含该文字的PPT文件。")
        else:
            print("\n[信息] 未在指定目录中找到任何PPT文件。")