This commit is contained in:
renzhiyuan 2026-04-11 03:12:56 +08:00
parent 15ea020bc1
commit 6c11412307
18 changed files with 7459 additions and 698 deletions

View File

@ -1 +1 @@
[{"name":"websectiga","value":"7750c37de43b7be9de8ed9ff8ea0e576519e8cd2157322eb972ecb429a7735d4","domain":".xiaohongshu.com","path":"/","expires":1776073705,"size":74,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"x-user-id-creator.xiaohongshu.com","value":"65d74a4c0000000005032a98","domain":".xiaohongshu.com","path":"/","expires":1810179755.091531,"size":57,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"xsecappid","value":"ugc","domain":".xiaohongshu.com","path":"/","expires":1807350714,"size":12,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"a1","value":"19d6b2f0b04zdps8dison8k8oibcyzaju3ji7d03d30000118748","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":54,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"webId","value":"f840cc8b10e0a01b0bdb839482af19d1","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":37,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"access-token-creator.xiaohongshu.com","value":"customer.creator.AT-68c517626228786611519495vggizcwmifuvnaaw","domain":".xiaohongshu.com","path":"/","expires":1778211754.091569,"size":96,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"sec_poison_id","value":"0e8199c2-5b2c-4b5d-9423-9ce4ae7c7d4a","domain":".xiaohongshu.com","path":"/","expires":1775815110,"size":49,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customerClientId","value":"231145420384063","domain":".xiaohongshu.com","path":"/","expires":1810179755.091552,"size":31,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"ets","value":"1775619738206","domain":".xiaohongshu.com","path":"/","expires":1778211738.206388,"size":16,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"gid","value":"yjfKDJiJ0J7SyjfKDJi8Dqf884ufUMYf3MlIVqfYTYl3D3q8Svu0VW888yyYW4Y8JD0j8Yd2","domain":".xiaohongshu.com","path":"/","expires":1810372429.581067,"size":75,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customer-sso-sid","value":"68c5176262287866115194944uxxdffhcemiwvwt","domain":".xiaohongshu.com","path":"/","expires":1776224554.091467,"size":56,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy_creator_session_id","value":"nWC5PzTFCCSJsLYiRFLFORIWUoUf5c4Egr3v","domain":".xiaohongshu.com","path":"/","expires":1778211755.091586,"size":61,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"acw_tc","value":"0a0d0eb817758145058628343eac7363daa6c0cadc9daf2e0f80b0fb928719","domain":"creator.xiaohongshu.com","path":"/","expires":1775816304.657778,"size":68,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy.creator.beaker.session.id","value":"1775619757404082990054","domain":".xiaohongshu.com","path":"/","expires":1778211755.091605,"size":54,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"loadts","value":"1775814714949","domain":".xiaohongshu.com","path":"/","expires":1807350714,"size":19,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443}]
[{"name":"gid","value":"yjfKDJiJ0J7SyjfKDJi8Dqf884ufUMYf3MlIVqfYTYl3D3q8Svu0VW888yyYW4Y8JD0j8Yd2","domain":".xiaohongshu.com","path":"/","expires":1810372429.581067,"size":75,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"ets","value":"1775619738206","domain":".xiaohongshu.com","path":"/","expires":1778211738.206388,"size":16,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"a1","value":"19d6b2f0b04zdps8dison8k8oibcyzaju3ji7d03d30000118748","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":54,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customer-sso-sid","value":"68c5176262287866115194944uxxdffhcemiwvwt","domain":".xiaohongshu.com","path":"/","expires":1776224554.091467,"size":56,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"x-user-id-creator.xiaohongshu.com","value":"65d74a4c0000000005032a98","domain":".xiaohongshu.com","path":"/","expires":1810179755.091531,"size":57,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"access-token-creator.xiaohongshu.com","value":"customer.creator.AT-68c517626228786611519495vggizcwmifuvnaaw","domain":".xiaohongshu.com","path":"/","expires":1778211754.091569,"size":96,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy_creator_session_id","value":"nWC5PzTFCCSJsLYiRFLFORIWUoUf5c4Egr3v","domain":".xiaohongshu.com","path":"/","expires":1778211755.091586,"size":61,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"webId","value":"f840cc8b10e0a01b0bdb839482af19d1","domain":".xiaohongshu.com","path":"/","expires":1807155738,"size":37,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"xsecappid","value":"ugc","domain":".xiaohongshu.com","path":"/","expires":1807379925,"size":12,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"loadts","value":"1775843925008","domain":".xiaohongshu.com","path":"/","expires":1807379925,"size":19,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"galaxy.creator.beaker.session.id","value":"1775619757404082990054","domain":".xiaohongshu.com","path":"/","expires":1778211755.091605,"size":54,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"websectiga","value":"2a3d3ea002e7d92b5c9743590ebd24010cf3710ff3af8029153751e41a6af4a3","domain":".xiaohongshu.com","path":"/","expires":1776103125,"size":74,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"sec_poison_id","value":"680df974-cc97-44bd-9c18-b9efaafb66cc","domain":".xiaohongshu.com","path":"/","expires":1775844530,"size":49,"httpOnly":false,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"acw_tc","value":"0a00076417758431730566823e6256f5349e529f992a6ba74dc0835439d93a","domain":"creator.xiaohongshu.com","path":"/","expires":1775844709.365943,"size":68,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443},{"name":"customerClientId","value":"231145420384063","domain":".xiaohongshu.com","path":"/","expires":1810179755.091552,"size":31,"httpOnly":true,"secure":false,"session":false,"priority":"Medium","sameParty":false,"sourceScheme":"Secure","sourcePort":443}]

7255
html/bjhpage.html Normal file

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@ package entitys
type PublishTaskDetail struct {
// publish 表字段
ID int `db:"ID"`
RequestID string `db:"request_id"`
PlatIndex string `db:"plat_index"`
Title string `db:"title"`

View File

@ -194,11 +194,30 @@ func (pm *PublishManager) executeOneTask(workerID int, headless bool) {
}
log.Printf("[Worker-%d] 开始处理任务 requestID=%s", workerID, task.RequestID)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
// 使用 channel 接收结果,避免 goroutine 泄漏
resultChan := make(chan *SingleResult, 1)
result := pm.processTask(ctx, task, headless)
go func() {
resultChan <- pm.processTask(ctx, task, headless)
}()
// 监听 ctx 超时
var result *SingleResult
select {
case result = <-resultChan:
// 任务正常完成
case <-ctx.Done():
// 超时或取消
log.Printf("[Worker-%d] 任务超时或被取消 requestID=%s, err=%v", workerID, task.RequestID, ctx.Err())
result = &SingleResult{
Success: false,
Message: fmt.Sprintf("任务执行超时: %v", ctx.Err()),
}
// 注意:这里不能等待 goroutine 结束,因为 processTask 可能卡住
// cancel() 会在 defer 中调用,但 processTask 内部需要响应 ctx.Done()
}
if result == nil {
log.Printf("[Worker-%d] 任务返回空结果", workerID)
@ -246,6 +265,7 @@ func (pm *PublishManager) acquireTask() (*entitys.PublishTaskDetail, error) {
var task entitys.PublishTaskDetail
querySQL := `
SELECT
p.id,
p.request_id,
p.plat_index,
p.title,
@ -302,7 +322,7 @@ func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.
if r := recover(); r != nil {
errMsg := fmt.Sprintf("任务执行发生panic: %v", r)
taskLogger.Printf("❌ CRITICAL: %s", errMsg)
pm.updatePublishStatus(publishData.RequestID, StatusFailed, errMsg)
pm.updatePublishStatus(publishData.ID, StatusFailed, errMsg)
}
}()
@ -310,7 +330,7 @@ func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.
params, sourceUrl := pm.extractTaskParams(publishData, taskLogger)
if params == nil {
pm.updatePublishStatus(publishData.RequestID, StatusFailed, "提取任务参数失败")
pm.updatePublishStatus(publishData.ID, StatusFailed, "提取任务参数失败")
return &SingleResult{Success: false, Message: "提取任务参数失败", RequestId: publishData.RequestID}
}
params.Headless = headless
@ -319,7 +339,7 @@ func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.
if publisherClass == nil {
errMsg := fmt.Sprintf("不支持的平台: %s", params.PlatIndex)
taskLogger.Printf("[任务 %s] ❌ %s", publishData.RequestID, errMsg)
pm.updatePublishStatus(publishData.RequestID, StatusFailed, errMsg)
pm.updatePublishStatus(publishData.ID, StatusFailed, errMsg)
return &SingleResult{Success: false, Message: errMsg, RequestId: publishData.RequestID}
}
@ -327,7 +347,7 @@ func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.
if err != nil {
errMsg := fmt.Sprintf("准备文件失败: %v", err)
taskLogger.Printf("[任务 %s] ❌ %s", publishData.RequestID, errMsg)
pm.updatePublishStatus(publishData.RequestID, StatusFailed, errMsg)
pm.updatePublishStatus(publishData.ID, StatusFailed, errMsg)
return &SingleResult{Success: false, Message: errMsg, RequestId: publishData.RequestID}
}
defer pm.cleanupFiles(docPath, imgPath, taskLogger, publishData.RequestID)
@ -336,7 +356,7 @@ func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.
if err != nil {
errMsg := fmt.Sprintf("提取文档内容失败: %v", err)
taskLogger.Printf("[任务 %s] ❌ %s", publishData.RequestID, errMsg)
pm.updatePublishStatus(publishData.RequestID, StatusFailed, errMsg)
pm.updatePublishStatus(publishData.ID, StatusFailed, errMsg)
return &SingleResult{Success: false, Message: errMsg, RequestId: publishData.RequestID}
}
params.ImagePath = imgPath
@ -348,10 +368,10 @@ func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.
if success {
taskLogger.Printf("[任务 %s] ✅ 发布成功: %s", publishData.RequestID, message)
pm.updatePublishStatus(publishData.RequestID, StatusSuccess, message)
pm.updatePublishStatus(publishData.ID, StatusSuccess, message)
} else {
taskLogger.Printf("[任务 %s] ❌ 发布失败: %s", publishData.RequestID, message)
pm.updatePublishStatus(publishData.RequestID, StatusFailed, message)
pm.updatePublishStatus(publishData.ID, StatusFailed, message)
}
taskLogger.Printf(strings.Repeat("=", 80))
@ -360,12 +380,12 @@ func (pm *PublishManager) processTask(ctx context.Context, publishData *entitys.
}
// RetryTask 重试任务(非无头模式)
func (pm *PublishManager) RetryTask(ctx context.Context, requestID string) *SingleResult {
func (pm *PublishManager) RetryTask(ctx context.Context, tokenId int, requestID string) *SingleResult {
if requestID == "" {
return &SingleResult{Success: false, Message: "requestID不能为空"}
}
publishData, err := pm.GetTaskByRequestID(requestID)
publishData, err := pm.GetTaskByRequestID(requestID, tokenId)
if err != nil || publishData == nil {
return &SingleResult{Success: false, Message: "任务不存在"}
}
@ -379,13 +399,14 @@ func (pm *PublishManager) RetryTask(ctx context.Context, requestID string) *Sing
}
// GetTaskByRequestID 根据RequestID获取任务
func (pm *PublishManager) GetTaskByRequestID(requestID string) (*entitys.PublishTaskDetail, error) {
func (pm *PublishManager) GetTaskByRequestID(requestID string, tokenId int) (*entitys.PublishTaskDetail, error) {
if requestID == "" {
return nil, fmt.Errorf("requestID不能为空")
}
sql := `
SELECT
p.id,
p.request_id,
p.plat_index,
p.title,
@ -403,10 +424,10 @@ func (pm *PublishManager) GetTaskByRequestID(requestID string) (*entitys.Publish
pl.desc
FROM publish p
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
WHERE p.request_id = ?
WHERE p.request_id = ? AND token_id=?
`
var task entitys.PublishTaskDetail
err := pm.db.GetOneToStruct(sql, &task, requestID)
err := pm.db.GetOneToStruct(sql, &task, requestID, tokenId)
if err != nil {
return nil, err
}
@ -503,18 +524,18 @@ func (pm *PublishManager) extractContent(docPath string, publisherClass *publish
}
// updatePublishStatus 更新发布状态
func (pm *PublishManager) updatePublishStatus(requestID string, status int, message string) error {
if requestID == "" {
return fmt.Errorf("requestID不能为空")
func (pm *PublishManager) updatePublishStatus(id int, status int, message string) error {
if id == 0 {
return fmt.Errorf("id不能为空")
}
var err error
if message != "" {
_, err = pm.db.Execute("UPDATE publish SET status = ?, msg = ? WHERE token_id=? AND request_id = ?", status, message, pm.TokenID, requestID)
_, err = pm.db.Execute("UPDATE publish SET status = ?, msg = ? WHERE id=?", status, message, id)
} else {
_, err = pm.db.Execute("UPDATE publish SET status = ? WHERE token_id=? AND request_id = ?", status, pm.TokenID, requestID)
_, err = pm.db.Execute("UPDATE publish SET status = ? WHERE id=?", status, id)
}
if err != nil {
log.Printf("更新发布状态失败: requestID=%s, status=%d, error=%v", requestID, status, err)
log.Printf("更新发布状态失败: id=%s, status=%d, error=%v", id, status, err)
}
return err
}

View File

@ -7,6 +7,7 @@ import (
"log"
"path/filepath"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
@ -29,17 +30,10 @@ func (p *BaijiahaoPublisher) CheckLoginStatus() bool {
}
func (p *BaijiahaoPublisher) CheckLogin() (bool, string) {
driverCreated := false
defer func() {
if driverCreated && p.Browser != nil {
p.Close()
}
}()
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
driverCreated = true
p.Page.MustNavigate(p.EditorURL)
p.Sleep(3)
@ -53,17 +47,10 @@ func (p *BaijiahaoPublisher) CheckLogin() (bool, string) {
}
func (p *BaijiahaoPublisher) WaitLogin() (bool, string) {
driverCreated := false
defer func() {
if driverCreated && p.Browser != nil {
p.Close()
}
}()
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
driverCreated = true
p.Page.MustNavigate(p.LoginedURL)
p.Sleep(3)
@ -98,7 +85,7 @@ func (p *BaijiahaoPublisher) PublishNote() (bool, string) {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
if p.LoadCookies() == nil {
p.Page.MustNavigate(p.EditorURL)
p.WaitForPageReady(5)
@ -121,14 +108,14 @@ func (p *BaijiahaoPublisher) doPublish() (bool, string) {
name string
fn func() error
}{
//{"切换到图文编辑模式", p.switchToGraphicMode},
{"点击hover", p.clickHoverButton},
{"输入内容", p.inputContent},
{"输入标题", p.inputTitle},
{"设置封面", p.uploadImage},
{"点击发布按钮", p.clickPublish},
{"处理确认弹窗", p.handleConfirmModal},
//{"处理确认弹窗", p.handleConfirmModal},
}
//https://baijiahao.baidu.com/builder/rc/clue?aside=0&footer=true&from=news&firstPublish=undefined&word_bag_id=null
for _, step := range steps {
if err := step.fn(); err != nil {
p.LogStep(step.name, false, err.Error())
@ -141,25 +128,50 @@ func (p *BaijiahaoPublisher) doPublish() (bool, string) {
return p.waitForPublishResult()
}
func (p *BaijiahaoPublisher) switchToGraphicMode() error {
p.LogInfo("切换到图文编辑模式...")
tabSelectors := []string{
".list-item.item-active",
".header-list-content .list-item",
"div[role='tab']:first-child",
func (p *BaijiahaoPublisher) clickHoverButton() error {
p.LogInfo("点击HoverButton...")
// 等待弹窗稳定
p.WaitForPageReady(5)
_, err := p.Page.Element("div.cheetah-tour-content")
if err != nil {
return err
}
for _, selector := range tabSelectors {
tab, err := p.Page.Element(selector)
if err == nil && tab != nil {
visible, _ := tab.Visible()
if visible {
p.JSClick(tab)
p.LogInfo(fmt.Sprintf("已点击图文标签: %s", selector))
p.Sleep(1)
return nil
maxAttempts := 10
for i := 0; i < maxAttempts; i++ {
// 检查弹窗是否存在
exists, _, err := p.Page.Has(".cheetah-tour")
if err != nil || !exists {
p.LogInfo("弹窗已关闭")
break
}
// 查找并点击弹窗中的按钮
result, err := p.Page.Eval(`() => {
const btns = document.querySelectorAll('.cheetah-tour .cheetah-btn, .cheetah-tour-next-btn, .cheetah-tour-close');
for (const btn of btns) {
if (btn.offsetParent !== null) {
const text = btn.innerText || btn.textContent;
btn.click();
return text;
}
}
return null;
}`)
if err != nil {
p.LogInfof("执行点击出错: %v", err)
continue
}
p.LogInfof("第%d次点击按钮: %v", i+1, result)
// 等待弹窗响应
time.Sleep(500 * time.Millisecond)
}
p.LogInfo("引导弹窗处理完成")
return nil
}

View File

@ -113,76 +113,61 @@ func NewBasePublisher(ctx context.Context, task *TaskParams, config *config.Conf
func (b *BasePublisher) SetupDriver() error {
b.LogInfo("初始化浏览器。。。。")
b.Headless = true
l := launcher.New().Bin(b.config.Sys.ChromePath)
l.Headless(b.Headless)
// 设置 Leakless 模式(解决 Windows 上的问题)
l.Leakless(false)
userDataDir := filepath.Join(b.config.Sys.ChromeDataDir, b.UserIndex, b.RequestID+fmt.Sprintf("___%d", time.Now().UnixNano()))
//userDataDir := fmt.Sprintf("./chrome_data/user_%d_", time.Now().UnixNano())
os.MkdirAll(userDataDir, 0755)
l := launcher.New().
Bin(b.config.Sys.ChromePath).
UserDataDir(userDataDir).
Headless(b.Headless).
Leakless(false).Set("disable-blink-features", "AutomationControlled")
if b.Headless {
// 无头模式专用参数
l.Set("headless", "new") // 使用新版无头模式
l.Set("disable-gpu")
l.Set("disable-software-rasterizer")
l.Set("disable-dev-shm-usage")
l.Set("no-sandbox")
// 禁用虚拟滚动,避免等待
//l.Set("disable-scroll-to-text-fragment")
l.Set("disable-dev-shm-usage")
} else {
l.Set("window-size", "1920,1080")
l.Set("start-maximized")
// 移除 headless 相关参数
l.Delete("headless")
}
// 设置用户数据目录
userDataDir := filepath.Join(b.config.Sys.ChromeDataDir, b.UserIndex)
os.MkdirAll(userDataDir, 0755)
l.UserDataDir(userDataDir)
// 为每个用户分配一个可用的随机端口,确保端口不冲突
//freePort, err := pkg.GetFreePort()
//if err != nil {
// return fmt.Errorf("获取空闲端口失败: %v", err)
//}
l.Set("remote-debugging-port", "0")
// 关键优化:不重新使用已有的数据目录时不要清除
l.Set("profile-directory", "Default")
//l.Set("profile-directory", "Default")
// 设置 Chrome 启动参数
l.Set("disable-blink-features", "AutomationControlled")
l.Set("no-sandbox")
l.Set("disable-dev-shm-usage")
l.Set("disable-gpu")
l.Set("disable-software-rasterizer")
l.Set("disable-setuid-sandbox")
//l.Set("no-sandbox")
//l.Set("disable-dev-shm-usage")
// 关键:禁用后台限制,让页面在后台也能正常执行
l.Set("disable-background-timer-throttling")
l.Set("disable-backgrounding-occluded-windows")
l.Set("disable-renderer-backgrounding")
l.Set("disable-ipc-flooding-protection")
//l.Set("disable-background-timer-throttling")
//l.Set("disable-backgrounding-occluded-windows")
//l.Set("disable-renderer-backgrounding")
//l.Set("disable-ipc-flooding-protection")
// 窗口大小
l.Set("window-size", "1920,1080")
l.Set("lang", "zh-CN")
l.Set("start-maximized")
l.Set("force-device-scale-factor", "1")
url, err := l.Launch()
if err != nil {
return fmt.Errorf("启动浏览器失败: %v", err)
}
b.Browser = rod.New().Context(b.ctx).ControlURL(url).MustConnect()
b.Page = b.Browser.MustPage()
time.Sleep(5000)
return nil
}
// func (b *BasePublisher) SetupDriver() error {
// b.LogInfo("初始化浏览器。。。。")
// b.Headless = true
//
// b.Browser = rod.New().Context(b.ctx).
// b.Page = b.Browser.MustPage()
// time.Sleep(5000)
// return nil
// }
func (b *BasePublisher) Close() {
if b.Page != nil {
b.Page.Close()
@ -223,6 +208,15 @@ func (b *BasePublisher) LoadCookies() error {
return b.Page.SetCookies(cookies)
}
func (b *BasePublisher) DelCookies() error {
err := os.Remove(b.CookiesFile)
if err != nil {
return err
}
return nil
}
func (b *BasePublisher) RefreshPage() error {
_, err := b.Page.Eval(`() => location.reload()`)
return err
@ -294,7 +288,7 @@ func (b *BasePublisher) LogInfo(message string) {
}
func (b *BasePublisher) LogInfof(message string, arg ...any) {
b.Logger.Printf("📌 %s", message, arg)
b.Logger.Printf("📌 "+message, arg)
}
func (b *BasePublisher) LogError(message string) {

View File

@ -186,7 +186,7 @@ func (p *CSDNPublisher) PublishNote() (bool, string) {
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
// 执行发布流程
steps := []struct {

View File

@ -179,32 +179,22 @@ func (p *DouyinSpPublisher) waitForUploadComplete() error {
func (p *DouyinSpPublisher) inputTitle() error {
p.LogInfo("输入视频标题...")
titleSelectors := []string{
"textarea[placeholder*='标题']",
"input[placeholder*='标题']",
".container-sGoJ9f input",
".semiInput-EyEyPL input",
exist, titleInput, err := p.Page.Has("input[placeholder*='标题']")
if err != nil {
return err
}
if !exist {
return fmt.Errorf("未找到标题输入框")
}
for _, selector := range titleSelectors {
titleInput, err := p.WaitForElementVisible(selector, 5)
if err == nil && titleInput != nil {
p.LogInfo(fmt.Sprintf("找到标题输入框: %s", selector))
p.ClearInput(titleInput)
p.SleepMs(300)
titleInput.Input("")
p.SleepMs(300)
titleInput.Input(p.Title)
p.LogInfo(fmt.Sprintf("标题已输入: %s", p.Title))
p.SleepMs(500)
return nil
}
}
return fmt.Errorf("未找到标题输入框")
}
func (p *DouyinSpPublisher) inputDescription() error {
p.LogInfo("输入视频描述...")
@ -299,22 +289,6 @@ func (p *DouyinSpPublisher) clickPublish() error {
p.LogInfo("已点击发布按钮")
p.SleepMs(3000)
confirmSelectors := []string{
".semi-modal .semi-button-primary",
".confirm-btn-JwJNCk",
"button:contains('确认')",
"button:contains('确定')",
}
for _, selector := range confirmSelectors {
confirmBtn, _ := p.WaitForElementClickable(selector, 2)
if confirmBtn != nil {
p.JSClick(confirmBtn)
p.LogInfo("已确认发布")
p.SleepMs(2000)
break
}
}
return nil
}
@ -374,15 +348,18 @@ func (p *DouyinSpPublisher) InitPage() error {
// 尝试加载cookies并检查登录状态
if err := p.LoadCookies(); err == nil {
p.Page.MustNavigate(p.EditorURL)
p.Page.MustNavigate(p.LoginURL)
p.WaitForPageReady(5)
p.Sleep(2)
p.Sleep(4)
}
// 统一检查登录状态
if !p.CheckLoginStatus() {
p.LogInfo("未登录或登录已过期,需要重新登录")
p.DelCookies()
return fmt.Errorf("需要登录")
}
p.Page.MustNavigate(p.EditorURL)
p.WaitForPageReady(5)
p.SaveCookies()
return nil
}
@ -393,7 +370,7 @@ func (p *DouyinSpPublisher) PublishNote() (bool, string) {
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
steps := []struct {
name string

View File

@ -56,7 +56,7 @@ func (p *JianshuPublisher) WaitLogin() (bool, string) {
defer p.Close()
p.Page.MustNavigate(p.EditorURL)
p.Sleep(3)
p.Sleep(10)
if p.CheckLoginStatus() {
p.SaveCookies()
@ -305,7 +305,7 @@ func (p *JianshuPublisher) PublishNote() (bool, string) {
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
steps := []struct {
name string

View File

@ -471,13 +471,20 @@ func (p *SohuPublisher) InitPage() error {
if err := p.LoadCookies(); err == nil {
p.Page.MustNavigate(p.EditorURL)
p.WaitForPageReady(5)
p.Sleep(2)
}
// 统一检查登录状态
if !p.CheckLoginStatus() {
p.LogInfo("未登录或登录已过期,需要重新登录")
return fmt.Errorf("需要登录")
}
p.Sleep(3)
if p.GetCurrentURL() != p.EditorURL {
p.Page.MustNavigate(p.EditorURL)
p.WaitForPageReady(5)
}
p.SaveCookies()
return nil
}
@ -488,7 +495,7 @@ func (p *SohuPublisher) PublishNote() (bool, string) {
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
steps := []struct {
name string

View File

@ -32,7 +32,7 @@ func (p *ShipinhaoVideoPublisher) PublishNote() (bool, string) {
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
// 3. 加载 cookies 并检查登录状态
if err := p.LoadCookies(); err == nil {
p.Page.Navigate(p.EditorURL)

View File

@ -473,7 +473,7 @@ func (p *ToutiaoPublisher) PublishNote() (bool, string) {
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
// 执行发布流程
steps := []struct {

View File

@ -115,22 +115,13 @@ func (p *XiaohongshuPublisher) inputTitle() error {
p.LogInfo("输入标题...")
// 查找标题输入框
titleSelectors := []string{
"textarea.d-input",
".d-input input",
"textarea[placeholder*='标题']",
"textarea",
}
var titleInput *rod.Element
var err error
for _, selector := range titleSelectors {
titleInput, err = p.WaitForElementVisible(selector, 3)
if err == nil && titleInput != nil {
p.LogInfo(fmt.Sprintf("找到标题输入框: %s", selector))
break
}
exsist, titleInput, err := p.Page.Has("textarea[placeholder*='标题']")
if exsist && err == nil {
p.LogInfo(fmt.Sprintf("找到标题输入框"))
}
if titleInput == nil {
@ -286,8 +277,8 @@ func (p *XiaohongshuPublisher) clickPublish() error {
// 输入话题标签
p.LogInfo("输入话题标签...")
tiptap, err := p.WaitForElement(".tiptap-container", 10)
if err == nil && tiptap != nil {
exist, tiptap, err := p.Page.Has(".tiptap-container")
if err == nil && exist {
editors, err := tiptap.Elements("[contenteditable='true']")
if err == nil && len(editors) > 0 {
// 将tags转换为 #tag1 #tag2 格式
@ -332,18 +323,6 @@ func (p *XiaohongshuPublisher) clickPublish() error {
func (p *XiaohongshuPublisher) waitForPublishResult() (bool, string) {
p.LogInfo("等待发布结果...")
for attempt := 0; attempt < 30; attempt++ {
// 检查是否出现失败提示
toastDiv, err := p.WaitForElement(".creator-publish-toast", 2)
if err == nil && toastDiv != nil {
toastText, err := toastDiv.Text()
if err == nil && toastText != "" {
p.LogInfo(fmt.Sprintf("发布失败提示: %s", toastText))
return false, fmt.Sprintf("发布失败: %s", toastText)
}
}
// 检查URL是否包含success
info, err := p.Page.Info()
if err == nil && strings.Contains(info.URL, "success") {
@ -351,6 +330,17 @@ func (p *XiaohongshuPublisher) waitForPublishResult() (bool, string) {
return true, "发布成功"
}
for attempt := 0; attempt < 30; attempt++ {
// 检查是否出现失败提示
exist, toastDiv, err := p.Page.Has(".creator-publish-toast")
if err == nil && exist {
toastText, err := toastDiv.Text()
if err == nil && toastText != "" {
p.LogInfo(fmt.Sprintf("发布失败提示: %s", toastText))
return false, fmt.Sprintf("发布失败: %s", toastText)
}
}
p.SleepMs(1000)
}
@ -427,7 +417,7 @@ func (p *XiaohongshuPublisher) PublishNote() (bool, string) {
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Page.Close()
defer p.Close()
// 执行发布流程
steps := []struct {

View File

@ -175,31 +175,22 @@ func (p *XiaohongshuVideoPublisher) waitForUploadComplete() error {
func (p *XiaohongshuVideoPublisher) inputTitle() error {
p.LogInfo(fmt.Sprintf("输入视频标题: %s", p.Title))
titleSelectors := []string{
"textarea.d-input",
".d-input input",
"input[type='text']",
"textarea",
exist, titleInput, err := p.Page.Has("input[placeholder*='标题']")
if err != nil {
return err
}
if !exist {
return fmt.Errorf("未找到标题输入框")
}
for _, selector := range titleSelectors {
titleInput, err := p.WaitForElementVisible(selector, 5)
if err == nil && titleInput != nil {
p.LogInfo(fmt.Sprintf("找到标题输入框: %s", selector))
p.ClearInput(titleInput)
p.SleepMs(300)
titleInput.Input("")
p.SleepMs(300)
titleInput.Input(p.Title)
p.LogInfo(fmt.Sprintf("标题已输入: %s", p.Title))
p.SleepMs(500)
return nil
}
}
return fmt.Errorf("未找到标题输入框")
}
func (p *XiaohongshuVideoPublisher) inputDescription() error {
p.LogInfo("输入视频描述...")

View File

@ -350,23 +350,16 @@ func (p *ZhihuPublisher) waitForPublishResult(timeout int) (bool, string) {
for time.Since(startTime) < time.Duration(timeout)*time.Second {
currentURL := p.GetCurrentURL()
// 检查失败弹窗
failedDiv, err := p.Page.Element(".Notification-textSection")
if err == nil && failedDiv != nil {
visible, _ := failedDiv.Visible()
if visible {
failedReason, _ := failedDiv.Text()
p.LogInfo(fmt.Sprintf("发布失败: %s", failedReason))
return false, failedReason
}
}
successKeywords := []string{"/p/", "/article/", "/people/", "/column/"}
for _, keyword := range successKeywords {
if strings.Contains(currentURL, keyword) && !strings.Contains(currentURL, "write") {
if !strings.Contains(currentURL, "/edit") {
p.LogInfo(fmt.Sprintf("发布成功URL: %s", currentURL))
return true, "发布成功"
}
// 检查失败弹窗
exist, failedDiv, _ := p.Page.HasX(".Notification-textSection")
if exist {
failedReason, _ := failedDiv.Text()
p.LogInfo(fmt.Sprintf("发布失败: %s", failedReason))
return false, failedReason
}
p.SleepMs(1000)

View File

@ -2,6 +2,7 @@ package service
import (
"fmt"
"os/exec"
"sync"
"testing"
"time"
@ -27,10 +28,14 @@ func TestMultipleChromeProcesses(t *testing.T) {
time.Sleep(10 * time.Minute)
}
func TestKill(t *testing.T) {
exec.Command("taskkill", "/F", "/IM", "chrome.exe").Run()
}
// TestCustomChromeWithMixedHeadless 使用自定义Chrome浏览器启动5个进程偶数有头奇数无头
func TestCustomChromeWithMixedHeadless(t *testing.T) {
// 配置你的Chrome路径
chromePath := "D:\\gop\\geoGo\\chrome\\chrome.exe"
chromePath := "D:\\goProject\\geogo\\chrome\\chrome.exe"
processCount := 5
browsers := make([]*rod.Browser, processCount)
@ -111,7 +116,7 @@ func TestCustomChromeWithMixedHeadless(t *testing.T) {
t.Logf("[进程 %d] 无头模式已访问 example.com不可见", idx)
}
page.MustClose()
//page.MustClose()
}(i)
}
@ -132,7 +137,7 @@ func TestCustomChromeWithMixedHeadless(t *testing.T) {
t.Logf("成功启动 %d/%d 个 Chrome 进程", successCount, processCount)
t.Log("浏览器窗口已打开(有头模式可见),按 Enter 键关闭所有进程...")
fmt.Scanln()
select {}
// 清理
//for i, browser := range browsers {
// if browser != nil {

View File

@ -147,7 +147,7 @@ func (s *PublishService) PublishStatus(c *fiber.Ctx, req *entitys.PublishStatusR
//}
func (s *PublishService) PublishExecuteRetry(c *fiber.Ctx, req *entitys.PublishExecuteRetryRequest) error {
_, err := s.publishBiz.ValidateAccessToken(c.UserContext(), req.AccessToken)
tokenInfo, err := s.publishBiz.ValidateAccessToken(c.UserContext(), req.AccessToken)
if err != nil {
return err
}
@ -156,7 +156,7 @@ func (s *PublishService) PublishExecuteRetry(c *fiber.Ctx, req *entitys.PublishE
if err != nil {
return err
}
result := pm.RetryTask(c.UserContext(), req.RequestID)
result := pm.RetryTask(c.UserContext(), int(tokenInfo.ID), req.RequestID)
return pkg.HandleResponse(c, result)
}

View File

@ -1,485 +0,0 @@
GOROOT=D:\go #gosetup
GOPATH=D:\go #gosetup
D:\go\bin\go.exe build -o C:\Users\Administrator\AppData\Local\JetBrains\GoLand2025.2\tmp\GoLand\___go_build_geo_cmd_server.exe -gcflags "all=-N -l" geo/cmd/server #gosetup
warning: both GOPATH and GOROOT are the same directory (D:\go); see https://go.dev/wiki/InstallTroubleshooting
"D:\GoLand 2025.2.5\plugins\go-plugin\lib\dlv\windows\dlv.exe" --listen=127.0.0.1:62082 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec C:\Users\Administrator\AppData\Local\JetBrains\GoLand2025.2\tmp\GoLand\___go_build_geo_cmd_server.exe -- #gosetup
API server listening at: 127.0.0.1:62082
WARNING: undefined behavior - version of Delve is too old for Go version go1.26.1 (maximum supported version 1.25)
┌───────────────────────────────────────────────────┐
│ Fiber v2.52.12 │
│ http://127.0.0.1:5001 │
│ (bound on host 0.0.0.0 and port 5001) │
│ │
│ Handlers ............ 17 Processes ........... 1 │
│ Prefork ....... Disabled PID ............. 22108 │
└───────────────────────────────────────────────────┘
2026/04/10 16:52:53 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[423.550ms] [rows:1] SELECT * FROM `token` WHERE access_token='6cb55ce2-2556-4908-91b5-5b78f0168cce' AND status=1 LIMIT 1
token
16:52:53 | 200 | 424.6891ms | 127.0.0.1 | POST | /publish_on | -
2026/04/10 16:52:53 自动发布服务已启动tokenID=1worker数量=3
2026/04/10 16:52:53 [Worker-1] 启动tokenID=1
2026/04/10 16:52:53 [Worker-2] 启动tokenID=1
2026/04/10 16:52:53 [Worker-0] 启动tokenID=1
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[412.746ms] [rows:1]
UPDATE publish p
SET p.status = 2,uid='cd76b1df-df01-4a'
WHERE p.request_id = (
SELECT request_id FROM (
SELECT p2.request_id
FROM publish p2
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
WHERE p2.token_id = 1
AND p2.status = 1
AND p2.publish_time <= '2026-04-10 16:52:53'
AND pl.status = 1
ORDER BY p2.publish_time ASC
LIMIT 1
) AS tmp
)
AND p.status = 1
publish
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[418.524ms] [rows:1]
UPDATE publish p
SET p.status = 2,uid='f2a6982a-8bef-4e'
WHERE p.request_id = (
SELECT request_id FROM (
SELECT p2.request_id
FROM publish p2
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
WHERE p2.token_id = 1
AND p2.status = 1
AND p2.publish_time <= '2026-04-10 16:52:53'
AND pl.status = 1
ORDER BY p2.publish_time ASC
LIMIT 1
) AS tmp
)
AND p.status = 1
publish
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[425.694ms] [rows:1]
UPDATE publish p
SET p.status = 2,uid='eba6d8a6-88c3-49'
WHERE p.request_id = (
SELECT request_id FROM (
SELECT p2.request_id
FROM publish p2
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
WHERE p2.token_id = 1
AND p2.status = 1
AND p2.publish_time <= '2026-04-10 16:52:53'
AND pl.status = 1
ORDER BY p2.publish_time ASC
LIMIT 1
) AS tmp
)
AND p.status = 1
publish
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[391.244ms] [rows:1]
SELECT
p.request_id,
p.plat_index,
p.title,
p.tag,
p.user_index,
p.url,
p.img,
p.publish_time,
p.status,
pl.index as plat_index_value,
pl.status as plat_status,
pl.login_url,
pl.edit_url,
pl.logined_url,
pl.desc
FROM publish p
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
WHERE uid='cd76b1df-df01-4a' AND p.token_id = 1
ORDER BY p.publish_time DESC
LIMIT 1
publish
2026/04/10 16:52:54.478724 ================================================================================
2026/04/10 16:52:54.478724 任务开始 | RequestID: 6 | 时间: 2026-04-10 16:52:54.478
2026/04/10 16:52:54.478724 ================================================================================
2026/04/10 16:52:54.478724 [任务 6] 开始处理headless=true
2026/04/10 16:52:54.478724 [任务 6] 任务详情 - 平台zh标题地推看过来用户0d86b848uu2183uu4a08
2026/04/10 16:52:54.478724 [任务 6] 标签解析完成: [#地推 #四川地推 #创业]
2026/04/10 16:52:54.478724 [任务 6] 开始下载文档...
2026/04/10 16:52:54 [Worker-1] 开始处理任务 requestID=6
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[406.859ms] [rows:1]
SELECT
p.request_id,
p.plat_index,
p.title,
p.tag,
p.user_index,
p.url,
p.img,
p.publish_time,
p.status,
pl.index as plat_index_value,
pl.status as plat_status,
pl.login_url,
pl.edit_url,
pl.logined_url,
pl.desc
FROM publish p
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
WHERE uid='f2a6982a-8bef-4e' AND p.token_id = 1
ORDER BY p.publish_time DESC
LIMIT 1
publish
2026/04/10 16:52:54.499312 ================================================================================
2026/04/10 16:52:54.499312 任务开始 | RequestID: 4 | 时间: 2026-04-10 16:52:54.499
2026/04/10 16:52:54.499312 ================================================================================
2026/04/10 16:52:54.499840 [任务 4] 开始处理headless=true
2026/04/10 16:52:54.499840 [任务 4] 任务详情 - 平台xhssp标题萌妹用户0d86b848uu2183uu4a08
2026/04/10 16:52:54.499840 [任务 4] 标签解析完成: [萌妹 宅舞 超性感]
2026/04/10 16:52:54.499840 [任务 4] 开始下载文档...
2026/04/10 16:52:54 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[401.220ms] [rows:1]
SELECT
p.request_id,
p.plat_index,
p.title,
p.tag,
p.user_index,
p.url,
p.img,
p.publish_time,
p.status,
pl.index as plat_index_value,
pl.status as plat_status,
pl.login_url,
pl.edit_url,
pl.logined_url,
pl.desc
FROM publish p
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
WHERE uid='eba6d8a6-88c3-49' AND p.token_id = 1
ORDER BY p.publish_time DESC
LIMIT 1
publish
2026/04/10 16:52:54.501413 ================================================================================
2026/04/10 16:52:54.501413 任务开始 | RequestID: 5 | 时间: 2026-04-10 16:52:54.501
2026/04/10 16:52:54.501413 ================================================================================
2026/04/10 16:52:54.501413 [任务 5] 开始处理headless=true
2026/04/10 16:52:54.501413 [任务 5] 任务详情 - 平台sphsp标题盘点全网最火的meme原型用户0d86b848uu2183uu4a08
2026/04/10 16:52:54.501413 [任务 5] 标签解析完成: [猫 meme 万恶之源]
2026/04/10 16:52:54.501413 [任务 5] 开始下载文档...
2026/04/10 16:52:54 [Worker-2] 开始处理任务 requestID=4
2026/04/10 16:52:54 [Worker-0] 开始处理任务 requestID=5
2026/04/10 16:52:54.568721 [任务 6] ✅ 文档下载成功: D:\gop\geoGo\docs\6.docx
2026/04/10 16:52:54.569769 [任务 6] 开始下载图片...
2026/04/10 16:52:54.629638 [任务 6] ✅ 图片下载成功: D:\gop\geoGo\images\6_1e3dcdb4-0f8a-4b57-aac2-85ecff03ff12.jpg
2026/04/10 16:52:55.723048 [任务 4] ✅ 文档下载成功: D:\gop\geoGo\docs\4.mp4
2026/04/10 16:52:55.723048 [任务 4] 开始下载图片...
2026/04/10 16:52:56.014721 [任务 5] ✅ 文档下载成功: D:\gop\geoGo\docs\5.mp4
2026/04/10 16:52:56.015773 [任务 5] 开始下载图片...
2026/04/10 16:52:56.206874 [任务 5] ✅ 图片下载成功: D:\gop\geoGo\images\5_003e4110-e937-491f-8cf2-92df3de00a8c.png
2026/04/10 16:52:56.206874 [任务 5] 开始执行发布...
2026/04/10 16:52:56.206874 📌 ==================================================
2026/04/10 16:52:56.206874 📌 开始执行sphsp
2026/04/10 16:52:56.206874 📌 标题: 盘点全网最火的meme原型
2026/04/10 16:52:56.206874 📌 标签: [猫 meme 万恶之源]
2026/04/10 16:52:56.206874 📌 ==================================================
2026/04/10 16:52:56.206874 📌 初始化浏览器。。。。
2026/04/10 16:52:56.233002 [任务 4] ✅ 图片下载成功: D:\gop\geoGo\images\4_769c6040-bff9-472b-9b9c-33d8f74cf61f.png
2026/04/10 16:52:56.233002 [任务 4] 开始执行发布...
2026/04/10 16:52:56.233002 📌 ==================================================
2026/04/10 16:52:56.233002 📌 开始执行xhssp
2026/04/10 16:52:56.233002 📌 标题: 萌妹
2026/04/10 16:52:56.233002 📌 标签: [萌妹 宅舞 超性感]
2026/04/10 16:52:56.233002 📌 ==================================================
2026/04/10 16:52:56.233002 📌 初始化浏览器。。。。
2026/04/10 16:52:56.907120 [任务 6] 开始提取文档内容...
2026/04/10 16:52:58.614081 [任务 6] ✅ 内容提取成功,长度: 69
2026/04/10 16:52:58.614081 [任务 6] 开始执行发布...
2026/04/10 16:52:58.614081 📌 ==================================================
2026/04/10 16:52:58.614081 📌 开始执行zh
2026/04/10 16:52:58.614081 📌 标题: 地推看过来!!!
2026/04/10 16:52:58.614081 📌 标签: [#地推 #四川地推 #创业]
2026/04/10 16:52:58.614081 📌 ==================================================
2026/04/10 16:52:58.614081 📌 初始化浏览器。。。。
2026/04/10 16:52:58.616804 ✅ 初始化页面: 成功
2026/04/10 16:52:59.468517 [任务 5] ❌ 发布失败: 需要登录
2026/04/10 16:52:59.617059 📌 开始上传视频: D:\gop\geoGo\docs\4.mp4
2026/04/10 16:52:59.646726 📌 视频文件已选择: D:\gop\geoGo\docs\4.mp4
2026/04/10 16:52:59.646726 📌 等待视频上传完成...
2026/04/10 16:52:59 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[429.171ms] [rows:1] UPDATE publish SET status = 3, msg = '需要登录' WHERE token_id=1 AND request_id = '5'
publish
2026/04/10 16:52:59.897687 ================================================================================
2026/04/10 16:52:59.897687 任务结束 | RequestID: 5 | 结果: false
2026/04/10 16:52:59.898712 [任务 5] 已删除文档文件: D:\gop\geoGo\docs\5.mp4
2026/04/10 16:52:59.899367 [任务 5] 已删除图片文件: D:\gop\geoGo\images\5_003e4110-e937-491f-8cf2-92df3de00a8c.png
2026/04/10 16:52:59 [Worker-0] 任务失败: 需要登录
2026/04/10 16:53:00.050108 📌 发布按钮已可点击,视频上传完成
2026/04/10 16:53:00.050108 ✅ 上传视频: 成功
2026/04/10 16:53:01.050256 📌 输入视频标题: 萌妹
2026/04/10 16:53:01.755888 📌 未登录或登录已过期,需要重新登录
2026/04/10 16:53:01.755888 ❌ 初始化页面: 失败 需要登录
2026/04/10 16:53:01.779792 [任务 6] ❌ 发布失败: 初始化页面失败: 需要登录
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[427.718ms] [rows:1] UPDATE publish SET status = 3, msg = '初始化页面失败: 需要登录' WHERE token_id=1 AND request_id = '6'
publish
2026/04/10 16:53:02.207510 ================================================================================
2026/04/10 16:53:02.207510 任务结束 | RequestID: 6 | 结果: false
2026/04/10 16:53:02.208014 [任务 6] 已删除文档文件: D:\gop\geoGo\docs\6.docx
2026/04/10 16:53:02.208014 [任务 6] 已删除图片文件: D:\gop\geoGo\images\6_1e3dcdb4-0f8a-4b57-aac2-85ecff03ff12.jpg
2026/04/10 16:53:02 [Worker-1] 任务失败: 初始化页面失败: 需要登录
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[406.214ms] [rows:1]
UPDATE publish p
SET p.status = 2,uid='e3a191eb-07d2-48'
WHERE p.request_id = (
SELECT request_id FROM (
SELECT p2.request_id
FROM publish p2
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
WHERE p2.token_id = 1
AND p2.status = 1
AND p2.publish_time <= '2026-04-10 16:53:01'
AND pl.status = 1
ORDER BY p2.publish_time ASC
LIMIT 1
) AS tmp
)
AND p.status = 1
publish
2026/04/10 16:53:02.529767 ❌ 输入标题: 失败 未找到标题输入框
2026/04/10 16:53:02.529767 [任务 4] ❌ 发布失败: 输入标题失败: 未找到标题输入框
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[379.609ms] [rows:1]
SELECT
p.request_id,
p.plat_index,
p.title,
p.tag,
p.user_index,
p.url,
p.img,
p.publish_time,
p.status,
pl.index as plat_index_value,
pl.status as plat_status,
pl.login_url,
pl.edit_url,
pl.logined_url,
pl.desc
FROM publish p
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
WHERE uid='e3a191eb-07d2-48' AND p.token_id = 1
ORDER BY p.publish_time DESC
LIMIT 1
publish
2026/04/10 16:53:02.686657 ================================================================================
2026/04/10 16:53:02.686657 任务开始 | RequestID: 1 | 时间: 2026-04-10 16:53:02.686
2026/04/10 16:53:02.686657 ================================================================================
2026/04/10 16:53:02.686657 [任务 1] 开始处理headless=true
2026/04/10 16:53:02.686657 [任务 1] 任务详情 - 平台xhs标题房地产新格局用户0d86b848uu2183uu4a08
2026/04/10 16:53:02.686657 [任务 1] 标签解析完成: [房地产 房地产格局]
2026/04/10 16:53:02.686657 [任务 1] 开始下载文档...
2026/04/10 16:53:02 [Worker-0] 开始处理任务 requestID=1
2026/04/10 16:53:02.750797 [任务 1] ✅ 文档下载成功: D:\gop\geoGo\docs\1.docx
2026/04/10 16:53:02.750797 [任务 1] 开始下载图片...
2026/04/10 16:53:02 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[445.705ms] [rows:1] UPDATE publish SET status = 3, msg = '输入标题失败: 未找到标题输入框' WHERE token_id=1 AND request_id = '4'
publish
2026/04/10 16:53:02.975473 ================================================================================
2026/04/10 16:53:02.975473 任务结束 | RequestID: 4 | 结果: false
2026/04/10 16:53:02.976009 [任务 4] 已删除文档文件: D:\gop\geoGo\docs\4.mp4
2026/04/10 16:53:02.976539 [任务 4] 已删除图片文件: D:\gop\geoGo\images\4_769c6040-bff9-472b-9b9c-33d8f74cf61f.png
2026/04/10 16:53:02 [Worker-2] 任务失败: 输入标题失败: 未找到标题输入框
2026/04/10 16:53:03.042424 [任务 1] ✅ 图片下载成功: D:\gop\geoGo\images\1_9ffe0dd7-108b-455d-aca4-bf729eba7ab9.png
2026/04/10 16:53:03.042424 [任务 1] 开始提取文档内容...
2026/04/10 16:53:04 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[378.221ms] [rows:1]
UPDATE publish p
SET p.status = 2,uid='5b37ab96-e0de-46'
WHERE p.request_id = (
SELECT request_id FROM (
SELECT p2.request_id
FROM publish p2
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
WHERE p2.token_id = 1
AND p2.status = 1
AND p2.publish_time <= '2026-04-10 16:53:04'
AND pl.status = 1
ORDER BY p2.publish_time ASC
LIMIT 1
) AS tmp
)
AND p.status = 1
publish
2026/04/10 16:53:04.715720 [任务 1] ✅ 内容提取成功,长度: 5372
2026/04/10 16:53:04.715720 [任务 1] 开始执行发布...
2026/04/10 16:53:04.715720 📌 ==================================================
2026/04/10 16:53:04.715720 📌 开始执行xhs
2026/04/10 16:53:04.715720 📌 标题: 房地产新格局
2026/04/10 16:53:04.715720 📌 标签: [房地产 房地产格局]
2026/04/10 16:53:04.715720 📌 ==================================================
2026/04/10 16:53:04.715720 📌 初始化浏览器。。。。
2026/04/10 16:53:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[421.319ms] [rows:1]
SELECT
p.request_id,
p.plat_index,
p.title,
p.tag,
p.user_index,
p.url,
p.img,
p.publish_time,
p.status,
pl.index as plat_index_value,
pl.status as plat_status,
pl.login_url,
pl.edit_url,
pl.logined_url,
pl.desc
FROM publish p
INNER JOIN plat pl ON p.plat_index COLLATE utf8mb4_unicode_ci = pl.index AND pl.status = 1
WHERE uid='5b37ab96-e0de-46' AND p.token_id = 1
ORDER BY p.publish_time DESC
LIMIT 1
publish
2026/04/10 16:53:05.009080 ================================================================================
2026/04/10 16:53:05.009080 任务开始 | RequestID: 2 | 时间: 2026-04-10 16:53:05.009
2026/04/10 16:53:05.009080 ================================================================================
2026/04/10 16:53:05.009080 [任务 2] 开始处理headless=true
2026/04/10 16:53:05.009080 [任务 2] 任务详情 - 平台xhs标题健身与猝死的关系用户0d86b848uu2183uu4a08
2026/04/10 16:53:05.009080 [任务 2] 标签解析完成: [健身 猝死]
2026/04/10 16:53:05.009080 [任务 2] 开始下载文档...
2026/04/10 16:53:05 [Worker-1] 开始处理任务 requestID=2
2026/04/10 16:53:05.067271 [任务 2] ✅ 文档下载成功: D:\gop\geoGo\docs\2.docx
2026/04/10 16:53:05.067271 [任务 2] 开始下载图片...
2026/04/10 16:53:05.309691 [任务 2] ✅ 图片下载成功: D:\gop\geoGo\images\2_ec459546-2873-4539-ae96-4d99c19ec62d.jpg
2026/04/10 16:53:05.309691 [任务 2] 开始提取文档内容...
2026/04/10 16:53:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[401.004ms] [rows:0]
UPDATE publish p
SET p.status = 2,uid='d54d1bab-80a4-4a'
WHERE p.request_id = (
SELECT request_id FROM (
SELECT p2.request_id
FROM publish p2
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
WHERE p2.token_id = 1
AND p2.status = 1
AND p2.publish_time <= '2026-04-10 16:53:04'
AND pl.status = 1
ORDER BY p2.publish_time ASC
LIMIT 1
) AS tmp
)
AND p.status = 1
publish
2026/04/10 16:53:06.894855 [任务 2] ✅ 内容提取成功,长度: 2274
2026/04/10 16:53:06.894855 [任务 2] 开始执行发布...
2026/04/10 16:53:06.894855 📌 ==================================================
2026/04/10 16:53:06.894855 📌 开始执行xhs
2026/04/10 16:53:06.894855 📌 标题: 健身与猝死的关系
2026/04/10 16:53:06.894855 📌 标签: [健身 猝死]
2026/04/10 16:53:06.894855 📌 ==================================================
2026/04/10 16:53:06.894855 📌 初始化浏览器。。。。
2026/04/10 16:53:07.849886 ✅ 初始化: 成功
2026/04/10 16:53:08.352714 ✅ 保存cookie: 成功
2026/04/10 16:53:09.245978 ✅ 初始化: 成功
2026/04/10 16:53:09.748755 ✅ 保存cookie: 成功
2026/04/10 16:53:10.331882 📌 已点击上传按钮
2026/04/10 16:53:11.332203 ✅ 点击上传按钮: 成功
2026/04/10 16:53:11.832762 📌 输入文章内容...
2026/04/10 16:53:12.378724 📌 清空编辑器失败: eval js error: TypeError: Cannot set properties of undefined (setting 'innerText')
at HTMLDivElement.<anonymous> (<anonymous>:1:44)
at HTMLDivElement.<anonymous> (<anonymous>:1:127) <nil>
2026/04/10 16:53:12.748818 📌 内容已输入,长度: 2274
2026/04/10 16:53:12.748818 ✅ 输入内容: 成功
2026/04/10 16:53:13.249362 📌 输入标题...
2026/04/10 16:53:37 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[438.945ms] [rows:0]
UPDATE publish p
SET p.status = 2,uid='49e9bf0f-120a-4c'
WHERE p.request_id = (
SELECT request_id FROM (
SELECT p2.request_id
FROM publish p2
INNER JOIN plat pl ON p2.plat_index COLLATE utf8mb4_unicode_ci = pl.index
WHERE p2.token_id = 1
AND p2.status = 1
AND p2.publish_time <= '2026-04-10 16:53:37'
AND pl.status = 1
ORDER BY p2.publish_time ASC
LIMIT 1
) AS tmp
)
AND p.status = 1
publish
2026/04/10 16:54:02 任务执行超时,[Worker-0] context deadline exceeded requestID=1
2026/04/10 16:54:02.688485 click fail:context deadline exceeded
2026/04/10 16:54:02.688485 ❌ 点击上传按钮: 失败 JS点击按钮失败: context deadline exceeded
2026/04/10 16:54:02.689219 [任务 1] ❌ 发布失败: 点击上传按钮失败: JS点击按钮失败: context deadline exceeded
2026/04/10 16:54:03 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[421.134ms] [rows:1] UPDATE publish SET status = 3, msg = '任务执行超时,[Worker-0] context deadline exceeded requestID=1' WHERE token_id=1 AND request_id = '1'
publish
2026/04/10 16:54:03 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[470.041ms] [rows:1] UPDATE publish SET status = 3, msg = '点击上传按钮失败: JS点击按钮失败: context deadline exceeded' WHERE token_id=1 AND request_id = '1'
publish
2026/04/10 16:54:03.159260 ================================================================================
2026/04/10 16:54:03.159260 任务结束 | RequestID: 1 | 结果: false
2026/04/10 16:54:03.159767 [任务 1] 已删除文档文件: D:\gop\geoGo\docs\1.docx
2026/04/10 16:54:03.160296 [任务 1] 已删除图片文件: D:\gop\geoGo\images\1_9ffe0dd7-108b-455d-aca4-bf729eba7ab9.png
2026/04/10 16:54:05 任务执行超时,[Worker-1] context deadline exceeded requestID=2
2026/04/10 16:54:05.009280 ❌ 输入标题: 失败 未找到标题输入框
2026/04/10 16:54:05.009280 [任务 2] ❌ 发布失败: 输入标题失败: 未找到标题输入框
2026/04/10 16:54:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[403.700ms] [rows:1] UPDATE publish SET status = 3, msg = '任务执行超时,[Worker-1] context deadline exceeded requestID=2' WHERE token_id=1 AND request_id = '2'
publish
2026/04/10 16:54:05 D:/gop/geoGo/utils/utils_gorm/sql_log.go:46 SLOW SQL >= 200ms
[428.723ms] [rows:1] UPDATE publish SET status = 3, msg = '输入标题失败: 未找到标题输入框' WHERE token_id=1 AND request_id = '2'
publish
2026/04/10 16:54:05.438513 ================================================================================
2026/04/10 16:54:05.438513 任务结束 | RequestID: 2 | 结果: false
2026/04/10 16:54:05.439077 [任务 2] 已删除文档文件: D:\gop\geoGo\docs\2.docx
2026/04/10 16:54:05.439641 [任务 2] 已删除图片文件: D:\gop\geoGo\images\2_ec459546-2873-4539-ae96-4d99c19ec62d.jpg