jackwener/OpenCLI · warning · EmptyResultError

zhihu download

zhihu download

Error message

The Zhihu column article had no exportable content.

What it means

In `zhihu download` for a column article, requireArticle throws EmptyResultError (code EMPTY_RESULT, exit 66 / EX_NOINPUT) when the extracted article's `contentHtml` is present and correctly typed but contains only whitespace. The article shell was parsed, but there is no exportable body content to convert/export.

Source

Thrown at clis/zhihu/download-helpers.js:119

            img.setAttribute('src', src);
            if (!seen.has(src)) {
                seen.add(src);
                imageUrls.push(src);
            }
        }
    });
    return { contentHtml: root.innerHTML, imageUrls };
}

function requireArticle(raw) {
    const data = unwrapEvaluateResult(raw);
    if (!data || typeof data !== 'object' || Array.isArray(data)
        || typeof data.title !== 'string' || typeof data.contentHtml !== 'string'
        || !Array.isArray(data.imageUrls) || !data.imageUrls.every((url) => typeof url === 'string')) {
        throw new CommandExecutionError('Zhihu column download returned malformed article fields');
    }
    if (!data.contentHtml.trim()) {
        throw new EmptyResultError('zhihu download', 'The Zhihu column article had no exportable content.');
    }
    return data;
}

export async function extractColumnArticle(page, target) {
    await page.goto(target.url);
    await page.wait(3);
    const normalize = `(${normalizeContentImages.toString()})`;
    const raw = await page.evaluate(`
      (() => {
        const content = document.querySelector('.Post-RichTextContainer, .RichText, .ArticleContent');
        const normalized = ${normalize}(content?.innerHTML || '');
        return {
          title: document.querySelector('.Post-Title, h1.ContentItem-title, .ArticleTitle')?.textContent?.trim() || 'untitled',
          author: document.querySelector('.AuthorInfo-name, .UserLink-link')?.textContent?.trim() || '',
          publishTime: document.querySelector('.ContentItem-time, .Post-Time')?.textContent?.trim() || '',
          ...normalized
        };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run after increasing the post-navigation wait (e.g. page.wait(3) or waiting for the article body selector) so content mounts.
  2. Verify the article has visible content when opened in the browser — if blank there, the column is deleted/members-only.
  3. Scroll or click any 'expand/read more' control before extraction so the full body renders.
  4. If content exists in the browser but extraction still yields empty HTML, fix the content selector in the extraction script.

Example fix

// before
await page.goto(target.url);
const article = requireArticle(await page.evaluate(extractScript));
// after: wait for the body before extracting
await page.goto(target.url);
await page.wait(3); // or waitForSelector on the article body
const article = requireArticle(await page.evaluate(extractScript));
Defensive patterns

Strategy: validation

Validate before calling

const data = await page.evaluate(extractScript);
if (typeof data?.contentHtml === 'string' && !data.contentHtml.trim()) {
  throw new Error('Article body empty — wait for content or check paywall/deletion');
}

Type guard

function hasExportableContent(v) {
  return typeof v?.contentHtml === 'string' && v.contentHtml.trim().length > 0;
}

Try / catch

try {
  const article = requireArticle(await page.evaluate(extractScript));
} catch (e) {
  if (e.code === 'EMPTY_RESULT') {
    console.warn('Column article had no exportable content — retry after full page load');
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: The column article body fails to render before extraction (lazy loading / JS not finished), the article is empty or deleted, or the content selector matches a container whose text is behind a 'read more'/paywall expansion that never opened.

Common situations: Download running before the article content mounts on a slow connection; members-only or deleted columns where the body is blank for the current viewer; the extraction grabbing an empty preview container instead of the full article body.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/f494c020a8b5cfd2. Report an issue: GitHub.