fish2018/pansou · error

解析验证数据失败

Error message

解析验证数据失败: %w

What it means

When the plugin receives an anti-bot challenge page, it extracts an embedded JSON payload (matches[1]) with the challenge parameters and unmarshals it into ChallengePageData. If json.Unmarshal fails — the extracted blob is not valid JSON or doesn't match the expected shape (e.g. it's HTML-wrapped or the site changed its page format) — the error is wrapped as '解析验证数据失败: %w'.

Solutions

  1. Log the wrapped %w error plus matches[1] (truncated) to see the actual payload, then update the extraction regex/decoding (e.g. html.UnescapeString) for the new page format.
  2. Sanitize the blob before unmarshaling: strip surrounding quotes/backslashes (if JSON-in-string, json.Unmarshal into a string first) and trim non-JSON trailing characters.
  3. Check if the page is actually a different challenge type and route it to solveRemotePowChallenge or another solver instead of parsing it as POW data.
  4. Update ChallengePageData field tags if the site renamed fields, so unmarshal succeeds.

Example fix

// before
if err := json.Unmarshal(matches[1], &challenge); err != nil {
    return fmt.Errorf("解析验证数据失败: %w", err)
}
// after
blob := []byte(html.UnescapeString(string(matches[1])))
if err := json.Unmarshal(blob, &challenge); err != nil {
    return p.solveRemotePowChallenge(scraper, requestURL) // fall back for unexpected formats
}
Defensive patterns

Strategy: fallback

Validate before calling

func looksLikeChallengeJSON(s string) bool {
    var c struct { ID string `json:"id"`; N string `json:"n"`; X string `json:"x"`; T int64 `json:"t"` }
    return json.Unmarshal([]byte(s), &c) == nil && c.ID != "" && c.N != ""
}
// if false, skip POW parsing and use the remote-challenge path

Try / catch

challenge, err := parseChallengeFromBody(body)
if err != nil {
    if strings.Contains(err.Error(), "解析验证数据失败") {
        return p.solveRemotePowChallenge(scraper, requestURL) // graceful fallback
    }
    return err
}

Prevention

When it happens

Trigger: The regex matched a challenge script on the page but the captured group contains malformed or non-canonical JSON (HTML entities, trailing garbage, new site page layout), so json.Unmarshal into ChallengePageData errors before the POW solver can run.

Common situations: Upstream site updated its challenge page format so the regex grabs the wrong region; response decompressed/escaped differently than expected; site returns a different captcha variant whose payload isn't the expected JSON object.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/1ec6882568b4ec65. Report an issue: GitHub.

Appendix: source

Thrown at plugin/gying/gying.go:1665

		baseTransport.Proxy = http.ProxyURL(proxyURL)
	}

	if DebugLog {
		fmt.Printf("[Gying] 已应用代理到scraper: %s\n", config.AppConfig.ProxyURL)
	}

	return nil
}

func (p *GyingPlugin) solveBotChallenge(scraper *cloudscraper.Scraper, requestURL string, body []byte) error {
	matches := challengeJSONPattern.FindSubmatch(body)
	if len(matches) < 2 {
		return p.solveRemotePowChallenge(scraper, requestURL)
	}

	var challenge ChallengePageData
	if err := json.Unmarshal(matches[1], &challenge); err != nil {
		return fmt.Errorf("解析验证数据失败: %w", err)
	}

	if challenge.ID != "" && challenge.N != "" && challenge.X != "" && challenge.T > 0 {
		return p.solvePowChallenge(scraper, requestURL, &challenge)
	}

	return p.solveLegacyHashChallenge(scraper, requestURL, &challenge)
}

func (p *GyingPlugin) solveRemotePowChallenge(scraper *cloudscraper.Scraper, requestURL string) error {
	powURL, err := p.buildPowURL(requestURL)
	if err != nil {
		return err
	}

	if DebugLog {
		fmt.Printf("[Gying] Remote PoW Challenge命中: url=%s powURL=%s\n", requestURL, powURL)
	}

View on GitHub (pinned to beaa561337)