refactor: 改进浏览器实例管理,按需创建浏览器实例 (#12)

- 移除全局浏览器单例,改为按需创建浏览器实例
- 添加 configs/browser.go 用于管理无头模式配置
- 更新 service.go 中所有方法,每次调用时创建新的浏览器实例
- 更新测试文件,使用新的浏览器管理方式
- 确保每个浏览器实例使用后正确关闭,避免资源泄漏

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
zy
2025-08-17 15:30:16 +08:00
committed by GitHub
parent cfaee894f5
commit 0e4450b12c
7 changed files with 41 additions and 41 deletions

View File

@@ -1,17 +1,12 @@
package browser package browser
import ( import (
"github.com/go-rod/rod"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/xpzouying/headless_browser" "github.com/xpzouying/headless_browser"
"github.com/xpzouying/xiaohongshu-mcp/cookies" "github.com/xpzouying/xiaohongshu-mcp/cookies"
) )
var ( func NewBrowser(headless bool) *headless_browser.Browser {
browser *headless_browser.Browser
)
func Init(headless bool) error {
opts := []headless_browser.Option{ opts := []headless_browser.Option{
headless_browser.WithHeadless(headless), headless_browser.WithHeadless(headless),
@@ -28,15 +23,5 @@ func Init(headless bool) error {
logrus.Warnf("failed to load cookies: %v", err) logrus.Warnf("failed to load cookies: %v", err)
} }
browser = headless_browser.New(opts...) return headless_browser.New(opts...)
return nil
}
func NewPage() *rod.Page {
return browser.NewPage()
}
func Close() {
browser.Close()
} }

View File

@@ -13,13 +13,11 @@ import (
func main() { func main() {
headlessModel := false // 登录的时候,需要界面,所以不能无头模式
if err := browser.Init(headlessModel); err != nil { b := browser.NewBrowser(false)
logrus.Fatalf("failed to init browser: %v", err) defer b.Close()
}
defer browser.Close()
page := browser.NewPage() page := b.NewPage()
defer page.Close() defer page.Close()
action := xiaohongshu.NewLogin(page) action := xiaohongshu.NewLogin(page)

14
configs/browser.go Normal file
View File

@@ -0,0 +1,14 @@
package configs
var (
useHeadless = true
)
func InitHeadless(h bool) {
useHeadless = h
}
// IsHeadless 是否无头模式。
func IsHeadless() bool {
return useHeadless
}

View File

@@ -3,9 +3,8 @@ package main
import ( import (
"flag" "flag"
"github.com/xpzouying/xiaohongshu-mcp/browser"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/xpzouying/xiaohongshu-mcp/configs"
) )
func main() { func main() {
@@ -16,10 +15,7 @@ func main() {
flag.BoolVar(&headless, "headless", true, "是否无头模式") flag.BoolVar(&headless, "headless", true, "是否无头模式")
flag.Parse() flag.Parse()
if err := browser.Init(headless); err != nil { configs.InitHeadless(headless)
logrus.Fatalf("failed to init browser: %v", err)
}
defer browser.Close()
if err := startServer(); err != nil { if err := startServer(); err != nil {
logrus.Fatalf("failed to run server: %v", err) logrus.Fatalf("failed to run server: %v", err)

View File

@@ -47,9 +47,12 @@ type FeedsListResponse struct {
// CheckLoginStatus 检查登录状态 // CheckLoginStatus 检查登录状态
func (s *XiaohongshuService) CheckLoginStatus(ctx context.Context) (*LoginStatusResponse, error) { func (s *XiaohongshuService) CheckLoginStatus(ctx context.Context) (*LoginStatusResponse, error) {
// 使用全局单例浏览器创建新页面 b := browser.NewBrowser(configs.IsHeadless())
page := browser.NewPage() defer b.Close()
page := b.NewPage()
defer page.Close() defer page.Close()
loginAction := xiaohongshu.NewLogin(page) loginAction := xiaohongshu.NewLogin(page)
isLoggedIn, err := loginAction.CheckLoginStatus(ctx) isLoggedIn, err := loginAction.CheckLoginStatus(ctx)
@@ -103,8 +106,10 @@ func (s *XiaohongshuService) processImages(images []string) ([]string, error) {
// publishContent 执行内容发布 // publishContent 执行内容发布
func (s *XiaohongshuService) publishContent(ctx context.Context, content xiaohongshu.PublishImageContent) error { func (s *XiaohongshuService) publishContent(ctx context.Context, content xiaohongshu.PublishImageContent) error {
// 使用全局单例浏览器创建新页面 b := browser.NewBrowser(configs.IsHeadless())
page := browser.NewPage() defer b.Close()
page := b.NewPage()
defer page.Close() defer page.Close()
action, err := xiaohongshu.NewPublishImageAction(page) action, err := xiaohongshu.NewPublishImageAction(page)
@@ -118,8 +123,10 @@ func (s *XiaohongshuService) publishContent(ctx context.Context, content xiaohon
// ListFeeds 获取Feeds列表 // ListFeeds 获取Feeds列表
func (s *XiaohongshuService) ListFeeds(ctx context.Context) (*FeedsListResponse, error) { func (s *XiaohongshuService) ListFeeds(ctx context.Context) (*FeedsListResponse, error) {
// 使用全局单例浏览器创建新页面 b := browser.NewBrowser(configs.IsHeadless())
page := browser.NewPage() defer b.Close()
page := b.NewPage()
defer page.Close() defer page.Close()
// 创建 Feeds 列表 action // 创建 Feeds 列表 action

View File

@@ -14,10 +14,10 @@ func TestGetFeedsList(t *testing.T) {
t.Skip("SKIP: 测试发布") t.Skip("SKIP: 测试发布")
_ = browser.Init(false) b := browser.NewBrowser(false)
defer browser.Close() defer b.Close()
page := browser.NewPage() page := b.NewPage()
defer page.Close() defer page.Close()
// NewFeedsListAction 内部已经处理导航 // NewFeedsListAction 内部已经处理导航

View File

@@ -14,10 +14,10 @@ func TestPublish(t *testing.T) {
t.Skip("SKIP: 测试发布") t.Skip("SKIP: 测试发布")
_ = browser.Init(false) b := browser.NewBrowser(false)
defer browser.Close() defer b.Close()
page := browser.NewPage() page := b.NewPage()
defer page.Close() defer page.Close()
action, err := NewPublishImageAction(page) action, err := NewPublishImageAction(page)