fish2018/pansou · error
[ ] 获取formhash失败
Error message
[%s] 获取formhash失败: %w
What it means
searchImpl wraps any failure from getFormhash, which GETs the site homepage and parses input[name='formhash'] to obtain the CSRF token needed for the search POST. This error means the homepage request or its processing failed (network, non-200 status, gzip or parse error, or missing formhash).
Solutions
- Enable DebugLog to see the actual status code and cookies received
- Check network/proxy connectivity to BaseURL and that the site is up
- Verify the User-Agent/headers in setRequestHeaders are not blocked by the site (try a browser UA)
- Re-check the formhash selector against current site HTML and update if markup changed
- Handle gzip/Cookie flow correctly — reuse the session client so cookies persist
Defensive patterns
Strategy: retry
Validate before calling
// pre-check connectivity before search
resp, err := http.Head(BaseURL)
if err != nil || resp.StatusCode != http.StatusOK {
// skip search, warn user site unreachable
} Try / catch
results, err := plugin.Search(ctx, keyword)
if err != nil {
var wrapped interface{ Unwrap() error }
if errors.As(err, new(error)) && strings.Contains(err.Error(), "获取formhash失败") {
time.Sleep(2*time.Second)
return plugin.Search(ctx, keyword) // bounded retry
}
return err
} Prevention
- Keep DebugLog enabled in staging to see status codes and cookies
- Always reuse the same session client across the search steps
- Use a realistic browser User-Agent
- Monitor for site markup changes and update selectors promptly
- Add bounded retries with backoff
When it happens
Trigger: p.getFormhash(sessionClient) fails during Step 1 of the three-step search flow: GET to BaseURL failed, non-200 status returned, gzip decoding or goquery parsing failed, or no formhash input was found in the HTML.
Common situations: Site is down or blocking the client (rate limiting, missing/blocked User-Agent), network outage or proxy issues, site redesign changing the formhash input markup, or a CDN returning an interstitial/challenge page instead of the real homepage.
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/a239211e273f05e4.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/qupanshe/qupanshe.go:79
}
// 创建带有Cookie管理的专用客户端,确保整个搜索过程使用同一个session
sessionClient, err := p.createSessionClient(client)
if err != nil {
return nil, fmt.Errorf("[%s] 创建session客户端失败: %w", p.Name(), err)
}
if DebugLog {
fmt.Printf("[qupanshe] 创建session客户端成功,开始三步搜索流程\n")
}
// Step 1: 获取首页formhash(使用session客户端)
formhash, err := p.getFormhash(sessionClient)
if err != nil {
if DebugLog {
fmt.Printf("[qupanshe] 获取formhash失败: %v\n", err)
}
return nil, fmt.Errorf("[%s] 获取formhash失败: %w", p.Name(), err)
}
if DebugLog {
fmt.Printf("[qupanshe] 获取到formhash: %s\n", formhash)
}
// Step 2: POST请求获取搜索结果URL(使用同一个session客户端)
searchURL, err := p.postSearchRequest(sessionClient, keyword, formhash)
if err != nil {
if DebugLog {
fmt.Printf("[qupanshe] POST搜索请求失败: %v\n", err)
}
return nil, fmt.Errorf("[%s] POST搜索请求失败: %w", p.Name(), err)
}
if DebugLog {
fmt.Printf("[qupanshe] 获取搜索URL成功: %s\n", searchURL)
}
// Step 3: GET请求获取搜索结果(使用同一个session客户端)View on GitHub (pinned to beaa561337)