/ clis / smzdm / search.js
search.js
 1  /**
 2   * 什么值得买搜索好价 — browser cookie, DOM scraping.
 3   *
 4   * Fix: The old adapter used `search.smzdm.com/ajax/` which returns 404.
 5   * New approach: navigate to `search.smzdm.com/?c=home&s=<keyword>&v=b`
 6   * and scrape the rendered DOM directly.
 7   */
 8  import { cli, Strategy } from '@jackwener/opencli/registry';
 9  cli({
10      site: 'smzdm',
11      name: 'search',
12      description: '什么值得买搜索好价',
13      domain: 'www.smzdm.com',
14      strategy: Strategy.COOKIE,
15      args: [
16          { name: 'query', required: true, positional: true, help: 'Search keyword' },
17          { name: 'limit', type: 'int', default: 20, help: 'Number of results' },
18      ],
19      columns: ['rank', 'title', 'price', 'mall', 'comments', 'url'],
20      func: async (page, kwargs) => {
21          const q = encodeURIComponent(kwargs.query);
22          const limit = kwargs.limit || 20;
23          // Navigate directly to search results page
24          await page.goto(`https://search.smzdm.com/?c=home&s=${q}&v=b`);
25          const data = await page.evaluate(`
26        (() => {
27          const limit = ${limit};
28          const items = document.querySelectorAll('li.feed-row-wide');
29          const results = [];
30          items.forEach((li) => {
31            if (results.length >= limit) return;
32            const titleEl = li.querySelector('h5.feed-block-title > a')
33                         || li.querySelector('h5 > a');
34            if (!titleEl) return;
35            const title = (titleEl.getAttribute('title') || titleEl.textContent || '').trim();
36            const url = titleEl.getAttribute('href') || titleEl.href || '';
37            const priceEl = li.querySelector('.z-highlight');
38            const price = priceEl ? priceEl.textContent.trim() : '';
39            let mall = '';
40            const mallEl = li.querySelector('.z-feed-foot-r .feed-block-extras span')
41                        || li.querySelector('.z-feed-foot-r span');
42            if (mallEl) mall = mallEl.textContent.trim();
43            const commentEl = li.querySelector('.feed-btn-comment');
44            const comments = commentEl ? parseInt(commentEl.textContent.trim()) || 0 : 0;
45            results.push({ rank: results.length + 1, title, price, mall, comments, url });
46          });
47          return results;
48        })()
49      `);
50          if (!Array.isArray(data))
51              return [];
52          return data;
53      },
54  });