{"id":15509883,"url":"https://github.com/atorber/puppet-xp-getting-started","last_synced_at":"2025-04-23T02:53:15.363Z","repository":{"id":37017942,"uuid":"418750653","full_name":"atorber/puppet-xp-getting-started","owner":"atorber","description":"基于wechaty-puppet-xp的Windows微信机器人","archived":false,"fork":false,"pushed_at":"2024-03-29T06:47:28.000Z","size":187,"stargazers_count":47,"open_issues_count":6,"forks_count":12,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-23T02:53:09.512Z","etag":null,"topics":["chatbot","wechat","wechaty"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/atorber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-19T03:04:43.000Z","updated_at":"2025-04-16T03:42:25.000Z","dependencies_parsed_at":"2024-01-19T08:32:08.745Z","dependency_job_id":"a86ae230-d785-4289-99ba-e4f995bfc29c","html_url":"https://github.com/atorber/puppet-xp-getting-started","commit_stats":null,"previous_names":["atorber/puppet-xp-getting-started"],"tags_count":0,"template":true,"template_full_name":"padlocal/wechaty-puppet-padlocal-demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atorber%2Fpuppet-xp-getting-started","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atorber%2Fpuppet-xp-getting-started/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atorber%2Fpuppet-xp-getting-started/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atorber%2Fpuppet-xp-getting-started/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atorber","download_url":"https://codeload.github.com/atorber/puppet-xp-getting-started/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250360259,"owners_count":21417718,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chatbot","wechat","wechaty"],"created_at":"2024-10-02T09:44:45.753Z","updated_at":"2025-04-23T02:53:15.342Z","avatar_url":"https://github.com/atorber.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wechaty Puppet XP Getting Started\r\n\r\n[![Powered by Wechaty](https://img.shields.io/badge/Powered%20By-atorber-brightgreen.svg)](https://github.com/atorber/puppet-xp-getting-started)\r\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-blue.svg)](https://www.typescriptlang.org/)\r\n[![GitHub stars](https://img.shields.io/github/stars/atorber/puppet-xp-getting-started.svg?label=github%20stars)](https://github.com/atorber/puppet-xp-getting-started)\r\n \u003cimg alt=\"GitHub forks badge\" src=\"https://img.shields.io/github/forks/atorber/puppet-xp-getting-started\"\u003e\r\n\r\n## 简介\r\n\r\n本项目是基于开源聊天机器人社区[Wechaty](https://github.com/wechaty)的[puppet-xp](https://github.com/wechaty/puppet-xp)项目开发微信聊天机器人快速入门和最佳实践，支持Windows微信客户端3.3.0.115，3.6.0.18, 3.9.2.23版本。\r\n\r\n优点：\r\n\r\n- 一键运行，免dll注入\r\n- Wechaty社区支持\r\n\r\n## 免责声明\r\n\r\n本仓库发布的内容，仅用于学习研究，请勿用于非法用途和商业用途！如因此产生任何法律纠纷，均与作者无关！\r\n\r\n运行微信机器人可能会造成封号等后果，。请自行承担风险。仅用于学习研究，请勿于非法用途。\r\n\r\n## 功能支持\r\n\r\n完全取决于[puppet-xp](https://github.com/wechaty/puppet-xp)项目的支持程度，目前支持的最新微信版本为3.9.2.23，最稳定的版本为3.6.0.18\r\n\r\n版本|3.3.0.115|3.6.0.18|3.9.2.23|\r\n:---|:---|:---|:---|\r\n**\u003c消息\u003e**|\r\n接收文本|✅|✅|✅\r\n接收图片|✅|✅|✅\r\n接收文件|✅|✅|✅\r\n接收动图|✅|✅|✅\r\n接收表情|✅|✅|✅\r\n接收小程序卡片|✅|✅|✅\r\n接收联系人卡片|✅|✅|✅\r\n接收位置卡片|✅|✅|✅\r\n发送文本|✅|✅|✅\r\n发送图片|✅|✅|✅\r\n发送文件|✅|✅|✅\r\n发送动图|✅|✅|✅\r\n**\u003c群组\u003e**|\r\n@群成员|✅|✅|✅\r\n群列表|✅|✅|✅\r\n群成员列表|✅|✅|✅\r\n群详情|✅|✅|✅\r\n进群提示|✅|✅|✅\r\n**\u003c联系人\u003e**|\r\n好友列表|✅|✅|✅\r\n好友详情|✅|✅|✅\r\n**\u003c其他\u003e**|\r\n登录事件|✅|✅|✅\r\n扫码登录|||✅\r\n\r\n## 快速开始\r\n\r\nwechaty-puppet-xp仅支持windows操作系统下使用,微信版本需要于npm包版本对应。快速开始默认使用3.9.2.23版本的微信。\r\n\r\n### 1. 检查微信客户端并登陆\r\n\r\n检查电脑上微信版本是否是支持的版本（如果不是必须下载指定版，如果是则不需要重新安装），正常**登陆微信**，如当前电脑微信版本不符，需要\r\n[下载WeChatSetup-v3.9.2.23.exe](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)\r\n\r\n### 2. 安装并检查当前nodejs环境\r\n\r\n[下载安装16LTS版本nodejs](https://nodejs.org/)，检查node版本 \u003e= v16.0.0\r\n\r\n```\r\nnode -v\r\n\r\nPS C:\\Users\\Administrator\\Documents\\GitHub\\wechaty-puppet-xp-demo\u003e node -v\r\nv16.15.0\r\n``` \r\n\r\n### 3. 下载demo代码 [puppet-xp-getting-started](https://github.com/atorber/puppet-xp-getting-started) \r\n\r\n```\r\ngit clone https://github.com/atorber/puppet-xp-getting-started\r\n```\r\n\r\n### 4.安装依赖\r\n\r\n```\r\ncd puppet-xp-getting-started\r\nnpm i wechaty-puppet-xp@next\r\nnpm install\r\n``` \r\n\r\n\u003e 如安装失败可手动安装puppet-xp，运行`npm i wechaty-puppet-xp@next`\r\n\r\n### 5. 启动程序\r\n\r\n**确保PC上的微信已处于登录状态状态，确认版本为v3.9.2.23**\r\n\r\n```\r\nnpm run start\r\n```\r\n\r\n显示类似如下，说明启动成功\r\n\r\n```\r\nPS C:\\Users\\Administrator\\Documents\\GitHub\\wechaty-puppet-xp-demo\u003e npm run start\r\n\r\n\u003e wechaty-puppet-xp-demo@0.2.2 start\r\n\u003e cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node ./src/index.ts\r\n\r\n01:42:54 INFO options... {\"version\":\"3.9.2.23\"}\r\n01:42:57 INFO StarterBot Starter Bot Started.\r\n01:43:12 INFO onLogin Contact\u003c大师\u003e login\r\n01:43:13 INFO 当前登录账号信息： Contact\u003c大师\u003e\r\n01:43:13 INFO 微信号查找联系人： Contact\u003c文件传输助手\u003e\r\n01:43:13 INFO 昵称查找联系人： Contact\u003c文件传输助手\u003e\r\n01:43:13 INFO 备注名称查找联系人： 没有找到联系人\r\n01:43:13 INFO 群ID查找群： Room\u003c大师是群主\u003e\r\n01:43:13 INFO 群名称查找群： Room\u003c大师是群主\u003e\r\n01:43:13 INFO 联系人数量： 6271\r\n01:43:13 INFO 群数量： 53\r\n```\r\n\r\n| 运行 | 对应程序 | 说明 |\r\n| :------------- |:-------------| :-----|\r\n| `npm start` | [src/indext.ts](src/index.ts) | ts代码示例 |\r\n| `npm run start:js` | [src/ding-dong-bot.js](examples/ding-dong-bot.js) | js代码示例 |\r\n\r\n## 代码示例\r\n\r\n```\r\n#!/usr/bin/env -S node --no-warnings --loader ts-node/esm\r\n/**\r\n * wechaty-puppet-xp示例代码，可以作为模版编写自己的业务逻辑.\r\n *  \r\n**/\r\nimport 'dotenv/config.js'\r\n\r\nimport {\r\n    Contact,\r\n    Message,\r\n    ScanStatus,\r\n    WechatyBuilder,\r\n    log,\r\n    types,\r\n} from 'wechaty'\r\n\r\nimport qrcodeTerminal from 'qrcode-terminal'\r\nimport { FileBox } from 'file-box'\r\n\r\nconst onScan = (qrcode: string, status: ScanStatus) =\u003e {\r\n    if (status === ScanStatus.Waiting || status === ScanStatus.Timeout) {\r\n        const qrcodeImageUrl = [\r\n            'https://wechaty.js.org/qrcode/',\r\n            encodeURIComponent(qrcode),\r\n        ].join('')\r\n        log.info('onScan: %s(%s) - %s', ScanStatus[status], status, qrcodeImageUrl)\r\n\r\n        qrcodeTerminal.generate(qrcode, { small: true })  // show qrcode on console\r\n\r\n    } else {\r\n        log.info('onScan: %s(%s)', ScanStatus[status], status)\r\n    }\r\n}\r\n\r\nconst onLogin = async (user: Contact) =\u003e {\r\n    log.info('onLogin', '%s login', user)\r\n    // 登录成功后调用bot\r\n    main()\r\n}\r\n\r\nconst onLogout = (user: Contact) =\u003e {\r\n    log.info('onLogout', '%s logout', user)\r\n}\r\n\r\nconst onMessage = async (msg: Message) =\u003e {\r\n    log.info('onMessage', JSON.stringify(msg))\r\n    // Message doc : https://wechaty.js.org/docs/api/message#messageage--number\r\n\r\n    const talker = msg.talker() // 发消息人\r\n    const listener = msg.listener() // 接收消息人\r\n    const room = msg.room() // 是否是群消息\r\n    const text = msg.text() // 消息内容\r\n    const type = msg.type() // 消息类型\r\n    const self = msg.self() // 是否自己发给自己的消息\r\n\r\n    log.info('talker', JSON.stringify(talker))\r\n    log.info('listener', listener||'undefined')\r\n    log.info('room', room || 'undefined')\r\n    log.info('text', text)\r\n    log.info('type', type)\r\n    log.info('self', self?'true':'false')\r\n\r\n    try {\r\n        switch (text) {\r\n            case 'ding': // 接收到的消息是ding，回复dong\r\n                await msg.say('dong')\r\n                break\r\n            case 'send text': // 接收到的消息是send text，发送文本消息\r\n                await msg.say('this is a test text')\r\n                break\r\n            case 'send image': // 接收到的消息是send image，发送图片\r\n                const image = FileBox.fromFile('file/ledongmao.jpg')\r\n                await msg.say(image)\r\n                break\r\n            case 'send file': // 接收到的消息是send file，发送文件\r\n                const fileBox = FileBox.fromUrl('https://wechaty.js.org/assets/logo.png')\r\n                await msg.say(fileBox)\r\n                break\r\n            case 'send video': // 接收到的消息是send video，发送视频\r\n                const video = FileBox.fromUrl('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4')\r\n                await msg.say(video)\r\n                break\r\n            case 'send audio': // 接收到的消息是send audio，发送音频\r\n                const audio = FileBox.fromUrl('http://www.zhongguoyinhang.com/upload/2018-11/201811161154314128.mp3')\r\n                await msg.say(audio)\r\n                break\r\n            case 'send emotion': // 接收到的消息是send emotion，发送表情\r\n                const emotion = FileBox.fromUrl('https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/0.gif')\r\n                await msg.say(emotion)\r\n                break\r\n            default:\r\n                break\r\n        }\r\n    } catch (e) {\r\n        console.log('回复消息失败...', e)\r\n    }\r\n\r\n    try{\r\n        switch (type) {\r\n            case types.Message.Text: // 接收到的消息是文本\r\n                log.info('接收到的消息是文本')\r\n                log.info('消息内容：', text)\r\n                break\r\n            case types.Message.Image: // 接收到的消息是图片\r\n                log.info('接收到的消息是图片')\r\n                const image = await msg.toImage().thumbnail()  // Save the media message as a FileBox\r\n                const filePath = 'file/' + image.name\r\n                try {\r\n                    image.toFile(filePath, true)\r\n                    log.info(`Saved file: ${filePath}`)\r\n                } catch (e) {\r\n                    log.error('保存文件错误：', e)\r\n                }\r\n                break\r\n            case types.Message.Attachment: // 接收到的消息是附件\r\n                log.info('接收到的消息是附件')\r\n                const attachment = await msg.toFileBox()  // Save the media message as a FileBox\r\n                const attachmentPath = 'file/' + attachment.name\r\n                try {\r\n                    attachment.toFile(attachmentPath, true)\r\n                    log.info(`Saved file: ${attachmentPath}`)\r\n                } catch (e) {\r\n                    log.error('保存文件错误：', e)\r\n                }\r\n                break\r\n            case types.Message.Video: // 接收到的消息是视频\r\n                log.info('接收到的消息是视频')\r\n                const video = await msg.toFileBox()  // Save the media message as a FileBox\r\n                const videoPath = 'file/' + video.name\r\n                try {\r\n                    video.toFile(videoPath, true)\r\n                    log.info(`Saved file: ${videoPath}`)\r\n                } catch (e) {\r\n                    log.error('保存文件错误：', e)\r\n                }\r\n                break\r\n            case types.Message.Audio: // 接收到的消息是音频\r\n                log.info('接收到的消息是音频')\r\n                break\r\n            case types.Message.Emoticon: // 接收到的消息是表情\r\n                log.info('接收到的消息是表情')\r\n                const emoticon = await msg.toFileBox()  // Save the media message as a FileBox\r\n                const emoticonPath = 'file/' + emoticon.name\r\n                try {\r\n                    emoticon.toFile(emoticonPath, true)\r\n                    log.info(`Saved file: ${emoticonPath}`)\r\n                } catch (e) {\r\n                    log.error('保存文件错误：', e)\r\n                }\r\n                break\r\n            case types.Message.Url: // 接收到的消息是链接\r\n                log.info('接收到的消息是链接')\r\n                try {\r\n                    const urlLink = await msg.toUrlLink()\r\n                    log.info('链接标题：', urlLink.title)\r\n                    log.info('链接地址：', urlLink.url)\r\n                } catch (e) {\r\n                    log.error('获取链接错误：', e)\r\n                }\r\n                break\r\n            case types.Message.MiniProgram: // 接收到的消息是小程序\r\n                log.info('接收到的消息是小程序')\r\n                try {\r\n                    const miniProgram = await msg.toMiniProgram()\r\n                    log.info('小程序标题：', miniProgram.title)\r\n                    log.info('小程序描述：', miniProgram.description)\r\n                    log.info('小程序页面地址：', miniProgram.pagePath)\r\n                    log.info('小程序缩略图：', miniProgram.thumbUrl)\r\n                } catch (e) {\r\n                    log.error('获取小程序错误：', e)\r\n                }\r\n                break\r\n            case types.Message.Transfer: // 接收到的消息是转账\r\n                log.info('接收到的消息是转账')\r\n                break\r\n            case types.Message.RedEnvelope: // 接收到的消息是红包\r\n                log.info('接收到的消息是红包')\r\n                break\r\n            case types.Message.Recalled: // 接收到的消息是撤回的消息\r\n                log.info('接收到的消息是撤回的消息')\r\n                break\r\n            case types.Message.Location: // 接收到的消息是位置\r\n                log.info('接收到的消息是位置')\r\n                break\r\n            case types.Message.GroupNote: // 接收到的消息是群公告\r\n                log.info('接收到的消息是群公告')\r\n                break\r\n            case types.Message.Contact: // 接收到的消息是联系人名片\r\n                log.info('接收到的消息是联系人名片')\r\n                break\r\n            case types.Message.ChatHistory: // 接收到的消息是聊天记录\r\n                log.info('接收到的消息是聊天记录')\r\n                break\r\n            case types.Message.Post: // 接收到的消息是公众号文章\r\n                log.info('接收到的消息是公众号文章')\r\n                break\r\n            case types.Message.Unknown: // 接收到的消息是未知类型\r\n                log.info('接收到的消息是未知类型')\r\n                break\r\n            default:\r\n                break\r\n        }\r\n    }catch(e){\r\n        console.log('处理消息失败...', e)\r\n    }\r\n    // 关键词回复,同时也是发送消息的方法\r\n}\r\n\r\nconst bot = WechatyBuilder.build({\r\n    name: 'ding-dong-bot',\r\n    puppet: 'wechaty-puppet-xp',\r\n    puppetOptions: {\r\n        version: '3.9.2.23',\r\n    }\r\n})\r\n\r\nbot.on('scan', onScan)\r\nbot.on('login', onLogin)\r\nbot.on('logout', onLogout)\r\nbot.on('message', onMessage)\r\n\r\nbot.start()\r\n    .then(async () =\u003e {\r\n        log.info('StarterBot', 'Starter Bot Started.')\r\n    })\r\n    .catch(e =\u003e log.error('StarterBot', e))\r\n\r\nconst main = async () =\u003e {\r\n\r\n    // 获取当前登录微信信息\r\n    try {\r\n        const self = bot.currentUser\r\n        log.info('当前登录账号信息：', self)\r\n    } catch (e) {\r\n        log.error('get user failed', e)\r\n    }\r\n\r\n    // 通过微信号搜索联系人\r\n    try {\r\n        const contactById = await bot.Contact.find({\r\n            id: 'filehelper'\r\n        })\r\n        log.info('微信号查找联系人：', contactById)\r\n        // 向联系人发送消息\r\n        contactById?.say('向指定好友微信号发送消息')\r\n    } catch (e) {\r\n        log.error('contactByWeixin', e)\r\n    }\r\n\r\n    // 通过昵称搜索联系人\r\n    try {\r\n        const contactByName = await bot.Contact.find({\r\n            name: '文件传输助手'\r\n        })\r\n        log.info('昵称查找联系人：', contactByName)\r\n        // 向联系人发送消息\r\n        contactByName?.say('向指定好友昵称发送消息')\r\n    } catch (e) {\r\n        log.error('contactByName', e)\r\n    }\r\n\r\n    // 通过备注搜索联系人\r\n    try {\r\n        const contactByAlias = await bot.Contact.find({\r\n            alias: '超哥'\r\n        })\r\n        log.info('备注名称查找联系人：', contactByAlias || '没有找到联系人')\r\n        // 向联系人发送消息\r\n        contactByAlias?.say('向指定好友备注好友发送消息')\r\n    } catch (e) {\r\n        log.error('contactByAlias', e)\r\n    }\r\n\r\n    try {\r\n        // 通过群ID搜索群\r\n        const roomById = await bot.Room.find({\r\n            id: '21341182572@chatroom'\r\n        })\r\n        log.info('群ID查找群：', roomById)\r\n        // 向群里发送消息\r\n        roomById?.say('向指定群ID发送消息')\r\n    } catch (e) {\r\n        log.error('roomById', e)\r\n    }\r\n\r\n    try {\r\n        // 通过群名称搜索群\r\n        const roomByName = await bot.Room.find({\r\n            topic: '大师是群主'\r\n        })\r\n        log.info('群名称查找群：', roomByName || '没有找到群')\r\n        // 向群里发送消息\r\n        roomByName?.say('向指定群名称发送消息')\r\n    } catch (e) {\r\n        console.log('roomByName', e)\r\n    }\r\n\r\n    try {\r\n        // 获取所有联系人\r\n        const contactList = await bot.Contact.findAll()\r\n        // log.info('获取联系人列表：', contactList)\r\n        log.info('联系人数量：', contactList.length)\r\n    } catch (e) {\r\n        log.error('contactList', e)\r\n    }\r\n\r\n    try {\r\n        // 获取所有群\r\n        const roomList = await bot.Room.findAll()\r\n        // log.info('获取群列表：', roomList)\r\n        log.info('群数量：', roomList.length)\r\n    } catch (e) {\r\n        log.error('roomList', e)\r\n    }\r\n\r\n}\r\n\r\n```\r\n\r\n## 版本支持\r\n\r\n本项目随wechaty-puppet-xp更新，支持多个微信版本，可自行切换微信版本及对应的npm版本\r\n\r\npuppet-xp|微信客户端下载|npm包安装|\r\n|:---|:---|:---|\r\n|1.3.x|[WeChat-v3.9.2.23](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.9.2.23/WeChatSetup-3.9.2.23.exe)|npm i wechaty-puppet-xp@next|\r\n|1.12.7|[WeChat-v3.6.0.18](https://github.com/tom-snow/wechat-windows-versions/releases/download/v3.6.0.18/WeChatSetup-3.6.0.18.exe)|npm i wechaty-puppet-xp@1.12.7|\r\n|1.11.14|[WeChat-v3.3.0.115](https://github.com/wechaty/wechaty-puppet-xp/releases/download/v0.5/WeChatSetup-v3.3.0.115.exe)|npm i wechaty-puppet-xp@1.11.14|\r\n\r\n## 相关项目\r\n\r\n- [wechaty-puppet-xp](https://github.com/wechaty/puppet-xp) 项目源码\r\n\r\n- [ChatFlow](https://github.com/atorber/chatflow) ChatFlow聊天机器人管理系统\r\n\r\n## 参考\r\n\r\n- [喜讯：使用Windows微信桌面版协议登录，wechaty免费版协议即将登场, @atorber, Jul 05, 2021](https://wechaty.js.org/2021/07/05/puppet-laozhang-wechat-bot/)\r\n- [全新的Windows puppet项目wechaty-puppet-xp启动, @atorber, Jul 13, 2021](https://wechaty.js.org/2021/07/13/wechaty-puppet-xp-start-up/)\r\n- [code如诗，bot如歌，由Wechaty引发的一个小白冒险之旅, @老张学技术, Jul 05, 2021](https://wechaty.js.org/2021/07/05/code-like-poetry-bot-like-song/)\r\n\r\n- [Wechaty Official Website](https://wechaty.js.org/docs/puppet-providers/xp)\r\n\r\n [![Star History Chart](https://api.star-history.com/svg?repos=atorber/puppet-xp-getting-started\u0026type=Date)](https://star-history.com/#atorber/puppet-xp-getting-started\u0026Date)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatorber%2Fpuppet-xp-getting-started","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatorber%2Fpuppet-xp-getting-started","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatorber%2Fpuppet-xp-getting-started/lists"}