/ clis / weixin / drafts.js
drafts.js
 1  import { AuthRequiredError, EmptyResultError } from '@jackwener/opencli/errors';
 2  import { cli, Strategy } from '@jackwener/opencli/registry';
 3  
 4  const WEIXIN_DOMAIN = 'mp.weixin.qq.com';
 5  
 6  export const draftsCommand = cli({
 7      site: 'weixin',
 8      name: 'drafts',
 9      description: '列出微信公众号草稿箱',
10      domain: WEIXIN_DOMAIN,
11      strategy: Strategy.COOKIE,
12      browser: true,
13      navigateBefore: false,
14      timeoutSeconds: 60,
15      args: [
16          { name: 'limit', type: 'int', default: 10, help: '最多显示条数' },
17      ],
18      columns: ['Index', 'Title', 'Time'],
19  
20      func: async (page, kwargs) => {
21          await page.goto('https://mp.weixin.qq.com/');
22          await page.wait(3);
23          const token = await page.evaluate(`(window.location.href.match(/token=(\\d+)/)||[])[1]`);
24          if (!token) {
25              throw new AuthRequiredError(WEIXIN_DOMAIN, '微信公众号草稿箱需要已登录的 mp.weixin.qq.com 会话');
26          }
27  
28          await page.goto(`https://mp.weixin.qq.com/cgi-bin/appmsg?begin=0&count=${kwargs.limit}&type=77&action=list_card&token=${token}&lang=zh_CN`);
29          await page.wait(4);
30  
31          const drafts = await page.evaluate(`(() => {
32              var results = [];
33              var idx = 0;
34  
35              var cards = document.querySelectorAll('.weui-desktop-card');
36              for (var i = 0; i < cards.length; i++) {
37                  if (cards[i].className.includes('card_new')) continue;
38                  var titleEl = cards[i].querySelector('[class*=title]');
39                  var timeEl = cards[i].querySelector('[class*=tips]');
40                  var title = titleEl ? titleEl.textContent.trim() : '';
41                  var time = timeEl ? timeEl.textContent.trim().replace(/\\s+/g, ' ') : '';
42                  if (title) results.push({ Index: ++idx, Title: title, Time: time });
43              }
44              if (results.length > 0) return results;
45  
46              var rows = document.querySelectorAll('tr, [class*=appmsg_item], [class*=list_item]');
47              rows.forEach(function(row) {
48                  var titleEl = row.querySelector('[class*=title] a, [class*=title], h4');
49                  var timeEl = row.querySelector('[class*=time], td:nth-child(2)');
50                  var title = titleEl ? titleEl.textContent.trim() : '';
51                  var time = timeEl ? timeEl.textContent.trim() : '';
52                  if (title && title !== '内容' && title.length < 80) {
53                      results.push({ Index: ++idx, Title: title, Time: time });
54                  }
55              });
56              return results;
57          })()`);
58  
59          if (!drafts || drafts.length === 0) {
60              throw new EmptyResultError('weixin drafts', 'No structured drafts found in the current Weixin Official Account backend');
61          }
62  
63          return drafts.slice(0, kwargs.limit);
64      },
65  });