fix(smzdm): navigate to search page directly instead of deprecated ajax API (#113)
The old adapter called `search.smzdm.com/ajax/?c=<channel>&s=<q>` which
now returns 404. This caused opencli smzdm search to always return empty
results regardless of keyword.
Fix: navigate directly to `search.smzdm.com/?c=home&s=<keyword>&v=b`
and scrape the rendered DOM via querySelectorAll('li.feed-row-wide').
Also switched from async IIFE to sync IIFE since all data is already in
the DOM after page load — no fetch needed.
Tested: opencli smzdm search --keyword A7M5 returns correct results
with prices and mall names.
This commit is contained in:
1 parent
47a898125f
commit
812db29ed8
1 file changed
+30
-39
+30
-39
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* 什么值得买搜索好价 — browser cookie, HTML parse.
|
||||
* Source: bb-sites/smzdm/search.js
|
||||
* 什么值得买搜索好价 — browser cookie, DOM scraping.
|
||||
*
|
||||
* Fix: The old adapter used `search.smzdm.com/ajax/` which returns 404.
|
||||
* New approach: navigate to `search.smzdm.com/?c=home&s=<keyword>&v=b`
|
||||
* and scrape the rendered DOM directly.
|
||||
*/
|
||||
import { cli, Strategy } from '../../registry.js';
|
||||
|
||||
@@ -18,46 +21,34 @@ cli({
|
||||
func: async (page, kwargs) => {
|
||||
const q = encodeURIComponent(kwargs.keyword);
|
||||
const limit = kwargs.limit || 20;
|
||||
await page.goto('https://www.smzdm.com');
|
||||
|
||||
// Navigate directly to search results page
|
||||
await page.goto(`https://search.smzdm.com/?c=home&s=${q}&v=b`);
|
||||
await page.wait(2);
|
||||
|
||||
const data = await page.evaluate(`
|
||||
(async () => {
|
||||
const q = '${q}';
|
||||
(() => {
|
||||
const limit = ${limit};
|
||||
// Try youhui channel first, then home
|
||||
for (const channel of ['youhui', 'home']) {
|
||||
try {
|
||||
const resp = await fetch('https://search.smzdm.com/ajax/?c=' + channel + '&s=' + q + '&p=1&v=b', {
|
||||
credentials: 'include',
|
||||
headers: {'X-Requested-With': 'XMLHttpRequest'}
|
||||
});
|
||||
if (!resp.ok) continue;
|
||||
const html = await resp.text();
|
||||
if (html.indexOf('feed-row-wide') === -1) continue;
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const items = doc.querySelectorAll('li.feed-row-wide');
|
||||
const results = [];
|
||||
items.forEach((li, i) => {
|
||||
if (results.length >= limit) return;
|
||||
const titleEl = li.querySelector('h5.feed-block-title > a')
|
||||
|| li.querySelector('h5 > a');
|
||||
if (!titleEl) return;
|
||||
const title = (titleEl.getAttribute('title') || titleEl.textContent || '').trim();
|
||||
const url = titleEl.getAttribute('href') || '';
|
||||
const priceEl = li.querySelector('.z-highlight');
|
||||
const price = priceEl ? priceEl.textContent.trim() : '';
|
||||
let mall = '';
|
||||
const extrasSpan = li.querySelector('.z-feed-foot-r .feed-block-extras span');
|
||||
if (extrasSpan) mall = extrasSpan.textContent.trim();
|
||||
const commentEl = li.querySelector('.feed-btn-comment');
|
||||
const comments = commentEl ? parseInt(commentEl.textContent.trim()) || 0 : 0;
|
||||
results.push({rank: results.length + 1, title, price, mall, comments, url});
|
||||
});
|
||||
if (results.length > 0) return results;
|
||||
} catch(e) { continue; }
|
||||
}
|
||||
return {error: 'No results'};
|
||||
const items = document.querySelectorAll('li.feed-row-wide');
|
||||
const results = [];
|
||||
items.forEach((li) => {
|
||||
if (results.length >= limit) return;
|
||||
const titleEl = li.querySelector('h5.feed-block-title > a')
|
||||
|| li.querySelector('h5 > a');
|
||||
if (!titleEl) return;
|
||||
const title = (titleEl.getAttribute('title') || titleEl.textContent || '').trim();
|
||||
const url = titleEl.getAttribute('href') || titleEl.href || '';
|
||||
const priceEl = li.querySelector('.z-highlight');
|
||||
const price = priceEl ? priceEl.textContent.trim() : '';
|
||||
let mall = '';
|
||||
const mallEl = li.querySelector('.z-feed-foot-r .feed-block-extras span')
|
||||
|| li.querySelector('.z-feed-foot-r span');
|
||||
if (mallEl) mall = mallEl.textContent.trim();
|
||||
const commentEl = li.querySelector('.feed-btn-comment');
|
||||
const comments = commentEl ? parseInt(commentEl.textContent.trim()) || 0 : 0;
|
||||
results.push({ rank: results.length + 1, title, price, mall, comments, url });
|
||||
});
|
||||
return results;
|
||||
})()
|
||||
`);
|
||||
if (!Array.isArray(data)) return [];
|
||||
|
||||
Reference in new issue
Block a user