将主题中的帖子标记为“已读”

我尝试通过向“https://{hostUrl}/topics/timings”发送带有 content-typecsrf tokenuser-agent 的 POST 请求来对该网站进行逆向工程。

这是请求体(json)的内容:

payload = {
  "topic_id": topic_id,
  "topic_time": post_count * 60000,
  "timings": timings
}

它返回的状态码是 200,但已读历史记录在 https://{hostUrl}/u/USERNAME/activity/read 处从未改变。

我尝试查看这篇文章,但帮助不大:

以下是大部分代码:

def get_csrf(session):
    r = session.get(f"https://{hostUrl}/session/csrf.json")

    if r.status_code != 200:
        raise RuntimeError("获取 CSRF 失败")

    data = r.json()

    if "csrf" not in data:
        raise RuntimeError("响应中没有 CSRF")

    return data["csrf"]

def load_topics(session, page):
    print(f"[主题] 第 {page} 页")

    r = session.get(
        f"https://{hostUrl}/latest.json?page={page}"
    )

    if r.status_code != 200:
        return []

    data = r.json()

    return [
        {
            "id": t["id"],
            "posts_count": t["posts_count"]
        }
        for t in data["topic_list"]["topics"]
    ]

def mark_post_as_read(session, topic_id, post_count):
    url = f"https://{hostUrl}/topics/timings"

    timings = {
        str(i): 60000
        for i in range(1, post_count + 1)
    }

    payload = {
        "topic_id": topic_id,
        "topic_time": post_count * 60000,
        "timings": timings
    }

    csrf = get_csrf(session)

    r = session.post(
        url,
        json=payload,
        headers={
            "X-CSRF-Token": csrf,
            "User-Agent": "Mozilla/5.0",
            "Content-Type": "application/json"
        }
    )

    print(f"[已读] {topic_id} → {r.status_code}")

    if r.status_code != 200:
        print(r.text[:300])

def tab_worker(session):
    page = 1

    while True:
        topics = load_topics(session, page)

        if not topics:
            break

        for t in topics:
            mark_post_as_read(
                session,
                t["id"],
                t["posts_count"]
            )

            time.sleep(0.4)

        page += 1

我顶一下这个帖子,因为我仍然需要答案。

谢谢

如果以扁平的 "timings[post_number]": [duration_in_ms] 形式发送,可以吗?它能工作吗?

2 个赞

它似乎不能完全奏效。

这是我修改后的代码片段。

def mark_post_as_read(session, topic_id, post_count):
    url = f"https://{hostUrl}/topics/timings"

    payload = {
        "topic_id": topic_id,
        "topic_time": post_count * 60000
    }

    for i in range(1, post_count):
        payload[f"timings[{i}]"] = 60000

    csrf = get_csrf(session)

    r = session.post(
        url,
        json=payload,
        headers={
            "X-CSRF-Token": csrf,
            "User-Agent": "Mozilla/5.0",
            "Content-Type": "application/json"
        }
    )

    print(f"[Read] {topic_id} → {r.status_code}")

    if r.status_code != 200:
        print(r.text[:300])

它仍然返回 200,但没有更新。

谢谢

代码看起来没问题,我不确定问题出在哪里。:confused:
我的直觉告诉我,我们只是在某个地方遗漏了显而易见的东西 :sweat_smile:

This works:

def load_topics(session, page):
    print(f"[Topics] 正在加载第 {page} 页")
    r = session.get(f"https://{hostUrl}/latest.json?page={page}")
    if r.status_code != 200:
        return []
    return [{"id": t["id"], "posts_count": t["posts_count"]} for t in r.json()["topic_list"]["topics"]]
    timings = {
        str(i): 60000
        for i in range(1, post_count + 1)
    }
    payload = {
        "topic_id": topic_id,
        "topic_time": post_count * 60000,
        "timings": timings 
    }    

    # 使用 json=payload 发送 application/json
    r = session.post(url, json=payload, headers = {
        "X-CSRF-Token": csrf,
        "User-Agent": "Mozilla/5.0",
        "X-Requested-With": "XMLHttpRequest",
        "Content-Type": "application/json"
      }
    )
1 个赞

太感谢你了!!!

这终于奏效了。

1 个赞

实际上,还有一件事。

这非常有趣!

  1. 确实会更新帖子阅读历史记录 :white_check_mark:
  2. 已读帖子数会增加 :white_check_mark:

但是:

  1. 主题已读数不会增加 :cross_mark:

我说的就是这两点!

非常有趣。

我不会对这些统计数据是由常规的后台作业出于性能原因而更新感到惊讶。

你用脚本更新时间戳的用例是什么?

我可以百分之百确定这个说法是正确的!
帖子阅读数更新了好几次,但主题阅读数没有。它们的间隔时间不同吗?已经大约 20 小时了,帖子阅读数在增加,但主题阅读数没有增加。

我只是想尝试逆向工程这些端点!这很酷。

我想我应该再等一会儿,然后再回来看看这些值是否发生了变化。

如果你能找出是哪个 job,你可以在 /sidekiq/scheduler 中手动触发 sidekiq job :slight_smile:

也许是 Jobs::DirectoryRefreshDaily

您在用户目录的 /u?period=daily 或每周的视图中是否看到了相同的内容?在那里,您可以看到顶部数字的更新时间。
image

我认为“今天”的数字每小时更新一次,而其他时间段每天只更新一次。

1 个赞

@Canapin,我不是该网站的所有者。如果我仍然可以仅以普通用户身份登录并触发它,请告诉我具体方法。

@Moin
我正在使用的网站禁用了该功能,并且总是返回“此处将显示一个显示其活动的社区成员列表。目前列表为空,因为您的社区还很新!”

在他的情况下,你不能。作为普通用户不利于对 API 进行逆向工程。
如果你可以,尝试本地开发安装或在廉价的 VPS(一个 3-4 美元的服务器就可以了)上进行生产安装,因为 Discourse 不再需要主机名或 SMTP。

1 个赞

嘿,@Canapin,感谢您持续的帮助。

我该如何做到这一点?它目前显示已读 22 个主题已读 260 万条帖子