├── .gitignore ├── LICENSE ├── README.md ├── config.js ├── doc ├── cnpm.jpg ├── email.jpg ├── getcookie.jpg └── setcookie.jpg ├── lib ├── fu.js ├── mail-template.ejs ├── mail.js ├── request_https.js └── utils.js ├── lin.js ├── main.js ├── package.json └── smzdm.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 午休随笔 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # puppeteer-sign 2 | 3 | 基于 puppeteer,什么值得买签到,完全模拟人工点击 4 | 5 | ## 使用方法 6 | 7 | ### 依赖环境 8 | 9 | `nodejs` 最好使用最新稳定版v12 https://nodejs.org/en/download/ 10 | 11 | ### 安装依赖 12 | 13 | 由于`puppeteer`需要安装软件包,推荐使用国内淘宝镜像安装 14 | cnpm 安装 `npm i cnpm -g` 15 | 16 | ```bash 17 | cnpm i 18 | ``` 19 | 20 | ![](doc/cnpm.jpg) 21 | 22 | ### 参数配置 23 | 24 | #### 邮箱配置 25 | 26 | >默认配置的是126的邮箱登录信息 27 | > 28 | >也可以用其他平台的邮箱,详见`/lib/mail.js` 文件中的说明 29 | 30 | 打开根目录的 `config.js` 文件,根据下图配置 31 | ![](doc/email.jpg) 32 | 33 | 34 | 邮件会发送每天的截图信息,方便查阅。 35 | 36 | #### 什么值得买 cookie配置 37 | 38 | 依赖 chrome 插件 `editthiscookie` 用来取网站cookie,有梯子的直接应用商店安装即可,没梯子的,可以百度搜搜安装一下。 39 | 40 | 具体步骤详解 41 | 1. 打开 `https://www.smzdm.com/` 官网并登录 42 | 2. 点开 `editthiscookie` 插件然后点如下图按钮 43 | ![](doc/getcookie.jpg) 44 | 3. 把复制的cookie粘贴到下图中 45 | ![](doc/setcookie.jpg) 46 | 47 | 48 | > 支持多个账号 49 | 50 | ### 执行 51 | 52 | > 推荐使用 `pm2` ,具体可以详见 `https://www.jianshu.com/p/e15fd72727fe` 53 | 54 | ```bash 55 | # 可以用node直接运行 56 | node main 57 | 58 | # 通过pm2执行 59 | pm2 start main.js 60 | 61 | # 查看运行日志 62 | pm2 log main 63 | ``` 64 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 项目配置表 3 | * @Author: xuess 4 | * @Date: 2019-06-04 17:29:18 5 | * @LastEditors: 午休 6 | * @LastEditTime: 2020-09-09 21:02:05 7 | */ 8 | 9 | // email 登陆账号 如:xxxx@126.com 默认使用的是 126的邮箱登录的。可以自行配置 10 | const emailName = 'xxxx@126.com'; 11 | // email 登陆密码 12 | const emailPassword = '123456'; 13 | 14 | // 接收者 邮箱 15 | const toEmail = 'xxxx@qq.com'; 16 | 17 | //用于签到的 账号信息 列表 18 | const cookieListValKey = [ 19 | { 20 | type: 'smzdm', 21 | username: '账号1', 22 | phone: '账号1', 23 | // 数组类型的 cookies 24 | cookies: [{xxx:'xxx'}] 25 | }, 26 | { 27 | type: 'smzdm', 28 | username: '账号2', 29 | phone: '账号2', 30 | // 数组类型的 cookies 31 | cookies: [{xxx:'xxx'}] 32 | }, 33 | ]; 34 | 35 | 36 | //回复列表 用于发表评论的内容 37 | let commitList = [ 38 | '感谢爆料,很不错啊', 39 | '感谢爆料,价格不错~~', 40 | ]; 41 | 42 | module.exports = { 43 | emailName, 44 | emailPassword, 45 | toEmail, 46 | cookieListValKey, 47 | commitList 48 | }; -------------------------------------------------------------------------------- /doc/cnpm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuess/puppeteer-sign/7efb9c934996e77a93d02c94c1c459290ea8010f/doc/cnpm.jpg -------------------------------------------------------------------------------- /doc/email.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuess/puppeteer-sign/7efb9c934996e77a93d02c94c1c459290ea8010f/doc/email.jpg -------------------------------------------------------------------------------- /doc/getcookie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuess/puppeteer-sign/7efb9c934996e77a93d02c94c1c459290ea8010f/doc/getcookie.jpg -------------------------------------------------------------------------------- /doc/setcookie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuess/puppeteer-sign/7efb9c934996e77a93d02c94c1c459290ea8010f/doc/setcookie.jpg -------------------------------------------------------------------------------- /lib/fu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Sorrow.X on 2017/6/16. 3 | */ 4 | const fs = require('fs'); 5 | const _path = require('path'); 6 | const util = require('util'); 7 | 8 | const path = _path; 9 | 10 | let isWindows = !!process.platform.match(/^win/); 11 | let wrench = { 12 | // 同步递归创建目录 13 | mkdirSyncRecursive: function(path, mode) { 14 | path = _path.normalize(path); 15 | let self = this; 16 | try { 17 | fs.mkdirSync(path, mode); 18 | } catch(err) { 19 | if(err.code == "ENOENT") { 20 | let slashIdx = path.lastIndexOf(_path.sep); 21 | 22 | if(slashIdx > 0) { 23 | let parentPath = path.substring(0, slashIdx); 24 | self.mkdirSyncRecursive(parentPath, mode); 25 | self.mkdirSyncRecursive(path, mode); 26 | } else { 27 | throw err; 28 | }; 29 | } else if(err.code == "EEXIST") { 30 | return; 31 | } else { 32 | throw err; 33 | }; 34 | }; 35 | }, 36 | 37 | // 同步递归删除目录 38 | rmdirSyncRecursive: function(path, failSilent) { 39 | let files; 40 | let self = this; 41 | try { 42 | files = fs.readdirSync(path); 43 | } catch(err) { 44 | if(failSilent) return; 45 | throw new Error(err.message); 46 | }; 47 | 48 | /* Loop through and delete everything in the sub-tree after checking it */ 49 | for(var i = 0; i < files.length; i++) { 50 | var file = _path.join(path, files[i]); 51 | var currFile = fs.lstatSync(file); 52 | 53 | if(currFile.isDirectory()) { 54 | // Recursive function back to the beginning 55 | self.rmdirSyncRecursive(file); 56 | } else if(currFile.isSymbolicLink()) { 57 | // Unlink symlinks 58 | if(isWindows) { 59 | fs.chmodSync(file, 666) // Windows needs this unless joyent/node#3006 is resolved.. 60 | }; 61 | fs.unlinkSync(file); 62 | } else { 63 | // Assume it's a file - perhaps a try/catch belongs here? 64 | if(isWindows) { 65 | fs.chmodSync(file, 666) // Windows needs this unless joyent/node#3006 is resolved.. 66 | }; 67 | fs.unlinkSync(file); 68 | }; 69 | }; 70 | 71 | /* Now that we know everything in the sub-tree has been deleted, we can delete the main 72 | directory. Huzzah for the shopkeep. */ 73 | return fs.rmdirSync(path); 74 | }, 75 | 76 | // 同步拷贝文件 77 | copyFile: function(src, dest) { 78 | let len = 64 * 1024; 79 | let buff = new Buffer(len); 80 | let fdr = fs.openSync(src, 'r'); 81 | let fdw = fs.openSync(dest, 'w'); 82 | let bytesRead = 1; 83 | let pos = 0; 84 | while(bytesRead > 0) { 85 | bytesRead = fs.readSync(fdr, buff, 0, len, pos); 86 | fs.writeSync(fdw, buff, 0, bytesRead); 87 | pos += bytesRead; 88 | } 89 | fs.closeSync(fdr); 90 | fs.closeSync(fdw); 91 | } 92 | }; 93 | 94 | // 判断fn是否是函数 95 | let isFunction = function(fn) { 96 | return Object.prototype.toString.call(fn) == '[object Function]'; 97 | }; 98 | 99 | // 判断str是否是字符串 100 | let isString = function(str) { 101 | return Object.prototype.toString.call(str) == '[object String]'; 102 | }; 103 | 104 | /** 105 | 文件操作单例 106 | @example 107 | 108 | fu.exist(file); //是否存在 109 | fu.copy(file, 'new-path'); //复制到某个新目录 110 | fu.move(file, 'new-path'); //移动到某个新目录 111 | fu.rename(file, 'new-name'); 112 | fu.delete(file); //删除文件或文件夹 113 | 114 | fu.mkdir(src); //创建目录 115 | fu.touch(my-file-name); //创建文件 116 | 117 | fu.write(my-file-name, data); //写入内容 118 | fu.append(my-file-name, append_data); //追加内容 119 | fu.read(my-file-name); //读取内容 120 | 121 | fu.type(my-file-name); //类型 122 | 123 | fu.extname(my-file-name); //文件后缀, 带. 124 | fu.extname(my-file-name); //文件后缀,不带. 125 | 126 | fu.copy('tmp', 'tmp2'); //复制文件或者文件夹tmp中的文件到目录tmp2 127 | fu.move('tmp', 'tmp2'); //移动文件或者文件夹tmp中的文件到文件夹tmp2 128 | 129 | fu.each(src, function(item){ 130 | console.log('遍历文件'); 131 | }); 132 | 133 | //异步的方式遍历 134 | var options = { 135 | sync: false, 136 | matchFunction: function(itm){ 137 | return item.name.match(/\.css$/i); 138 | } 139 | } 140 | var onComplete = function(){ 141 | console.log('遍历完成'); 142 | } 143 | fu.each(src, function(item), options, onComplete); 144 | **/ 145 | let FileUtil = (function() { 146 | 147 | // 属性 148 | function F() {}; 149 | 150 | // 方法 151 | F.prototype = { 152 | constructor: F, 153 | 154 | /** 155 | 判断某个或某些文件(夹)是否存在 156 | @method exist 157 | @param {String} f 一个文件(夹)名称 158 | @return Boolean 文件是否存在 159 | **/ 160 | exist: function(f) { 161 | return fs.existsSync(f); 162 | }, 163 | 164 | /** 165 | 是否是文件 166 | @method isFile 167 | @static 168 | @param {String} f 文件名称 169 | @return Boolean 是否是文件 170 | **/ 171 | isFile: function(f) { 172 | return this.exist(f) && fs.statSync(f).isFile(); 173 | }, 174 | 175 | /** 176 | 是否是文件夹 177 | @method isDirectory 178 | @static 179 | @param {String} f 文件名称 180 | @return Boolean 是否是文件夹 181 | **/ 182 | isDirectory: function(f, dir) { 183 | return this.exist(f) && fs.statSync(f).isDirectory(); 184 | }, 185 | 186 | /** 187 | @method extname 188 | @param {String} f 文件名称 189 | @param {String} (optional) withDot 是否带上. 190 | @return String 文件后缀 191 | @example 192 | console.log(fu.extname('image.jpg')); // jpg 193 | **/ 194 | extname: function(f, withDot) { 195 | var extname = path.extname(f); 196 | if(!withDot && extname && extname.charAt(0) == '.') { 197 | return extname.substr(1); 198 | } 199 | return extname; 200 | }, 201 | 202 | /** 203 | 创建目录 204 | @method mkdir 205 | @param {String|Array} f 一个或多个文件夹 206 | @param {Number} permission 文件权限 207 | @example 208 | fu.mkdir('model'); 209 | fu.mkdir(['view', 'controller']); 210 | fu.mkdir('mydir', 0775); 211 | **/ 212 | mkdir: function(f, permission) { 213 | if(util.isArray(f)) { 214 | var self = this; 215 | f.forEach(function(item) { 216 | self.mkdir(item, permission); 217 | }) 218 | } else { 219 | if(!this.exist(f)) { 220 | wrench.mkdirSyncRecursive(f, permission || 0777); 221 | } 222 | } 223 | }, 224 | 225 | /** 226 | 创建文件 227 | @method touch 228 | @param {String|Array} f 一个或多个文件 229 | @param {int} (optional)[0777] permission 文件权限 230 | @param {String} (optional) data 文件内容 231 | @example 232 | fu.touch('README.md'); 233 | fu.touch('app.js', 0777); 234 | fu.touch(['view/view.js', 'model/model.js']); 235 | fu.touch('app.js', 0777, 'window.app = (function(){ return "app" })()'); 236 | **/ 237 | touch: function(f, permission, data) { 238 | if(util.isArray(f)) { 239 | var self = this; 240 | f.forEach(function(item) { 241 | self.touch(item, permission); 242 | }) 243 | } else { 244 | data = data || ''; 245 | this.mkdir(path.dirname(f)); 246 | this.write(f, data); 247 | } 248 | }, 249 | 250 | /** 251 | 删除文件或文件夹 252 | @method delete 253 | @param {String|Array} f 一个或多个文件或文件夹 254 | @example 255 | fu.delete('/var/www/tmp/data/one.txt'); 256 | fu.delete('/var/www/tmp/data/') 257 | **/ 258 | delete: function(f) { 259 | if(util.isArray(f)) { 260 | var self = this; 261 | f.forEach(function(item) { 262 | self.delete(item); 263 | }) 264 | } else { 265 | if(this.exist(f)) { 266 | if(this.isDirectory(f)) { 267 | wrench.rmdirSyncRecursive(f, true); 268 | } else { 269 | fs.unlinkSync(f); 270 | } 271 | } 272 | } 273 | }, 274 | 275 | /** 276 | 读取文件内容 277 | @method read 278 | @param {String} f 文件名 279 | @param {String} (optional) encoding 编码,默认`utf-8` 280 | @example 281 | fu.read('文件名'); 282 | **/ 283 | read: function(f, encoding) { 284 | return fs.readFileSync(f, encoding || 'utf-8'); 285 | }, 286 | 287 | /** 288 | 写入内容到文件 (会覆盖以前的内容) 289 | @method read 290 | @param {String} f 文件名 291 | @param {String} data 文件内容 292 | @param {String} (optional) encoding 编码,默认`utf-8` 293 | @example 294 | fu.write('README.md', '你的数据'); 295 | **/ 296 | write: function(f, data, encoding) { 297 | return fs.writeFileSync(f, data, encoding || 'utf-8'); 298 | }, 299 | 300 | /** 301 | 追加内容到文件 302 | @method append 303 | @static 304 | @param {String} f 文件名 305 | @param {String} data 文件内容 306 | @param {String} (optional) encoding 编码,默认`utf-8` 307 | @example 308 | fu.append('README.md', '你的数据'); 309 | **/ 310 | append: function(f, data, encoding) { 311 | return fs.appendFileSync(f, data, encoding); 312 | }, 313 | 314 | /** 315 | 更改名称 316 | @method rename 317 | @param {String} name 文件名 318 | @param {String} (optional) newName 新的文件名 319 | @example 320 | fu.rename('app.js', 'app_bak.js'); 321 | fu.rename('app.js', '/usr/local/bak/app.js'); 322 | **/ 323 | rename: function(name, newName) { 324 | this.mkdir(path.dirname(newName)); 325 | fs.renameSync(name, newName); 326 | }, 327 | 328 | /** 329 | 移动文件或文件夹中的文件到新的目录(移动完可以重命名) 330 | @method move 331 | @param {String|Array} f 一个或多个文件 332 | @param {String} target 目标文件目录 333 | @param {String} (optional) filter_or_newName 过滤正则或者过滤函数或者新名称 334 | @example 335 | //移动js文件 336 | fu.move(fu.list(src), targetDir, /\.js$/i); 337 | fu.move(fu.list(src), targetDir, function(f) { 338 | return f.match(/\.js$/i); 339 | }); 340 | //移动并且改名 341 | fu.move('src/app.js', 'dest', 'app-min.js'); 342 | **/ 343 | move: function(f, target, filter_or_newName) { 344 | var self = this; 345 | var isValid = function(item) { 346 | if(self.isDirectory(item)) { 347 | return true; 348 | }; 349 | if(filter_or_newName) { 350 | if(util.isRegExp(filter_or_newName)) { 351 | return filter_or_newName.test(item); 352 | } else if(isFunction(filter_or_newName)) { 353 | return filter_or_newName(item); 354 | }; 355 | }; 356 | return true; 357 | }; 358 | if(util.isArray(f)) { 359 | f.forEach(function(item) { 360 | self.move(item, target); 361 | }); 362 | } else { 363 | var name; 364 | if(!isValid(f)) { 365 | return; 366 | }; 367 | if(filter_or_newName && isString(filter_or_newName)) { 368 | name = filter_or_newName; 369 | filter_or_newName = null; 370 | } else { 371 | name = path.basename(f); 372 | }; 373 | var newName = path.normalize(target + path.sep + name); 374 | 375 | try { 376 | //如果是文件 377 | if(this.isFile(f)) { 378 | this.rename(f, newName); 379 | }; 380 | //如果没有过滤参数 381 | if(!filter_or_newName) { 382 | return this.rename(f, target); 383 | }; 384 | 385 | //可能有过滤,被过滤掉的文件不能被移动 386 | var deleteList = []; 387 | this.each(f, function(item) { 388 | var dir, t; 389 | if(item.directory) { 390 | dir = path.relative(f, item.name); 391 | t = path.normalize(target + path.sep + dir); 392 | self.mkdir(t); 393 | deleteList.push(item.name); 394 | } else { 395 | dir = path.dirname(path.relative(f, item.name)) 396 | t = path.normalize(target + path.sep + dir); 397 | self.move(item.name, t, filter_or_newName); 398 | }; 399 | }, { 400 | matchFunction: function(item) { 401 | return isValid(item.name); 402 | } 403 | }); 404 | 405 | deleteList.forEach(function(item) { 406 | self.delete(item); 407 | }); 408 | self.delete(f); 409 | 410 | } catch(err) { 411 | if(this.isFile(f)) { 412 | this.copy(f, target, filter_or_newName); 413 | this.delete(f); 414 | } else if(this.isDirectory(f)) { 415 | this.copy(f, target, filter_or_newName); 416 | this.delete(f); 417 | }; 418 | }; 419 | }; 420 | }, 421 | 422 | /** 423 | 复制文件或文件夹中的文件到新的目录(复制完可以重命名) 424 | @method copy 425 | @param {String|Array} f 一个或多个文件 426 | @param {String} target 目标文件目录 427 | @param {String} (optional) filter_or_newName 过滤正则或者过滤函数或者新名称 428 | @example 429 | //拷贝js文件 430 | fu.copy(fu.list(src), targetDir, /\.js$/i); 431 | fu.copy(fu.list(src), targetDir, function(f){ 432 | return f.match(/\.js$/i); 433 | }); 434 | //拷贝并且改名 435 | fu.copy('src/app.js', 'dest', 'app-min.js'); 436 | **/ 437 | copy: function(f, target, filter_or_newName) { 438 | var self = this; 439 | var isValid = function(item) { 440 | if(self.isDirectory(item)) { 441 | return true; 442 | }; 443 | if(filter_or_newName) { 444 | if(util.isRegExp(filter_or_newName)) { 445 | return filter_or_newName.test(item); 446 | } else if(isFunction(filter_or_newName)) { 447 | return filter_or_newName(item); 448 | }; 449 | }; 450 | return true; 451 | }; 452 | if(util.isArray(f)) { 453 | f.forEach(function(item) { 454 | // self.copy(item, dir); 455 | self.copy(item, target); 456 | }); 457 | } else { 458 | var name; 459 | if(!isValid(f)) { 460 | return; 461 | }; 462 | if(filter_or_newName && isString(filter_or_newName)) { 463 | name = filter_or_newName; 464 | filter_or_newName = null; 465 | } else { 466 | name = path.basename(f); 467 | }; 468 | 469 | var newName = path.normalize(target + path.sep + name); 470 | 471 | if(this.isFile(f)) { 472 | this.mkdir(path.dirname(newName)); 473 | wrench.copyFile(f, newName); 474 | } else if(this.isDirectory(f)) { 475 | this.each(f, function(item) { 476 | var dir, t; 477 | if(!item.directory) { 478 | dir = path.dirname(path.relative(f, item.name)); 479 | t = path.normalize(target + path.sep + dir); 480 | self.copy(item.name, t, filter_or_newName); 481 | }; 482 | }); 483 | }; 484 | }; 485 | }, 486 | 487 | /** 488 | 遍历目录下的文件和文件夹 489 | @method each 490 | @static 491 | @param {String} dir 目录 492 | @param {Function} callback 遍历时的回调函数 493 | @param {Object} options 过滤参数 494 | @param {Boolean} options.recursive 是否遍历子文件夹,默认true 495 | @param {Boolean} options.excludeFile 是否屏蔽文件 496 | @param {Boolean} options.excludeDirectory 是否屏蔽文件夹 497 | @param {Boolean} options.sync 是否异步,默认同步 498 | @param {Function} options.matchFunction 匹配函数 499 | @param {Function} (optional) onComplete 完成文件遍历的回调函数 500 | @example 501 | // 同步遍历 502 | fu.each('src', function(item){ 503 | console.log(item); 504 | }, { 505 | excludeDirectory: true, 506 | matchFunction: function(item){ 507 | return item.filename.match(/\.js/i); 508 | } 509 | }); 510 | 511 | //以异步方式调用 512 | fu.each('src', function(item){ 513 | console.log(item.filename); 514 | }, { sync: false}, function(){ 515 | console.log('读取完毕') 516 | }); 517 | **/ 518 | each: function(dir, callback, options, onComplete) { 519 | options = options || {}; 520 | dir = dir.replace(/(\/+)$/, ''); 521 | 522 | let self = this; 523 | let sync = options.sync != undefined ? options.sync : true; 524 | let excludeFile = options.excludeFile; 525 | let excludeDirectory = options.excludeDirectory; 526 | let matchFunction = options.matchFunction; 527 | let breakFunction = options.breakFunction; 528 | let preventRecursiveFunction = options.preventRecursiveFunction; 529 | let recursive = true; 530 | let checkCount = 0; 531 | let p, i, l; 532 | 533 | var onFinished = function() { 534 | if(checkCount <= 0 && onComplete) { 535 | onComplete(); 536 | }; 537 | }; 538 | 539 | if(options.recursive === false) { 540 | recursive = false; 541 | }; 542 | 543 | if(!this.isDirectory(dir)) { 544 | onFinished(); 545 | return []; 546 | }; 547 | 548 | var handleItem = function(filename) { 549 | var name = dir + path.sep + filename; 550 | var isDir = self.isDirectory(name); 551 | var info = { 552 | directory: isDir, 553 | name: name, 554 | filename: filename 555 | }; 556 | 557 | if(isDir) { 558 | if(recursive) { 559 | if(!preventRecursiveFunction || !preventRecursiveFunction(info)) { 560 | checkCount++; 561 | self.each(name, callback, options, function() { 562 | checkCount--; 563 | onFinished(); 564 | }); 565 | }; 566 | }; 567 | 568 | if(!excludeDirectory) { 569 | if(!matchFunction || (matchFunction && matchFunction(info))) { 570 | callback(info); 571 | }; 572 | }; 573 | } else if(self.isFile(name)) { 574 | if(!excludeFile) { 575 | if(!matchFunction || (matchFunction && matchFunction(info))) { 576 | callback(info); 577 | }; 578 | }; 579 | }; 580 | checkCount--; 581 | onFinished(); 582 | }; 583 | if(sync) { 584 | p = fs.readdirSync(dir); 585 | p.forEach(handleItem); 586 | checkCount = 0; 587 | onFinished(); 588 | } else { 589 | fs.readdir(dir, function(e, arr) { 590 | if(e) { 591 | onFinished(); 592 | } else { 593 | checkCount = arr.length; 594 | onFinished(); 595 | arr.forEach(function(item) { 596 | handleItem(item); 597 | }); 598 | }; 599 | }); 600 | }; 601 | }, 602 | 603 | /** 604 | 列出目录下的文件和文件夹 605 | @method list 606 | @static 607 | @param {String} dir 目录 608 | @param {Object} options 过滤参数 609 | @param {Boolean} options.recursive 是否遍历子文件夹,默认true 610 | @param {Boolean} options.excludeFile 是否屏蔽文件 611 | @param {Boolean} options.excludeDirectory 是否屏蔽文件夹 612 | @param {Function} options.breakFunction 终止函数 613 | @param {Function} options.matchFunction 匹配函数 614 | @param {Boolean} fullView 是否返回更完整的文件信息 615 | @return Array 文件和文件夹信息 616 | @example 617 | //列出所有js文件 618 | var list = fu.list('aa', { 619 | excludeDirectory: true, 620 | matchFunction: function(item){ 621 | return item.filename.match(/\.js$/i); 622 | } 623 | }); 624 | console.log(list); //list = ['a.js', 'b/c.js', ...] 625 | 626 | //列出所有js文件,包含完整信息 627 | var list = fu.list('aa', { 628 | excludeDirectory: true, 629 | matchFunction: function(item){ 630 | return item.filename.match(/\.js$/i); 631 | } 632 | }, true); 633 | console.log(list); 634 | **/ 635 | list: function(dir, options, fullView) { 636 | let result = []; 637 | options = options || {}; 638 | options.sync = true; 639 | this.each(dir, function(item) { 640 | if(fullView) { 641 | result.push(item); 642 | } else { 643 | result.push(item.name); 644 | } 645 | }, options); 646 | return result; 647 | } 648 | }; 649 | 650 | //实例容器 651 | let instance; 652 | 653 | let _static = { 654 | name: 'FileUtil', 655 | 656 | //获取实例的方法 657 | //返回F的实例 658 | getInstance: function(args) { 659 | if(instance === undefined) { 660 | instance = new F(args); 661 | }; 662 | return instance; 663 | } 664 | }; 665 | return _static; 666 | })(); 667 | 668 | let fu = FileUtil.getInstance(); 669 | 670 | module.exports = fu; -------------------------------------------------------------------------------- /lib/mail-template.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 85 |

签到数据列表:

86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | <% for(let i = 0; i < logoInfoSign.length; i++) { 101 | let info = logoInfoSign[i]; %> 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | <%}%> 115 |
编号昵称签到时间新增积分经验连续签到(天)总积分总经验总金币声望等级
<%=i+1%><%=info.cookie%><%= info.date %><%= info.jsonData.add_point%><%= info.jsonData.checkin_num%><%= info.jsonData.point%><%= info.jsonData.exp%><%= info.jsonData.gold%><%= info.jsonData.prestige%><%= info.jsonData.rank%>


116 |


117 |

评论数据列表:

118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | <%for(let i = 0; i < logoInfoCommit.length; i++) { 135 | let info = logoInfoCommit[i];%> 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | <%}%> 150 |
编号昵称评论时间评论内容昵称新增积分新增经验新增金币新增声望评论id评论文章链接
<%=i+1%><%=info.cookie%><%=info.jsonData.format_date_client%><%=info.jsonData.comment_content%><%=info.jsonData.display_name%><%=info.jsonData.post_points%><%=info.jsonData.post_experience%><%=info.jsonData.post_gold%><%=info.jsonData.post_prestige%><%=info.jsonData.comment_ID%><%=info.pId%>
151 | 152 | -------------------------------------------------------------------------------- /lib/mail.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 发邮件 工具类 3 | * xuess 4 | * 2018年03月29日 修改 5 | */ 6 | 7 | const nodemailer = require('nodemailer');//发邮件 8 | const moment = require("moment"); //日期 9 | const fu = require('./fu.js'); //文件操作 10 | const { emailName , emailPassword ,toEmail } = require('../config.js'); //配置 11 | const { ascii2native } = require('./utils'); //工具类 12 | 13 | 14 | const transporter = nodemailer.createTransport({ 15 | //https://nodemailer.com/smtp/well-known/ 支持列表 16 | //https://github.com/nodemailer/nodemailer-wellknown/blob/master/services.json 配置 17 | //126 邮箱参考 https://cnodejs.org/topic/55629a8a8f294e213d10b8e7 18 | host: "smtp.126.com", 19 | secureConnection: true, 20 | port: 465, 21 | auth: { 22 | user: emailName, 23 | pass: emailPassword 24 | } 25 | }); 26 | 27 | 28 | /** 29 | * 发邮件 带截图 30 | * @param {Object} title 标题 31 | * @param {Object} text 内容 32 | */ 33 | function sendMailForImage(text) { 34 | //今天日期 35 | let now = moment(); 36 | let today = now.clone().add(0, 'days').format('YYYY-MM-DD'); 37 | // let today = moment().format('LL'); 38 | 39 | //图片路径 40 | let imgPath = []; 41 | 42 | //查找 TODO 这里路径要写 当前 有点this 作用域的问题。 上层调用的 43 | fu.each('./screenshot/smzdm', function(item) { 44 | imgPath.push(item); 45 | }); 46 | //查找 TODO 这里路径要写 当前 有点this 作用域的问题。 上层调用的 47 | fu.each('./screenshot/tf8', function(item) { 48 | imgPath.push(item); 49 | }); 50 | 51 | let attachmentsList = [], 52 | htmlImg = ''; 53 | 54 | console.log('process.cwd()',process.cwd()); 55 | //数字不能用 直接用i ,会造成只能发十个,到第十一个 就是第一个图了 56 | for(let i = 0; i < imgPath.length; i++) { 57 | htmlImg += `

${imgPath[i].filename}





`; 58 | let temp = { 59 | filename: imgPath[i].filename, //图片名称 60 | // path: process.cwd() + "/screenshot/" + imgPath[i], //图片来源 61 | path: imgPath[i].name, //图片来源 62 | cid: `img${i + 123}` //插入图片标识 63 | }; 64 | attachmentsList.push(temp); 65 | } 66 | 67 | let html = `
68 | 你好:
69 |   下面为【浏览器签到】日报汇报(${today})的内容
70 | ${htmlImg} 71 | `; 72 | 73 | //邮件内容选项设定 74 | let mailOptions = { 75 | from: `自己 <${emailName}>`, // 发件地址 76 | to: toEmail, // 收件列表 77 | cc: '', //抄送人 78 | bcc: '', //密抄送人 79 | subject: `【浏览器签到】日报汇报(${today})`, //邮件主题 80 | text: `【浏览器签到】日报汇报(${today})`, // plaintext body 81 | html: html, //html内容 82 | attachments: attachmentsList 83 | }; 84 | 85 | transporter.sendMail(mailOptions, function(error, info) { 86 | if(error) { 87 | return console.log(error); 88 | } 89 | console.log(`今天是${today},签到日报已发! --- Message sent: ${info.response}`); 90 | }); 91 | } 92 | 93 | /** 94 | * 发邮件 错误信息 95 | * @param {Object} title 标题 96 | * @param {Object} errStr 内容 97 | */ 98 | function sendMailErr(title, errStr) { 99 | 100 | let now = moment(); 101 | let today = now.clone().add(0, 'days').format('YYYY-MM-DD'); 102 | 103 | let html = `
104 | ${title}
105 | ${errStr}
106 | `; 107 | 108 | //邮件内容选项设定 109 | let mailOptions = { 110 | from: `自己 <${emailName}>`, // 发件地址 111 | to: toEmail, // 收件列表 112 | cc: '', //抄送人 113 | bcc: '', //密抄送人 114 | subject: `${title}(${today})`, //邮件主题 115 | text: `${title}(${today})`, // plaintext body 116 | html: html //html内容 117 | }; 118 | 119 | transporter.sendMail(mailOptions, function(error, info) { 120 | if(error) { 121 | return console.log(error); 122 | } 123 | console.log(`今天是${today},错误信息已发! --- Message sent: ${info.response}`); 124 | }); 125 | } 126 | 127 | module.exports = { 128 | sendMailForImage, 129 | sendMailErr 130 | }; -------------------------------------------------------------------------------- /lib/request_https.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https 请求模块 3 | * xuess 4 | * 2018-04-17 5 | */ 6 | 7 | 'use strict'; 8 | const http = require('https'); 9 | const querystring = require('querystring'); 10 | const url = require('url'); 11 | 12 | /** 13 | * 14 | */ 15 | module.exports = function(options, cookie, referer) { 16 | 17 | let URL = url.parse(options.url); 18 | let type = options.type.toUpperCase() || 'GET'; 19 | 20 | //处理cookie 21 | cookie = cookie || ''; 22 | 23 | //处理请求参数 24 | let contents = false; 25 | if(!!options.params) { 26 | contents = querystring.stringify(options.params); 27 | } 28 | 29 | //如果是get,把参数跟在url后面 30 | let path = URL.path; 31 | if(type === 'GET' && contents) { 32 | path = path + '?' + contents; 33 | } 34 | 35 | let requestOptions = { 36 | host: URL.hostname, 37 | port: URL.port, 38 | path: path, 39 | method: type, 40 | headers: { 41 | Cookie: cookie, 42 | Referer : referer 43 | } 44 | }; 45 | 46 | requestOptions.headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'; 47 | 48 | if(type ==='POST' && contents) { 49 | requestOptions.headers['Content-Type'] = 'application/json;charset=UTF-8'; 50 | requestOptions.headers['Content-Length'] = contents.length; 51 | } 52 | 53 | // console.log('requestOptions === ',requestOptions); 54 | let req = http.request(requestOptions, function(res) { 55 | res.setEncoding('UTF-8'); 56 | let str = ''; 57 | res.on('data', function(chunk) { 58 | str = str + chunk; 59 | }); 60 | 61 | res.on('end', function() { 62 | let setCookie = res.headers['set-cookie']; 63 | //执行回调 64 | options.callback && options.callback(str, setCookie); 65 | }); 66 | 67 | res.on('error', function(e) { 68 | options.callback && options.callback(e); 69 | }); 70 | }); 71 | 72 | req.on('error', function(e) { 73 | options.callback && options.callback(e); 74 | }); 75 | 76 | //post请求,需要把请求体发送过去 77 | if(type === 'POST' && contents) { 78 | req.write(contents); 79 | } 80 | 81 | req.end(); 82 | 83 | }; 84 | 85 | 86 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | //时间格式化 2 | Date.prototype.Format = function(fmt) { 3 | let o = { 4 | "M+": this.getMonth() + 1, //月份 5 | "d+": this.getDate(), //日 6 | "h+": this.getHours(), //小时 7 | "m+": this.getMinutes(), //分 8 | "s+": this.getSeconds(), //秒 9 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度 10 | "S": this.getMilliseconds() //毫秒 11 | }; 12 | if(/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 13 | for(let k in o) 14 | if(new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 15 | return fmt; 16 | } 17 | 18 | //取随机数 min = 最小值 ; max = 最大值 19 | let getRandom = (min, max) => { 20 | return parseInt(Math.random() * (max - min + 1) + min); 21 | } 22 | 23 | //转码ascii 转 native 24 | let ascii2native = (str) => { 25 | let asciicode = str.split("\\u"); 26 | let nativeValue = asciicode[0]; 27 | for(let i = 1; i < asciicode.length; i++) { 28 | let code = asciicode[i]; 29 | nativeValue += String.fromCharCode(parseInt("0x" + code.substring(0, 4))); 30 | if(code.length > 4) { 31 | nativeValue += code.substring(4, code.length); 32 | } 33 | } 34 | return nativeValue; 35 | } 36 | 37 | const sleep = (timeountMS) => new Promise((resolve) => { 38 | setTimeout(resolve, timeountMS); 39 | }); 40 | 41 | module.exports = { 42 | getRandom, 43 | ascii2native, 44 | sleep 45 | } 46 | -------------------------------------------------------------------------------- /lin.js: -------------------------------------------------------------------------------- 1 | const puppeteer = require("puppeteer"); 2 | const cheerio = require("cheerio"); 3 | const { cookiesData } = require("./data"); 4 | 5 | (async () => { 6 | const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']}); 7 | const page = await browser.newPage(); 8 | 9 | // page.setUserAgent(userAgent) 10 | await page.setViewport({ 11 | width: 1920, 12 | height: 3080 13 | }); 14 | await page.setCookie(...cookiesData); 15 | await page.once("load", () => console.log("Page loaded!")); 16 | await page.goto("https://www.smzdm.com"); 17 | // await page.tap("#J_search_input"); 18 | // await page.keyboard.type("Hello World!", { delay: 100 }); 19 | // await page.click('.J_feed_za'); 20 | // await page.keyboard.type("World", { delay: 100 }); 21 | 22 | var data = await page.content(); 23 | 24 | let $ = cheerio.load(data); 25 | 26 | let id = $("#feed-main-list") 27 | .find("li") 28 | .eq(0) 29 | .attr("articleid"); 30 | console.log( 31 | $("#feed-main-list") 32 | .find("li") 33 | .eq(0) 34 | .attr("articleid") 35 | ); 36 | 37 | 38 | await page.goto(`https://www.smzdm.com/p/${id.split("_")[1]}/#hfeeds`); 39 | 40 | await page.tap("#textareaComment"); 41 | await page.keyboard.type("又要解读的吗,。。!", { delay: 100 }); 42 | await page.tap("#textCommentSubmit"); 43 | 44 | await page.screenshot({ path: "example.png" }); 45 | 46 | await browser.close(); 47 | })(); 48 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Descripttion: 什么值得买签到程序 3 | * @Author: xuess 4 | * @Date: 2019-06-04 18:00:15 5 | * @LastEditors: 午休 6 | * @LastEditTime: 2020-09-09 20:50:57 7 | */ 8 | 9 | const fu = require("./lib/fu.js"); //文件操作 10 | const smzdm = require("./smzdm"); 11 | const schedule = require("node-schedule"); //定时器 12 | const { getRandom, sleep } = require("./lib/utils"); //工具类 13 | const { sendMailForImage, sendMailErr } = require("./lib/mail"); //发邮件 14 | const { cookieListValKey } = require("./config"); //配置文件 15 | 16 | (async () => { 17 | //延迟执行签到 18 | const setTimeSign = async (userinfo, index) => { 19 | // 随机 20 | await sleep(getRandom(100000, 300000)); 21 | 22 | // 执行签到 23 | if (userinfo.type == "smzdm") { 24 | await smzdm(userinfo.cookies, userinfo.username); 25 | } 26 | 27 | // TODO 这里可以执行其他签到程序 28 | 29 | // 执行到最后一个 发送邮件 30 | // TODO 这里可以执行完就发送邮件 31 | if (cookieListValKey.length - 1 == index) { 32 | // await sendMailForImage("签到截图"); 33 | console.log("打完收工!"); 34 | } 35 | }; 36 | 37 | const doSign = async () => { 38 | // 删除截图目录 39 | await fu.delete(["./screenshot/smzdm"]); 40 | // 新建目录 41 | await fu.mkdir(["./screenshot/smzdm"]); 42 | 43 | try { 44 | // 立即执行 签到 45 | for (let i = 0; i < cookieListValKey.length; i++) { 46 | await setTimeSign(cookieListValKey[i], i); 47 | } 48 | } catch (e) { 49 | sendMailErr("主签到报错", e); 50 | } 51 | }; 52 | 53 | //每天9点 30 执行 定时执行签到 54 | schedule.scheduleJob("40 30 9 * * *", async () => { 55 | await doSign(); 56 | }); 57 | 58 | //每天12点 10 执行 定时执行签到 59 | schedule.scheduleJob("30 10 12 * * *", async () => { 60 | await doSign(); 61 | }); 62 | 63 | //每天20点 10 执行 定时执行签到 64 | schedule.scheduleJob("30 10 20 * * *", async () => { 65 | await doSign(); 66 | }); 67 | 68 | // 立即执行 69 | doSign(); 70 | // sendMailForImage("签到截图"); 71 | 72 | //每天18点30执行 发邮件 发送签到截图 73 | schedule.scheduleJob("10 30 18 * * *", () => { 74 | //发邮件 签到截图 75 | sendMailForImage("签到截图"); 76 | }); 77 | })(); 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppeteer-sign", 3 | "version": "1.0.0", 4 | "description": "基于puppeteer,签到", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "node smzdm.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/xuess/puppeteer-sign.git" 12 | }, 13 | "keywords": [ 14 | "node", 15 | "sign", 16 | "smzdm" 17 | ], 18 | "author": "xuess ", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/xuess/puppeteer-sign/issues" 22 | }, 23 | "homepage": "https://github.com/xuess/puppeteer-sign#readme", 24 | "dependencies": { 25 | "cheerio": "^1.0.0-rc.3", 26 | "ejs": "^2.6.1", 27 | "moment": "^2.22.1", 28 | "node-schedule": "^1.3.0", 29 | "nodemailer": ">=6.4.16", 30 | "puppeteer": "^1.x" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /smzdm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 什么值得买签到程序 3 | * 支持自动签到,自动评论3条,自动错误邮件提醒 4 | * xuess 5 | */ 6 | 7 | const puppeteer = require("puppeteer"); 8 | const { getRandom, sleep } = require("./lib/utils"); //工具类 9 | const { sendMailErr } = require("./lib/mail"); //发邮件 10 | 11 | const smzdm = async (cookiesData, userName) => { 12 | // const browser = await puppeteer.launch({ 13 | // // headless: false, 14 | // slowMo: 100 15 | // }); 16 | // linux 环境 执行 17 | const browser = await puppeteer.launch({ 18 | args: ["--no-sandbox", "--disable-setuid-sandbox"], 19 | slowMo: 150 20 | }); 21 | 22 | const page = await browser.newPage(); 23 | 24 | // await page.setUserAgent(userAgent) 25 | await page.setViewport({ 26 | width: 1080, 27 | height: 1920 28 | }); 29 | await page.setCookie(...cookiesData); 30 | await page.once("load", () => console.log("Page loaded!")); 31 | 32 | try { 33 | await page.goto("https://www.smzdm.com/", { 34 | timeout: 60 * 1000, 35 | waitUntil: [ 36 | "load", //等待 “load” 事件触发 37 | "domcontentloaded", //等待 “domcontentloaded” 事件触发 38 | "networkidle0", //在 500ms 内没有任何网络连接 39 | "networkidle2" //在 500ms 内网络连接个数不超过 2 个 40 | ] 41 | }); 42 | // 等待元素出现 43 | await page.waitForSelector(".J_punch"); 44 | // 点击 45 | await page.tap(".J_punch"); 46 | 47 | } catch (error) { 48 | console.log("签到报错!"); 49 | // sendMailErr(`smzdm 签到报错${userName}`, error); 50 | } 51 | // await page.tap("#J_search_input"); 52 | // await page.keyboard.type("Hello World!", { delay: 100 }); 53 | // await page.click('.J_feed_za'); 54 | // await page.keyboard.type("World", { delay: 100 }); 55 | 56 | // 签到 57 | 58 | console.log(userName, " 签到成功!"); 59 | 60 | await sleep(3000); 61 | 62 | await page.screenshot({ 63 | path: `./screenshot/smzdm/${userName}-sign-${new Date().Format( 64 | "yyyy-MM-dd" 65 | )}.png` 66 | }); 67 | 68 | // TODO 评论 69 | // await page.goto("https://faxian.smzdm.com/"); 70 | 71 | // let pageDom = await page.content(); 72 | 73 | // let tempPostIdList = [], 74 | // hrefUrl = "https://www.smzdm.com/p/14144125/", 75 | // maxTime = 3; 76 | 77 | // let $ = cheerio.load(pageDom); 78 | 79 | // $(".feed-ver-title").each(function(i, e) { 80 | // if (i > 20) { 81 | // return false; 82 | // } 83 | // let href = $(e) 84 | // .find("a") 85 | // .eq(0) 86 | // .attr("href"); 87 | // tempPostIdList.push(href); 88 | // }); 89 | 90 | // console.log(userName, ": 候选-->", tempPostIdList); 91 | 92 | // for (let i = 0; i < maxTime; i++) { 93 | // hrefUrl = tempPostIdList[Math.floor(Math.random() * tempPostIdList.length)]; 94 | // console.log(userName, ": 选择-->", hrefUrl); 95 | // // 等待半小时 96 | // // await sleep(getRandom(100000,300000)); 97 | // await sleep(getRandom(15000,25000)); 98 | 99 | // try { 100 | // await page.goto(`${hrefUrl}#hfeeds`); 101 | // await page.tap("#textareaComment"); 102 | // await page.keyboard.type( 103 | // commitList[Math.floor(Math.random() * commitList.length)], 104 | // { delay: 100 } 105 | // ); 106 | 107 | // await page.tap("#textCommentSubmit"); 108 | 109 | // await sleep(15000); 110 | 111 | // await page.screenshot({ 112 | // path: `./screenshot/smzdm/${userName}-${i}-${new Date().Format("yyyy-MM-dd")}.png` 113 | // }); 114 | // } catch (error) { 115 | // console.log(error); 116 | // maxTime++; 117 | // } 118 | // } 119 | 120 | // await page.goto(`https://www.smzdm.com/p/${id.split("_")[1]}/#hfeeds`); 121 | 122 | // await page.tap("#textareaComment"); 123 | // await page.keyboard.type( 124 | // commitList[Math.floor(Math.random() * commitList.length)], 125 | // { delay: 100 } 126 | // ); 127 | // await page.tap("#textCommentSubmit"); 128 | 129 | // await sleep(3000); 130 | 131 | // await page.screenshot({ 132 | // path: `./screenshot/smzdm/${userName}-${index}.png` 133 | // }); 134 | await page.close(); 135 | await browser.close(); 136 | }; 137 | module.exports = smzdm; 138 | // smzdm(cookieListValKey[5].cookies, cookieListValKey[5].username); 139 | --------------------------------------------------------------------------------