fish2018/pansou · warning

无法提取帖子ID: index=

Error message

无法提取帖子ID: index=%d

What it means

During result extraction, each candidate search-result element is expected to carry its post id in the HTML `id` attribute. If the attribute is missing or empty, the plugin pushes this error to errorChan for that index instead of a result. It means the DOM selector matched an element that does not look like a real post row.

Solutions

  1. Update the selector used to collect result elements so it only matches real post rows.
  2. Treat this as a non-fatal per-result error: log it at debug level and continue with remaining results instead of failing the whole search.
  3. Verify the site HTML structure with the actual page and adjust the id extraction (e.g. fall back to parsing the href for the thread id).
  4. Check whether the site changed its markup (browser devtools on a real search page).

Example fix

// before
postID, exists := s.Attr("id")
if !exists || postID == "" {
    errorChan <- fmt.Errorf("无法提取帖子ID: index=%d", index)
    return
}
// after
postID, exists := s.Attr("id")
if !exists || postID == "" {
    if href, ok := s.Find("h3.xs3 a").Attr("href"); ok {
        if _, id, found := strings.Cut(href, "thread-"); found {
            postID = strings.TrimSuffix(id, ".htm")
        }
    }
}
if postID == "" {
    errorChan <- fmt.Errorf("无法提取帖子ID: index=%d", index)
    return
}
Defensive patterns

Strategy: validation

Validate before calling

postID, exists := sel.Attr("id")
if !exists || strings.TrimSpace(postID) == "" {
    // skip this element or attempt href-based fallback before indexing detail page
    return
}

Type guard

func hasPostID(s *goquery.Selection) (string, bool) {
    id, exists := s.Attr("id")
    return strings.TrimSpace(id), exists && strings.TrimSpace(id) != ""
}

Try / catch

results, err := plugin.Search(keyword, ext)
if err != nil {
    if strings.Contains(err.Error(), "无法提取帖子ID") {
        log.Printf("some results skipped (markup change?): %v", err)
        return results, nil // or fall back to another plugin
    }
    return nil, err
}

Prevention

When it happens

Trigger: In the per-element goroutine of doSearch: s.Attr("id") returns exists=false or an empty string — i.e. the `s` selector (post-row matcher) matched a non-post element such as an ad, sticky layout element, or a markup change on the site.

Common situations: Site template redesign (posts no longer carry id attributes), scraper matching sponsored/promoted rows, or pages served with a degraded/mobile layout.

Related errors


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

Appendix: source

Thrown at plugin/hdr4k/hdr4k.go:235

			items = append(items, s)
		}
	})
	
	// 并发处理每个搜索结果项
	for i, s := range items {
		wg.Add(1)
		
		go func(index int, s *goquery.Selection) {
			defer wg.Done()
			
			// 获取信号量
			semaphore <- struct{}{}
			defer func() { <-semaphore }()
			
			// 提取帖子ID
			postID, exists := s.Attr("id")
			if !exists || postID == "" {
				errorChan <- fmt.Errorf("无法提取帖子ID: index=%d", index)
				return
			}
			
			// 提取标题
			titleElement := s.Find("h3.xs3 a")
			title := p.cleanHTML(titleElement.Text())
			title = strings.TrimSpace(title)
			
			// 提取内容描述
			contentElement := s.Find("p").First()
			content := p.cleanHTML(contentElement.Text())
			content = strings.TrimSpace(content)
			
			// 提取日期时间
			var datetime time.Time
			dateElements := s.Find("p span")
			if dateElements.Length() > 0 {
				dateStr := strings.TrimSpace(dateElements.First().Text())

View on GitHub (pinned to beaa561337)