fish2018/pansou · error

[ ] 创建网页搜索请求失败

Error message

[%s] 创建网页搜索请求失败: %w

What it means

searchWeb is the HTML scraping fallback used when the JSON API path fails; it builds a second request to SearchWebURL and wraps any construction error in this message. As with the API path, this fires before any bytes hit the network.

Solutions

  1. Validate the composed searchURL with url.Parse before creating the request
  2. Check the SearchWebURL constant and query string composition
  3. Confirm url.QueryEscape is applied to all user-supplied parts

Example fix

// before
searchURL := SearchWebURL + "?wd=" + url.QueryEscape(keyword) + "&ext=1"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
// after
u, uerr := url.Parse(SearchWebURL)
if uerr != nil {
    return nil, fmt.Errorf("invalid SearchWebURL %q: %w", SearchWebURL, uerr)
}
q := u.Query(); q.Set("wd", keyword); q.Set("ext", "1"); u.RawQuery = q.Encode()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(SearchWebURL)
if err != nil || u.Host == "" {
    return nil, fmt.Errorf("invalid SearchWebURL %q: %w", SearchWebURL, err)
}

Try / catch

results, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "创建网页搜索请求失败") {
    return nil, fmt.Errorf("feikuai web fallback misconfigured: %w", err)
}

Prevention

When it happens

Trigger: http.NewRequestWithContext(ctx, http.MethodGet, SearchWebURL+"?wd="+url.QueryEscape(keyword)+"&ext=1", nil) fails — malformed URL composition or illegal characters after concatenation.

Common situations: Stale or mistyped SearchWebURL constant, keyword containing characters that break the URL even after QueryEscape (e.g. embedded control chars), domain rotation mistakes.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at plugin/feikuai/feikuai.go:177

				results = append(results, result)
			}
		}
	}

	// 使用关键词过滤结果
	return plugin.FilterResultsByKeyword(results, keyword), nil
}

// searchWebFallback parses the current server-rendered external search page.
// Feikuai's legacy JSON endpoint now responds with 403, while this page still
// exposes both disk links and magnets in stable HTML markup.
func (p *FeikuaiPlugin) searchWeb(client *http.Client, keyword string, apiErr error) ([]model.SearchResult, error) {
	ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
	defer cancel()
	searchURL := SearchWebURL + "?wd=" + url.QueryEscape(keyword) + "&ext=1"
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建网页搜索请求失败: %w", p.Name(), err)
	}
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/136.0.0.0 Safari/537.36")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Referer", "https://feikuai.in/")
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("[%s] API 失败且网页搜索请求失败: %v (API: %v)", p.Name(), err, apiErr)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("[%s] API 失败且网页搜索返回状态码 %d (API: %v)", p.Name(), resp.StatusCode, apiErr)
	}
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 网页搜索 HTML 解析失败: %w", p.Name(), err)
	}

View on GitHub (pinned to beaa561337)