refactor(comment_feed): streamline comment reply process and enhance error handling
- Removed redundant waiting times and improved the logic for finding comment elements and reply buttons. - Simplified the reply button search by consolidating selectors and enhancing error messages. - Improved the overall readability of the code by removing unnecessary comments and whitespace. - Ensured better handling of potential errors during the comment reply process.
This commit is contained in:
@@ -83,6 +83,7 @@ func (f *CommentFeedAction) PostComment(ctx context.Context, feedID, xsecToken,
|
|||||||
logrus.Infof("Comment posted successfully to feed: %s", feedID)
|
logrus.Infof("Comment posted successfully to feed: %s", feedID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReplyToComment 回复指定评论
|
// ReplyToComment 回复指定评论
|
||||||
func (f *CommentFeedAction) ReplyToComment(ctx context.Context, feedID, xsecToken, commentID, userID, content string) error {
|
func (f *CommentFeedAction) ReplyToComment(ctx context.Context, feedID, xsecToken, commentID, userID, content string) error {
|
||||||
page := f.page.Context(ctx).Timeout(60 * time.Second)
|
page := f.page.Context(ctx).Timeout(60 * time.Second)
|
||||||
@@ -208,20 +209,6 @@ func findCommentElement(page *rod.Page, commentID, userID string) (*rod.Element,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func locateCommentElement(page *rod.Page, commentID, userID string) (*rod.Element, error) {
|
func locateCommentElement(page *rod.Page, commentID, userID string) (*rod.Element, error) {
|
||||||
// 首先在comments-container内查找
|
|
||||||
if commentsContainer, err := page.Element(".comments-container"); err == nil && commentsContainer != nil {
|
|
||||||
if commentID != "" {
|
|
||||||
if el, err := locateCommentElementByCommentIDInContainer(commentsContainer, commentID); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if userID != "" {
|
|
||||||
if el, err := locateCommentElementByUserIDInContainer(commentsContainer, userID); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果在comments-container内没有找到,尝试在整个页面查找
|
// 如果在comments-container内没有找到,尝试在整个页面查找
|
||||||
if commentID != "" {
|
if commentID != "" {
|
||||||
if el, err := locateCommentElementByCommentID(page, commentID); err == nil && el != nil {
|
if el, err := locateCommentElementByCommentID(page, commentID); err == nil && el != nil {
|
||||||
@@ -252,20 +239,6 @@ func locateCommentElementByCommentID(page *rod.Page, commentID string) (*rod.Ele
|
|||||||
return el, nil
|
return el, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试其他data属性
|
|
||||||
selectors := []string{
|
|
||||||
fmt.Sprintf(`[data-comment-id="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[data-comment_id="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[data-commentid="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[data-id="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[comment-id="%s"]`, commentID),
|
|
||||||
}
|
|
||||||
for _, selector := range selectors {
|
|
||||||
if el, err := page.Element(selector); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("未找到评论ID: %s", commentID)
|
return nil, fmt.Errorf("未找到评论ID: %s", commentID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,11 +249,6 @@ func locateCommentElementByUserID(page *rod.Page, userID string) (*rod.Element,
|
|||||||
|
|
||||||
selectors := []string{
|
selectors := []string{
|
||||||
fmt.Sprintf(`[data-user-id="%s"]`, userID),
|
fmt.Sprintf(`[data-user-id="%s"]`, userID),
|
||||||
fmt.Sprintf(`[data-user_id="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`[data-userid="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`[data-uid="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`a[data-user-id="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`a[href*="%s"]`, userID),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, selector := range selectors {
|
for _, selector := range selectors {
|
||||||
@@ -306,66 +274,6 @@ func locateCommentElementByUserID(page *rod.Page, userID string) (*rod.Element,
|
|||||||
return nil, fmt.Errorf("未找到用户ID: %s", userID)
|
return nil, fmt.Errorf("未找到用户ID: %s", userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在指定容器内查找评论元素
|
|
||||||
func locateCommentElementByCommentIDInContainer(container *rod.Element, commentID string) (*rod.Element, error) {
|
|
||||||
if commentID == "" {
|
|
||||||
return nil, fmt.Errorf("评论ID为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 首先尝试直接通过ID查找
|
|
||||||
idSelector := fmt.Sprintf("#comment-%s", commentID)
|
|
||||||
if el, err := container.Element(idSelector); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试其他data属性
|
|
||||||
selectors := []string{
|
|
||||||
fmt.Sprintf(`[data-comment-id="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[data-comment_id="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[data-commentid="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[data-id="%s"]`, commentID),
|
|
||||||
fmt.Sprintf(`[comment-id="%s"]`, commentID),
|
|
||||||
}
|
|
||||||
for _, selector := range selectors {
|
|
||||||
if el, err := container.Element(selector); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("在容器内未找到评论ID: %s", commentID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在指定容器内通过用户ID查找评论元素
|
|
||||||
func locateCommentElementByUserIDInContainer(container *rod.Element, userID string) (*rod.Element, error) {
|
|
||||||
if userID == "" {
|
|
||||||
return nil, fmt.Errorf("用户ID为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
selectors := []string{
|
|
||||||
fmt.Sprintf(`[data-user-id="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`[data-user_id="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`[data-userid="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`[data-uid="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`a[data-user-id="%s"]`, userID),
|
|
||||||
fmt.Sprintf(`a[href*="%s"]`, userID),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, selector := range selectors {
|
|
||||||
if el, err := container.Element(selector); err == nil && el != nil {
|
|
||||||
// 找到用户链接,返回其父级评论元素
|
|
||||||
if parent, err := el.Element(".comment-item"); err == nil && parent != nil {
|
|
||||||
return parent, nil
|
|
||||||
}
|
|
||||||
if parent, err := el.Element(".comment"); err == nil && parent != nil {
|
|
||||||
return parent, nil
|
|
||||||
}
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("在容器内未找到用户ID: %s", userID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待评论容器加载完成
|
// 等待评论容器加载完成
|
||||||
func waitForCommentsContainer(page *rod.Page) {
|
func waitForCommentsContainer(page *rod.Page) {
|
||||||
jsCode := `() => {
|
jsCode := `() => {
|
||||||
@@ -510,41 +418,21 @@ func buildIdentifier(commentID, userID string) string {
|
|||||||
return userID
|
return userID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 选取当前层主的回复按钮
|
||||||
func findReplyButton(commentEl *rod.Element) (*rod.Element, error) {
|
func findReplyButton(commentEl *rod.Element) (*rod.Element, error) {
|
||||||
logrus.Infof("开始查找回复按钮...")
|
if commentEl == nil {
|
||||||
|
return nil, fmt.Errorf("评论元素为空")
|
||||||
// 在right区域内查找interactions
|
|
||||||
right, err := commentEl.Element(".right")
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("未找到.right区域")
|
|
||||||
return nil, fmt.Errorf("未找到.right区域")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interactions, err := right.Element(".interactions")
|
selector := ".right .interactions .reply"
|
||||||
if err != nil {
|
btn, err := commentEl.Element(selector)
|
||||||
logrus.Errorf("未找到.interactions区域")
|
if err != nil || btn == nil {
|
||||||
return nil, fmt.Errorf("未找到.interactions区域")
|
logrus.Warnf("未找到回复按钮,选择器: %s, err: %v", selector, err)
|
||||||
|
return nil, fmt.Errorf("未找到回复按钮")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 选择器列表
|
logrus.Infof("通过选择器 %s 找到回复按钮", selector)
|
||||||
selectors := []string{
|
return btn, nil
|
||||||
".reply", // 回复容器(最通用)
|
|
||||||
":nth-child(2)", // 第二个子元素(单评论)
|
|
||||||
".reply-icon", // 回复图标
|
|
||||||
".reds-icon.reply-icon", // 带类的回复图标
|
|
||||||
".reply.icon-container", // 回复图标容器
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在interactions区域内查找
|
|
||||||
for _, selector := range selectors {
|
|
||||||
if el, err := interactions.Element(selector); err == nil && el != nil {
|
|
||||||
logrus.Infof("通过选择器 %s 找到回复按钮", selector)
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Errorf("未找到回复按钮")
|
|
||||||
return nil, fmt.Errorf("未找到回复按钮")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyClickSuccess 验证点击是否真的成功(检查是否出现了回复输入框)
|
// verifyClickSuccess 验证点击是否真的成功(检查是否出现了回复输入框)
|
||||||
@@ -555,10 +443,6 @@ func verifyClickSuccess(clickedEl *rod.Element) bool {
|
|||||||
// 检查是否出现了回复输入框
|
// 检查是否出现了回复输入框
|
||||||
selectors := []string{
|
selectors := []string{
|
||||||
"div.input-box div.content-edit p.content-input",
|
"div.input-box div.content-edit p.content-input",
|
||||||
"div.input-box [contenteditable='true']",
|
|
||||||
"[contenteditable='true']",
|
|
||||||
"textarea",
|
|
||||||
"input[type='text']",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, selector := range selectors {
|
for _, selector := range selectors {
|
||||||
@@ -570,35 +454,6 @@ func verifyClickSuccess(clickedEl *rod.Element) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用JavaScript检查是否有新的输入框出现
|
|
||||||
jsCode := `() => {
|
|
||||||
// 查找所有可编辑元素
|
|
||||||
const editables = document.querySelectorAll('[contenteditable="true"], textarea, input[type="text"]');
|
|
||||||
for (const el of editables) {
|
|
||||||
// 检查元素是否可见
|
|
||||||
const rect = el.getBoundingClientRect();
|
|
||||||
if (rect.width > 0 && rect.height > 0) {
|
|
||||||
// 检查元素是否在视口中
|
|
||||||
const inViewport = rect.top >= 0 && rect.left >= 0 &&
|
|
||||||
rect.bottom <= window.innerHeight &&
|
|
||||||
rect.right <= window.innerWidth;
|
|
||||||
if (inViewport) {
|
|
||||||
console.log('找到可见的输入元素:', el);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}`
|
|
||||||
|
|
||||||
if result, err := page.Eval(jsCode); err == nil && result != nil {
|
|
||||||
if result.Value.Bool() {
|
|
||||||
logrus.Infof("JavaScript验证成功:找到可见的输入元素")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Infof("验证失败:没有找到回复输入框")
|
logrus.Infof("验证失败:没有找到回复输入框")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -615,29 +470,13 @@ func findReplyInput(page *rod.Page, commentEl *rod.Element) (*rod.Element, error
|
|||||||
return el, nil
|
return el, nil
|
||||||
}
|
}
|
||||||
selectors := []string{
|
selectors := []string{
|
||||||
"div.input-box div.content-edit p.content-input", // 原有选择器
|
"div.input-box div.content-edit p.content-input", // 原有选择器
|
||||||
"div.input-box [contenteditable='true']", // 通用输入框
|
|
||||||
"[contenteditable='true']", // 任何可编辑元素
|
|
||||||
"textarea", // 备用textarea
|
|
||||||
"input[type='text']", // 备用text输入框
|
|
||||||
"[data-role='reply-input'] [contenteditable='true']",
|
|
||||||
}
|
}
|
||||||
for _, selector := range selectors {
|
for _, selector := range selectors {
|
||||||
if el, err := page.Element(selector); err == nil && el != nil {
|
if el, err := page.Element(selector); err == nil && el != nil {
|
||||||
return el, nil
|
return el, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 尝试在评论内部寻找可编辑区域
|
|
||||||
if el, err := commentEl.Element("[contenteditable='true']"); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
// 最后尝试:等待一下再查找,可能是动态加载的
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
for _, selector := range selectors {
|
|
||||||
if el, err := page.Element(selector); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("未找到回复输入框")
|
return nil, fmt.Errorf("未找到回复输入框")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,9 +488,16 @@ func tryClickChainForComment(el *rod.Element) bool {
|
|||||||
|
|
||||||
// 获取元素信息用于调试
|
// 获取元素信息用于调试
|
||||||
text, _ := el.Text()
|
text, _ := el.Text()
|
||||||
class, _ := el.Attribute("class")
|
classAttr, _ := el.Attribute("class")
|
||||||
tag, _ := el.Describe(0, false)
|
class := ""
|
||||||
logrus.Infof("准备点击元素 - 文本: '%s', 类: '%s', 标签: %s", text, class, tag)
|
if classAttr != nil {
|
||||||
|
class = *classAttr
|
||||||
|
}
|
||||||
|
tagName := ""
|
||||||
|
if desc, err := el.Describe(0, false); err == nil && desc != nil {
|
||||||
|
tagName = desc.NodeName
|
||||||
|
}
|
||||||
|
logrus.Infof("准备点击元素 - 文本: '%s', 类: '%s', 标签: %s", text, class, tagName)
|
||||||
|
|
||||||
// 检查元素是否可见和可点击
|
// 检查元素是否可见和可点击
|
||||||
visible, _ := el.Visible()
|
visible, _ := el.Visible()
|
||||||
@@ -701,12 +547,6 @@ func tryClickChainForComment(el *rod.Element) bool {
|
|||||||
func findSubmitButton(page *rod.Page) (*rod.Element, error) {
|
func findSubmitButton(page *rod.Page) (*rod.Element, error) {
|
||||||
selectors := []string{
|
selectors := []string{
|
||||||
"div.bottom button.submit",
|
"div.bottom button.submit",
|
||||||
"button.submit",
|
|
||||||
"button.reds-button",
|
|
||||||
"button[type='submit']",
|
|
||||||
"button:contains('回复')",
|
|
||||||
"button:contains('发布')",
|
|
||||||
"button:contains('发送')",
|
|
||||||
}
|
}
|
||||||
for _, selector := range selectors {
|
for _, selector := range selectors {
|
||||||
if el, err := page.Element(selector); err == nil && el != nil {
|
if el, err := page.Element(selector); err == nil && el != nil {
|
||||||
@@ -716,22 +556,5 @@ func findSubmitButton(page *rod.Page) (*rod.Element, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 使用JS查找包含特定文本的按钮
|
|
||||||
jsCode := `() => {
|
|
||||||
const buttons = document.querySelectorAll('button');
|
|
||||||
for (const btn of buttons) {
|
|
||||||
const text = btn.textContent || btn.innerText || '';
|
|
||||||
if (text.includes('回复') || text.includes('发布') || text.includes('发送')) {
|
|
||||||
const disabled = btn.getAttribute('disabled');
|
|
||||||
if (!disabled) {
|
|
||||||
return btn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}`
|
|
||||||
if el, err := page.ElementByJS(rod.Eval(jsCode)); err == nil && el != nil {
|
|
||||||
return el, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("未找到回复发布按钮")
|
return nil, fmt.Errorf("未找到回复发布按钮")
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user