fish2018/pansou · error
未找到DToken
Error message
未找到DToken
What it means
getToken scraped the token page successfully but no script tag contained a DToken definition, so the token variable stayed empty. The plugin depends on this client-side token to build authenticated search requests; without it searching is impossible. This is a page-structure/anti-bot change on the upstream site rather than a network fault.
Solutions
- Fetch the token page manually and inspect script contents to find the new token variable name or delivery mechanism
- Update the extraction regex/selector in getToken to match the current script pattern
- Check whether the token now comes from a cookie (e.g. DToken cookie) or a JSON endpoint and scrape that instead
- Detect challenge pages (markers like 'captcha'/'verify') and surface a clearer error instead of '未找到DToken'
Example fix
// before
if token == "" {
return "", fmt.Errorf("未找到DToken")
}
// after
if token == "" {
return "", fmt.Errorf("未找到DToken: token页面结构可能已变更或返回了验证页面 (url=%s, len=%d)", tokenURL, len(pageHTML))
} Defensive patterns
Strategy: fallback
Validate before calling
html, _ := io.ReadAll(resp.Body)
if !strings.Contains(string(html), "DToken") {
return fmt.Errorf("token page no longer exposes DToken; scraper needs update")
} Try / catch
token, err := getToken(ctx)
if errors.Is(err, errDTokenNotFound) {
return scrapeTokenFromCookieJar(client) // alternate extraction path
} Prevention
- Add a canary test that fetches the token page and asserts DToken extraction works
- Detect challenge/consent pages explicitly and report a distinct error
- Cache tokens to reduce scraping frequency and lower detection risk
When it happens
Trigger: After iterating doc.Find("script"), token == "" — the DToken regex found no match in any inline script (site renamed the variable, moved token into external JS/headers, or served a challenge page with 200).
Common situations: Upstream site updated its front-end and renamed/moved DToken; served a consent/anti-bot page with HTTP 200; token now delivered via cookie or API endpoint instead of inline script.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/6526e65a3af30d4e.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xys/xys.go:195
// 查找script标签中的DToken定义
var token string
doc.Find("script").Each(func(i int, s *goquery.Selection) {
scriptContent := s.Text()
if strings.Contains(scriptContent, "DToken") {
// 使用正则表达式提取token
re := regexp.MustCompile(`const\s+DToken\s*=\s*"([^"]+)"`)
matches := re.FindStringSubmatch(scriptContent)
if len(matches) > 1 {
token = matches[1]
if p.debugMode {
log.Printf("[XYS] 从script中提取到token: %s", token[:10]+"...")
}
}
}
})
if token == "" {
return "", fmt.Errorf("未找到DToken")
}
// 缓存token
p.tokenCache.Store(cacheKey, TokenCache{
Token: token,
Timestamp: time.Now(),
})
return token, nil
}
// doRequestWithRetry 带重试机制的HTTP请求
func (p *XysPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {
maxRetries := 3
var lastErr error
for i := 0; i < maxRetries; i++ {
if i > 0 {View on GitHub (pinned to beaa561337)