diff --git a/xiaohongshu/publish.go b/xiaohongshu/publish.go index 0484f40..29bd950 100644 --- a/xiaohongshu/publish.go +++ b/xiaohongshu/publish.go @@ -293,7 +293,7 @@ func submitPublish(page *rod.Page, title, content string, tags []string, schedul slog.Info("定时发布设置完成", "schedule_time", scheduleTime.Format("2006-01-02 15:04")) } - submitButton := page.MustElement("div.submit div.d-button-content") + submitButton := page.MustElement(".publish-page-publish-btn button.bg-red") submitButton.MustClick() time.Sleep(3 * time.Second) @@ -525,129 +525,51 @@ func isElementVisible(elem *rod.Element) bool { // setSchedulePublish 设置定时发布时间 func setSchedulePublish(page *rod.Page, t time.Time) error { - // 1. 点击"定时发布" radio button - if err := clickScheduleRadio(page); err != nil { + // 1. 点击定时发布开关 + if err := clickScheduleSwitch(page); err != nil { return err } - time.Sleep(500 * time.Millisecond) + time.Sleep(800 * time.Millisecond) - // 2. 点击时间选择器打开面板 - if err := clickDateTimePicker(page); err != nil { - return err - } - time.Sleep(500 * time.Millisecond) - - // 3. 设置日期和时间 + // 2. 设置日期时间 if err := setDateTime(page, t); err != nil { return err } - time.Sleep(300 * time.Millisecond) - - // 4. 点击确定按钮 - if err := clickConfirmButton(page); err != nil { - return err - } time.Sleep(500 * time.Millisecond) return nil } -// clickScheduleRadio 点击定时发布 radio -func clickScheduleRadio(page *rod.Page) error { - labels, err := page.Elements("span.el-radio__label") +// clickScheduleSwitch 点击定时发布开关 +func clickScheduleSwitch(page *rod.Page) error { + switchElem, err := page.Element(".post-time-wrapper .d-switch") if err != nil { - return errors.Wrap(err, "查找 radio label 失败") + return errors.Wrap(err, "查找定时发布开关失败") } - for _, label := range labels { - text, err := label.Text() - if err != nil { - continue - } - if strings.TrimSpace(text) == "定时发布" { - if err := label.Click(proto.InputMouseButtonLeft, 1); err != nil { - return errors.Wrap(err, "点击定时发布按钮失败") - } - slog.Info("已点击定时发布按钮") - return nil - } + if err := switchElem.Click(proto.InputMouseButtonLeft, 1); err != nil { + return errors.Wrap(err, "点击定时发布开关失败") } - - return errors.New("未找到定时发布按钮") -} - -// clickDateTimePicker 点击时间选择器 -func clickDateTimePicker(page *rod.Page) error { - // 查找日期时间选择器输入框 - picker, err := page.Element("input.el-input__inner[placeholder='选择日期和时间']") - if err != nil { - return errors.Wrap(err, "查找时间选择器失败") - } - - if err := picker.Click(proto.InputMouseButtonLeft, 1); err != nil { - return errors.Wrap(err, "点击时间选择器失败") - } - slog.Info("已点击时间选择器") + slog.Info("已点击定时发布开关") return nil } -// setDateTime 设置日期和时间 +// setDateTime 设置日期时间 func setDateTime(page *rod.Page, t time.Time) error { - dateStr := t.Format("2006-01-02") - timeStr := t.Format("15:04") + dateTimeStr := t.Format("2006-01-02 15:04") - // 设置日期 - dateInput, err := page.Element("input.el-input__inner[placeholder='选择日期']") + input, err := page.Element(".date-picker-container input") if err != nil { - return errors.Wrap(err, "查找日期输入框失败") + return errors.Wrap(err, "查找日期时间输入框失败") } - if err := dateInput.SelectAllText(); err != nil { - return errors.Wrap(err, "选择日期文本失败") - } - if err := dateInput.Input(dateStr); err != nil { - return errors.Wrap(err, "输入日期失败") - } - slog.Info("已设置日期", "date", dateStr) - time.Sleep(300 * time.Millisecond) - - // 设置时间 - timeInput, err := page.Element("input.el-input__inner[placeholder='选择时间']") - if err != nil { - return errors.Wrap(err, "查找时间输入框失败") + if err := input.SelectAllText(); err != nil { + return errors.Wrap(err, "选择日期时间文本失败") } - if err := timeInput.SelectAllText(); err != nil { - return errors.Wrap(err, "选择时间文本失败") + if err := input.Input(dateTimeStr); err != nil { + return errors.Wrap(err, "输入日期时间失败") } - if err := timeInput.Input(timeStr); err != nil { - return errors.Wrap(err, "输入时间失败") - } - slog.Info("已设置时间", "time", timeStr) + slog.Info("已设置日期时间", "datetime", dateTimeStr) return nil } - -// clickConfirmButton 点击确定按钮 -func clickConfirmButton(page *rod.Page) error { - // 查找日期选择器弹窗中的确定按钮 - buttons, err := page.Elements("button.el-picker-panel__link-btn") - if err != nil { - return errors.Wrap(err, "查找确定按钮失败") - } - - for _, btn := range buttons { - text, err := btn.Text() - if err != nil { - continue - } - if strings.TrimSpace(text) == "确定" { - if err := btn.Click(proto.InputMouseButtonLeft, 1); err != nil { - return errors.Wrap(err, "点击确定按钮失败") - } - slog.Info("已点击确定按钮") - return nil - } - } - - return errors.New("未找到确定按钮") -} diff --git a/xiaohongshu/publish_video.go b/xiaohongshu/publish_video.go index 13e8f5c..614d561 100644 --- a/xiaohongshu/publish_video.go +++ b/xiaohongshu/publish_video.go @@ -10,6 +10,7 @@ import ( "github.com/go-rod/rod" "github.com/go-rod/rod/lib/proto" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // PublishVideoContent 发布视频内容 @@ -21,14 +22,26 @@ type PublishVideoContent struct { ScheduleTime *time.Time // 定时发布时间,nil 表示立即发布 } -// NewPublishVideoAction 进入发布页并切换到“上传视频” +// NewPublishVideoAction 进入发布页并切换到"上传视频" func NewPublishVideoAction(page *rod.Page) (*PublishAction, error) { pp := page.Timeout(300 * time.Second) - pp.MustNavigate(urlOfPublic).MustWaitIdle().MustWaitDOMStable() + if err := pp.Navigate(urlOfPublic); err != nil { + return nil, errors.Wrap(err, "导航到发布页面失败") + } + + // 使用 WaitLoad 代替 WaitIdle(更宽松) + if err := pp.WaitLoad(); err != nil { + logrus.Warnf("等待页面加载出现问题: %v,继续尝试", err) + } + time.Sleep(2 * time.Second) + + if err := pp.WaitDOMStable(time.Second, 0.1); err != nil { + logrus.Warnf("等待 DOM 稳定出现问题: %v,继续尝试", err) + } time.Sleep(1 * time.Second) - if err := mustClickPublishTab(page, "上传视频"); err != nil { + if err := mustClickPublishTab(pp, "上传视频"); err != nil { return nil, errors.Wrap(err, "切换到上传视频失败") } @@ -90,7 +103,7 @@ func waitForPublishButtonClickable(page *rod.Page) (*rod.Element, error) { maxWait := 10 * time.Minute interval := 1 * time.Second start := time.Now() - selector := "button.publishBtn" + selector := ".publish-page-publish-btn button.bg-red" slog.Info("开始等待发布按钮可点击(视频)")