Golang解析需要登录的网站时遇到问题

Golang解析需要登录的网站时遇到问题 我正在尝试从供应商网站解析商品信息,但不知道为什么我的代码无法正常工作。我使用 MercuryEngineering/CookieMonster 设置 cookie,虽然能返回网站数据,但返回的是登录页面数据而不是商品页面数据:

func main() {
cookies, err := cookiemonster.ParseFile("MyCookieFile.txt")
if err != nil {
	panic(err)
}

cookiejar, err := cookiejar.New(nil)
if err != nil {
	panic(err)
}

u, err := url.Parse("MySite")
if err != nil {
	panic(err)
}

cookiejar.SetCookies(u, cookies)

if err != nil {
	panic(err)
}

// jujujar, err := cookiejar.New(&cookiejar.Options{
// 	Filename: cookies,
// })

// if err != nil {
// 	panic(err)
// }

client := &http.Client{
	Jar: cookiejar,
}

response, err := client.Get("MySiteDirectoryWithProducts")

if err != nil {
	panic(err)
}

query, err := goquery.NewDocumentFromResponse(response)
if err != nil {
	panic(err)
}

myQuery := query.Find("body a").Each(func(index int, item *goquery.Selection) {
	linkTag := item
	link, _ := linkTag.Attr("href")
	linkText := linkTag.Text()
	fmt.Printf("Link #%d: '%s' - '%s'\n", index, linkText, link)
})

fmt.Print(myQuery)
}

更多关于Golang解析需要登录的网站时遇到问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复
func main() {
    fmt.Println("hello world")
}

更多关于Golang解析需要登录的网站时遇到问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


请确保 MyCookieFile.txt 中的 Cookie 是有效的。 你不能简单地复制浏览器中的 Cookie,因为它们通常在一段时间后会过期,并且是特定于你的浏览器的(服务器可能还会检查 User-Agent)。 要通过编程方式查询需要登录的网站,你也可以使用 Go 进行登录:将你的凭据发送到登录页面以获取新的 Cookie。

func main() {
    fmt.Println("hello world")
}

问题在于你的代码没有正确处理会话管理和重定向。当网站需要登录时,仅仅设置Cookie可能不够,还需要确保会话有效且遵循正确的认证流程。

以下是修复后的代码:

package main

import (
	"fmt"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	cookiemonster "github.com/MercuryEngineering/CookieMonster"
)

func main() {
	// 解析Cookie文件
	cookies, err := cookiemonster.ParseFile("MyCookieFile.txt")
	if err != nil {
		log.Fatal("解析Cookie文件失败:", err)
	}

	// 创建Cookie Jar
	jar, err := cookiejar.New(nil)
	if err != nil {
		log.Fatal("创建Cookie Jar失败:", err)
	}

	// 解析目标URL
	targetURL := "MySite"
	u, err := url.Parse(targetURL)
	if err != nil {
		log.Fatal("解析URL失败:", err)
	}

	// 设置Cookie到Jar
	jar.SetCookies(u, cookies)

	// 创建HTTP客户端,启用Cookie和重定向处理
	client := &http.Client{
		Jar: jar,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			// 在重定向时保持Cookie
			return nil
		},
		Timeout: 30 * time.Second,
	}

	// 创建请求并设置必要的Header
	req, err := http.NewRequest("GET", "MySiteDirectoryWithProducts", nil)
	if err != nil {
		log.Fatal("创建请求失败:", err)
	}

	// 设置用户代理和其他必要的Header
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
	req.Header.Set("Accept-Language", "en-US,en;q=0.5")
	req.Header.Set("Connection", "keep-alive")

	// 发送请求
	response, err := client.Do(req)
	if err != nil {
		log.Fatal("发送请求失败:", err)
	}
	defer response.Body.Close()

	// 检查响应状态码
	if response.StatusCode != http.StatusOK {
		log.Printf("警告: 收到非200状态码: %d", response.StatusCode)
	}

	// 验证是否成功登录 - 检查响应内容是否包含登录页面特征
	doc, err := goquery.NewDocumentFromReader(response.Body)
	if err != nil {
		log.Fatal("解析HTML失败:", err)
	}

	// 检查页面标题或特定元素来判断是否在登录页面
	pageTitle := doc.Find("title").Text()
	if strings.Contains(strings.ToLower(pageTitle), "login") || 
	   strings.Contains(strings.ToLower(pageTitle), "sign in") {
		log.Fatal("仍然在登录页面,Cookie可能已过期或无效")
	}

	// 如果成功进入商品页面,提取链接
	fmt.Println("成功访问商品页面,提取链接:")
	doc.Find("body a").Each(func(index int, item *goquery.Selection) {
		link, exists := item.Attr("href")
		if exists {
			linkText := item.Text()
			fmt.Printf("Link #%d: '%s' - '%s'\n", index, strings.TrimSpace(linkText), link)
		}
	})

	// 调试信息:显示当前Cookie
	fmt.Printf("\n当前会话Cookie数量: %d\n", len(jar.Cookies(u)))
	for i, cookie := range jar.Cookies(u) {
		fmt.Printf("Cookie %d: %s=%s\n", i+1, cookie.Name, cookie.Value)
	}
}

如果仍然遇到问题,可以添加会话验证功能:

// 验证会话是否有效
func validateSession(client *http.Client, baseURL string) bool {
	req, err := http.NewRequest("GET", baseURL, nil)
	if err != nil {
		return false
	}

	resp, err := client.Do(req)
	if err != nil {
		return false
	}
	defer resp.Body.Close()

	// 检查响应中是否包含登录相关的关键词
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return false
	}

	// 检查页面是否包含登录表单或登录相关文本
	hasLoginForm := doc.Find("input[type='password']").Length() > 0
	hasLoginText := strings.Contains(strings.ToLower(doc.Text()), "login") || 
				   strings.Contains(strings.ToLower(doc.Text()), "sign in")
	
	return !hasLoginForm && !hasLoginText
}

主要修复点:

  1. 使用自定义请求而非简单的client.Get(),以便设置必要的HTTP Header
  2. 添加重定向处理确保Cookie在重定向过程中保持
  3. 添加会话验证逻辑检查是否成功登录
  4. 改进错误处理和调试信息输出
  5. 添加超时设置防止请求挂起
回到顶部