← Back to skills

Domain skill

weread

Markdown synced from browser-harness domain skills.

Host
weread
Files
1

Agent prompt

Use this skill

Copy this prompt into your coding agent to make it enable browser-harness domain skills and read this exact domain folder before automating.

Set up https://github.com/browser-use/browser-harness for me if it is not already installed. If setup is needed, read `install.md` first to install and connect it to my real browser. Then read `SKILL.md` for normal usage and always read `helpers.py` because that is where the browser-harness functions are.

Enable domain skills if they are not already enabled by setting `BH_DOMAIN_SKILLS=1` for browser-harness. Use the `weread` domain skill from `agent-workspace/domain-skills/weread/`. Read every markdown file for this domain before inventing an approach:
- agent-workspace/domain-skills/weread/read.md

Use those domain-skill notes to complete my task for `weread` in my real browser. When you open a setup, verification, or task tab, activate it so I can see the active browser tab.

Skill contents

What the agent will read

Auto Reading

read.md

Source
  • Field-tested against weread.qq.com on 2026-05-06. Requires WeChat login for reading features.
  • ---
  • ---
  • BOOKID — unique book identifier (e.g., ee0320b053b925ee0519857)
Show full markdown

Field-tested against weread.qq.com on 2026-05-06. Requires WeChat login for reading features.


Core Flow

code
Step 1: Check login status
    ├── Not logged in → Prompt user to scan QR code → Wait for login completion
    └── Logged in → Proceed to Step 2

Step 2: Check reading progress
    ├── No progress or finished → Pick first book from New Book ranking → Record status → Proceed to Step 3
    └── Unfinished book → Resume reading → Proceed to Step 3

Step 3: Auto reading (1 minute per session)
    ├── Every 3-5s scroll down 100px
    ├── See "Next Chapter" → Click, continue reading
    ├── See "Book Complete" + "Mark as Finished" → Click mark as finished → Record status as finished
    └── Time's up → Save progress, wait for next session

URL Patterns

PageURL
Homehttps://weread.qq.com/
Risinghttps://weread.qq.com/web/category/rising
Hot Searchhttps://weread.qq.com/web/category/hot_search
New Bookhttps://weread.qq.com/web/category/newbook
Book Detailhttps://weread.qq.com/web/bookDetail/{BOOK_ID}
Readerhttps://weread.qq.com/web/reader/{BOOK_ID}k{CHAPTER_HASH}

Reader URL Pattern

code
https://weread.qq.com/web/reader/{BOOK_ID}k{CHAPTER_HASH}
  • BOOK_ID — unique book identifier (e.g., ee0320b053b925ee0519857)
  • CHAPTER_HASH — chapter hash value (e.g., 08432c902c4084b6fbb18c9)
  • Directly accessing the URL jumps to the specified chapter

Step 1: Login Flow

Login Detection

python
# Check if login is needed
login_needed = js("""
    const loginBtn = document.querySelector('[class*=login], [class*=Login]');
    const qrCode = document.querySelector('[class*=qrcode], [class*=QRCode]');
    return !!(loginBtn || qrCode);
""")

Login Process

  1. Navigate to https://weread.qq.com/
  2. Page shows a QR code login prompt
  3. User scans the QR code with the WeChat mobile app
  4. Page auto-redirects to the home page after successful scan
  5. Login state is persisted — no need to re-login

Wait For Login Completion

python
# Wait for login to complete
import time

def wait_for_login(timeout=120):
    start = time.time()
    while time.time() - start < timeout:
        # Check if still on login page
        on_login = js("""
            const loginBtn = document.querySelector('[class*=login], [class*=Login]');
            return !!loginBtn;
        """)
        if not on_login:
            return True
        time.sleep(2)
    return False

Step 2: Reading Progress Management

progress.json Structure

json
{
  "book": {
    "title": "book title",
    "author": "author",
    "url": "current chapter URL"
  },
  "progress": {
    "status": "reading | finished",
    "currentChapter": "chapter name",
    "completedChapters": ["list of chapters"],
    "lastReadTime": "2026-05-06"
  }
}

Load Progress

python
import json
import os

PROGRESS_FILE = "progress.json"

def load_progress():
    if not os.path.exists(PROGRESS_FILE):
        return None
    with open(PROGRESS_FILE, "r", encoding="utf-8") as f:
        return json.load(f)

Save Progress

python
def save_progress(book_title, author, url, chapter, completed_chapters, status="reading"):
    progress = {
        "book": {
            "title": book_title,
            "author": author,
            "url": url
        },
        "progress": {
            "status": status,
            "currentChapter": chapter,
            "completedChapters": completed_chapters,
            "lastReadTime": time.strftime("%Y-%m-%d")
        }
    }
    with open(PROGRESS_FILE, "w", encoding="utf-8") as f:
        json.dump(progress, f, ensure_ascii=False, indent=2)

Check Reading Status

python
def should_pick_new_book():
    progress = load_progress()
    if progress is None:
        return True  # never read before
    if progress["progress"]["status"] == "finished":
        return True  # already finished
    return False  # has an unfinished book

Pick Book From New Book Ranking

python
def pick_book_from_new_ranking():
    # Navigate to New Book ranking
    new_tab("https://weread.qq.com/web/category/newbook")
    wait_for_load()
    time.sleep(2)

    # Scroll to top
    js("window.scrollTo(0, 0)")
    time.sleep(1)

    # Click the first book
    first_book = js("""
        const allElements = document.querySelectorAll("[class*=title]");
        for (const el of allElements) {
            const text = el.textContent.trim();
            if (text.length > 3 && text.length < 50 && !text.includes("榜")) {
                const rect = el.getBoundingClientRect();
                return {
                    title: text,
                    x: rect.x + rect.width / 2,
                    y: rect.y + rect.height / 2
                };
            }
        }
        return null;
    """)

    if first_book:
        click_at_xy(first_book["x"], first_book["y"])
        wait_for_load()
        time.sleep(1)

    return first_book["title"] if first_book else None

Step 3: Auto Reading

Scroll Reading

python
import random

def scroll_reading(duration=360):
    start_time = time.time()
    chapters_read = []

    while time.time() - start_time < duration:
        # Scroll down 100px
        js("window.scrollBy(0, 100)")

        # Random wait 3-5 seconds
        wait_time = random.uniform(3, 5)
        time.sleep(wait_time)

        # Check if "Next Chapter" button is visible
        next_chapter = find_next_chapter_button()
        if next_chapter and next_chapter["visible"]:
            # Record current chapter
            current = get_current_chapter()
            chapters_read.append(current)
            # Click next chapter
            click_at_xy(next_chapter["x"], next_chapter["y"])
            wait_for_load()
            time.sleep(1)
            continue

        # Check if "Book Complete" and "Mark as Finished"
        finished = check_book_finished()
        if finished:
            click_mark_finished()
            return chapters_read, True  # True = book finished

    return chapters_read, False  # False = time's up, book not finished

Find Next Chapter Button

python
def find_next_chapter_button():
    buttons = js("""
        const items = [];
        const elements = document.querySelectorAll("button, a, [role=button], [class*=next], [class*=Next]");
        elements.forEach(el => {
            const text = el.textContent.trim();
            if (text.includes("下一章")) {
                const rect = el.getBoundingClientRect();
                items.push({
                    text: text,
                    x: rect.x + rect.width/2,
                    y: rect.y + rect.height/2,
                    visible: rect.top < window.innerHeight && rect.bottom > 0
                });
            }
        });
        return items;
    """)
    return buttons[0] if buttons else None

Get Current Chapter

python
def get_current_chapter():
    return js("""
        const title = document.title;
        const parts = title.split(" - ");
        return parts.length > 1 ? parts[1] : "未知章节";
    """)

Check Book Finished

python
def check_book_finished():
    return js("""
        const elements = document.querySelectorAll("[class*=finish], [class*=complete], [class*=end]");
        for (const el of elements) {
            const text = el.textContent.trim();
            if (text.includes("全书完") || text.includes("已读完")) {
                return true;
            }
        }
        return false;
    """)

Click Mark As Finished

python
def click_mark_finished():
    button = js("""
        const elements = document.querySelectorAll("button, [role=button]");
        for (const el of elements) {
            const text = el.textContent.trim();
            if (text.includes("标记读完") || text.includes("标记已读")) {
                const rect = el.getBoundingClientRect();
                return {x: rect.x + rect.width/2, y: rect.y + rect.height/2};
            }
        }
        return null;
    """)
    if button:
        click_at_xy(button["x"], button["y"])
        wait_for_load()
        time.sleep(1)

Gotchas

  • Persistent login — No need to re-login after first scan, unless browser data is cleared.
  • "Next Chapter" button position — The button is at the bottom of the page; scroll it into the viewport before clicking.
  • Scroll interval — 3-5s random interval simulates real reading; scrolling too fast may trigger detection.
  • Chapter URL changes — Each chapter has a unique URL hash; saving the full URL allows precise position restoration.
  • Book finished detection — Some books may lack a "Book Complete" prompt; adjust detection logic as needed.
  • New Book ranking first pick — Ranking order may change; always fetch the first book in real time.