fish2018/pansou · error
获取验证脚本失败
Error message
获取验证脚本失败: %w
What it means
After locating the verification script URL, solveVerification downloads the JS file with fetchBody. If that HTTP fetch fails (network error, timeout, non-OK status handled by fetchBody), the error is wrapped with this message and returned, aborting the verification solve. The %w wrapping preserves the underlying network/HTTP error for errors.Is/As inspection.
Solutions
- Print/check the wrapped cause (errors.Unwrap) to see if it's a timeout, DNS failure, or HTTP status, and fix accordingly.
- Verify normalizeURL(pageURL, scriptMatch[1]) yields the correct absolute script URL — a bad base or relative path yields a 404.
- Ensure the request carries the site's cookies/Referer (same client with cookie jar) since the script host may reject unauthenticated fetches.
- Increase detailTimeout if the script host is slow, or retry the fetch with backoff.
- Check whether the script URL changed on the site and update the fetch or add a fallback mirror path.
Example fix
// before
jsBody, err := p.fetchBody(client, scriptURL, pageURL, detailTimeout)
if err != nil {
return fmt.Errorf("获取验证脚本失败: %w", err)
}
// after
jsBody, err := p.fetchBody(client, scriptURL, pageURL, detailTimeout)
if err != nil {
return fmt.Errorf("获取验证脚本失败 (url=%s): %w", scriptURL, err) // include URL for diagnosis
} Defensive patterns
Strategy: retry
Validate before calling
// sanity-check the absolute script URL before fetching
abs := normalizeURL(pageURL, scriptMatch[1])
if u, err := neturl.Parse(abs); err != nil || u.Host == "" {
return fmt.Errorf("invalid verification script URL derived from %s", pageURL)
} Type guard
func isScriptFetchErr(err error) bool {
var ne net.Error
return err != nil && (errors.As(err, &ne) || strings.Contains(err.Error(), "获取验证脚本失败"))
} Try / catch
if err := plugin.SolveVerification(client, pageURL, body); err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// transient: retry once with a longer timeout
time.Sleep(time.Second)
return plugin.SolveVerification(client, pageURL, body)
}
return err
} Prevention
- Set detailTimeout generously for script CDN fetches, with one retry on timeout.
- Log scriptURL on failure to distinguish bad URL construction from network issues.
- Ensure cookies/Referer from the challenge page are sent when fetching the script.
- Verify normalizeURL output in tests for relative script paths (e.g. /static/verify.js).
- Watch the wrapped cause for 403/404 to detect bot-blocking or script relocation early.
When it happens
Trigger: In solveVerification, p.fetchBody(client, scriptURL, pageURL, detailTimeout) returns a non-nil error while downloading the verification challenge JS from the host serving the slider script.
Common situations: The script host blocks datacenter IPs or requires a Referer/cookie the client isn't sending; scriptURL is relative and normalizeURL produced a wrong absolute URL; detailTimeout is too short for a slow script CDN; the site moved or removed the verification script (404).
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/108ba0be60ad3e09.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/qiwei/qiwei.go:359
if lastErr == nil {
lastErr = fmt.Errorf("[%s] 获取详情失败: %s", p.Name(), detailURL)
}
return detailInfo{}, lastErr
}
// solveVerification completes the site's deterministic slider challenge. The
// challenge is session-bound, so the caller and this method must share a
// cookie jar on the same http.Client.
func (p *QiweiPlugin) solveVerification(client *http.Client, pageURL, verifyHTML string) error {
scriptMatch := verificationScriptRegex.FindStringSubmatch(verifyHTML)
if len(scriptMatch) < 2 {
return fmt.Errorf("未找到滑动验证脚本")
}
scriptURL := normalizeURL(pageURL, scriptMatch[1])
jsBody, err := p.fetchBody(client, scriptURL, pageURL, detailTimeout)
if err != nil {
return fmt.Errorf("获取验证脚本失败: %w", err)
}
typeMatch := verificationTypeRegex.FindStringSubmatch(jsBody)
keyMatch := verificationKeyRegex.FindStringSubmatch(jsBody)
valueMatch := verificationValueRegex.FindStringSubmatch(jsBody)
if len(typeMatch) < 2 || len(keyMatch) < 2 || len(valueMatch) < 2 {
return fmt.Errorf("验证脚本参数不完整")
}
encodedValue := md5StringToHex(valueMatch[1])
endpointPath := "/a20be899_96a6_40b2_88ba_32f1f75f1552_yanzheng_huadong.php"
if endpointMatch := verificationEndpointRegex.FindStringSubmatch(jsBody); len(endpointMatch) > 1 {
endpointPath = "/" + endpointMatch[1]
}
parsedPage, err := url.Parse(pageURL)
if err != nil {
return fmt.Errorf("验证页面地址无效: %w", err)
}View on GitHub (pinned to beaa561337)