reddit-api by alinaqi/claude-bootstrap
npx skills add https://github.com/alinaqi/claude-bootstrap --skill reddit-api加载方式:base.md + [language].md
用于将 Reddit 数据集成到应用程序中 - 获取帖子、评论、子版块和用户数据。
资料来源: Reddit API 文档 | OAuth2 Wiki | PRAW 文档
script - 用于个人使用/你控制的机器人web app - 用于需要用户认证的服务器端应用installed app - 用于移动/桌面应用http://localhost:8000/callback (用于开发)广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
client_id (应用名称下方) 和 client_secret# .env
REDDIT_CLIENT_ID=your_client_id
REDDIT_CLIENT_SECRET=your_client_secret
REDDIT_USER_AGENT=YourApp/1.0 by YourUsername
REDDIT_USERNAME=your_username # 仅适用于脚本应用
REDDIT_PASSWORD=your_password # 仅适用于脚本应用
User-Agent 格式 : <platform>:<app_id>:<version> (by /u/<username>)
| 层级 | 限制 | 说明 |
|---|---|---|
| OAuth 认证 | 100 QPM | 每个 OAuth client ID |
| 非认证 | 被阻止 | 必须使用 OAuth |
User-Agent 请求头以避免被阻止X-Ratelimit-* 响应头pip install praw
# 或
uv add praw
import praw
from pydantic_settings import BaseSettings
class RedditSettings(BaseSettings):
reddit_client_id: str
reddit_client_secret: str
reddit_user_agent: str
reddit_username: str
reddit_password: str
class Config:
env_file = ".env"
settings = RedditSettings()
reddit = praw.Reddit(
client_id=settings.reddit_client_id,
client_secret=settings.reddit_client_secret,
user_agent=settings.reddit_user_agent,
username=settings.reddit_username,
password=settings.reddit_password,
)
# 验证认证
print(f"Logged in as: {reddit.user.me()}")
import praw
reddit = praw.Reddit(
client_id="your_client_id",
client_secret="your_client_secret",
user_agent="YourApp/1.0 by YourUsername",
)
# 只读模式 - 可以浏览,不能发帖/投票
reddit.read_only = True
# 获取子版块帖子
subreddit = reddit.subreddit("python")
# 热门帖子
for post in subreddit.hot(limit=10):
print(f"{post.title} - {post.score} upvotes")
# 最新帖子
for post in subreddit.new(limit=10):
print(post.title)
# 搜索帖子
for post in subreddit.search("pydantic", limit=5):
print(post.title)
# 获取特定帖子
submission = reddit.submission(id="abc123")
print(submission.title)
print(submission.selftext)
# 获取评论
submission.comments.replace_more(limit=0) # 展平评论树
for comment in submission.comments.list():
print(f"{comment.author}: {comment.body[:100]}")
# 提交文本帖子
subreddit = reddit.subreddit("test")
submission = subreddit.submit(
title="Test Post",
selftext="This is the body of my post."
)
# 提交链接帖子
submission = subreddit.submit(
title="Check this out",
url="https://example.com"
)
# 投票
submission.upvote()
submission.downvote()
submission.clear_vote()
# 评论
submission.reply("Great post!")
# 回复评论
comment = reddit.comment(id="xyz789")
comment.reply("I agree!")
# 流式获取新帖子
for post in reddit.subreddit("python").stream.submissions():
print(f"New post: {post.title}")
# 处理帖子...
# 流式获取新评论
for comment in reddit.subreddit("python").stream.comments():
print(f"New comment by {comment.author}: {comment.body[:50]}")
# 获取用户信息
user = reddit.redditor("spez")
print(f"Karma: {user.link_karma + user.comment_karma}")
# 用户的帖子
for post in user.submissions.new(limit=5):
print(post.title)
# 用户的评论
for comment in user.comments.new(limit=5):
print(comment.body[:100])
npm install snoowrap
# 或
pnpm add snoowrap
import Snoowrap from "snoowrap";
const reddit = new Snoowrap({
userAgent: "YourApp/1.0 by YourUsername",
clientId: process.env.REDDIT_CLIENT_ID!,
clientSecret: process.env.REDDIT_CLIENT_SECRET!,
username: process.env.REDDIT_USERNAME!,
password: process.env.REDDIT_PASSWORD!,
});
// 配置速率限制
reddit.config({
requestDelay: 1000, // 请求间隔 1 秒
continueAfterRatelimitError: true,
});
// 从子版块获取热门帖子
const posts = await reddit.getSubreddit("typescript").getHot({ limit: 10 });
posts.forEach((post) => {
console.log(`${post.title} - ${post.score} upvotes`);
});
// 搜索帖子
const results = await reddit.getSubreddit("programming").search({
query: "typescript",
sort: "relevance",
time: "month",
limit: 10,
});
// 获取特定帖子
const submission = await reddit.getSubmission("abc123").fetch();
console.log(submission.title);
// 获取评论
const comments = await submission.comments.fetchAll();
comments.forEach((comment) => {
console.log(`${comment.author.name}: ${comment.body.slice(0, 100)}`);
});
// 提交文本帖子
const post = await reddit.getSubreddit("test").submitSelfpost({
title: "Test Post",
text: "This is the body.",
});
// 提交链接
const linkPost = await reddit.getSubreddit("test").submitLink({
title: "Check this out",
url: "https://example.com",
});
// 投票和评论
await post.upvote();
await post.reply("Great post!");
import httpx
import base64
from pydantic import BaseModel
class RedditClient:
def __init__(self, client_id: str, client_secret: str, user_agent: str):
self.client_id = client_id
self.client_secret = client_secret
self.user_agent = user_agent
self.access_token: str | None = None
self.client = httpx.AsyncClient()
async def authenticate(self) -> None:
"""获取仅应用 OAuth 令牌。"""
auth = base64.b64encode(
f"{self.client_id}:{self.client_secret}".encode()
).decode()
response = await self.client.post(
"https://www.reddit.com/api/v1/access_token",
headers={
"Authorization": f"Basic {auth}",
"User-Agent": self.user_agent,
},
data={
"grant_type": "client_credentials",
},
)
response.raise_for_status()
self.access_token = response.json()["access_token"]
async def get_posts(self, subreddit: str, sort: str = "hot", limit: int = 10) -> list[dict]:
"""从子版块获取帖子。"""
if not self.access_token:
await self.authenticate()
response = await self.client.get(
f"https://oauth.reddit.com/r/{subreddit}/{sort}",
headers={
"Authorization": f"Bearer {self.access_token}",
"User-Agent": self.user_agent,
},
params={"limit": limit},
)
response.raise_for_status()
return [post["data"] for post in response.json()["data"]["children"]]
async def close(self) -> None:
await self.client.aclose()
# 使用示例
async def main():
client = RedditClient(
client_id="your_id",
client_secret="your_secret",
user_agent="YourApp/1.0",
)
try:
posts = await client.get_posts("python", limit=5)
for post in posts:
print(f"{post['title']} - {post['score']} upvotes")
finally:
await client.close()
interface RedditPost {
title: string;
score: number;
url: string;
selftext: string;
author: string;
created_utc: number;
}
class RedditClient {
private accessToken: string | null = null;
constructor(
private clientId: string,
private clientSecret: string,
private userAgent: string
) {}
async authenticate(): Promise<void> {
const auth = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString("base64");
const response = await fetch("https://www.reddit.com/api/v1/access_token", {
method: "POST",
headers: {
Authorization: `Basic ${auth}`,
"User-Agent": this.userAgent,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
});
const data = await response.json();
this.accessToken = data.access_token;
}
async getPosts(subreddit: string, sort = "hot", limit = 10): Promise<RedditPost[]> {
if (!this.accessToken) await this.authenticate();
const response = await fetch(
`https://oauth.reddit.com/r/${subreddit}/${sort}?limit=${limit}`,
{
headers: {
Authorization: `Bearer ${this.accessToken}`,
"User-Agent": this.userAgent,
},
}
);
const data = await response.json();
return data.data.children.map((child: any) => child.data);
}
}
适用于用户使用其 Reddit 账户登录的应用:
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
import httpx
import secrets
app = FastAPI()
state_store: dict[str, bool] = {}
REDDIT_CLIENT_ID = "your_client_id"
REDDIT_CLIENT_SECRET = "your_client_secret"
REDIRECT_URI = "http://localhost:8000/callback"
@app.get("/login")
async def login():
state = secrets.token_urlsafe(16)
state_store[state] = True
auth_url = (
f"https://www.reddit.com/api/v1/authorize"
f"?client_id={REDDIT_CLIENT_ID}"
f"&response_type=code"
f"&state={state}"
f"&redirect_uri={REDIRECT_URI}"
f"&duration=permanent"
f"&scope=identity read submit vote"
)
return RedirectResponse(auth_url)
@app.get("/callback")
async def callback(code: str, state: str):
if state not in state_store:
return {"error": "Invalid state"}
del state_store[state]
# 用 code 交换令牌
async with httpx.AsyncClient() as client:
response = await client.post(
"https://www.reddit.com/api/v1/access_token",
auth=(REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET),
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
},
headers={"User-Agent": "YourApp/1.0"},
)
tokens = response.json()
# 安全存储令牌,与用户会话关联
return {"access_token": tokens["access_token"][:10] + "..."}
| 范围 | 描述 |
|---|---|
identity | 访问用户名和注册日期 |
read | 访问帖子和评论 |
submit | 提交链接和评论 |
vote | 对内容进行赞成/反对投票 |
edit | 编辑帖子和评论 |
history | 访问投票历史 |
subscribe | 管理子版块订阅 |
mysubreddits | 访问已订阅的子版块 |
privatemessages | 访问私信 |
save | 保存/取消保存内容 |
project/
├── src/
│ ├── reddit/
│ │ ├── __init__.py
│ │ ├── client.py # Reddit 客户端包装器
│ │ ├── models.py # 帖子/评论的 Pydantic 模型
│ │ └── scraper.py # 数据收集逻辑
│ └── main.py
├── .env
└── pyproject.toml
from pydantic import BaseModel
from datetime import datetime
class RedditPost(BaseModel):
id: str
title: str
author: str
subreddit: str
score: int
upvote_ratio: float
url: str
selftext: str
created_utc: datetime
num_comments: int
is_self: bool
@classmethod
def from_praw(cls, submission) -> "RedditPost":
return cls(
id=submission.id,
title=submission.title,
author=str(submission.author),
subreddit=submission.subreddit.display_name,
score=submission.score,
upvote_ratio=submission.upvote_ratio,
url=submission.url,
selftext=submission.selftext,
created_utc=datetime.fromtimestamp(submission.created_utc),
num_comments=submission.num_comments,
is_self=submission.is_self,
)
class RedditComment(BaseModel):
id: str
author: str
body: str
score: int
created_utc: datetime
parent_id: str
is_submitter: bool
X-Ratelimit-* 响应头MoreComments - 在 PRAW 中使用 replace_more().stream 获取实时数据# PRAW 安装
pip install praw
# Snoowrap 安装
npm install snoowrap
# 测试认证
python -c "import praw; r = praw.Reddit(...); print(r.user.me())"
| 操作 | 端点 |
|---|---|
| 认证令牌 | POST https://www.reddit.com/api/v1/access_token |
| API 请求 | https://oauth.reddit.com/... |
| 子版块帖子 | GET /r/{subreddit}/{sort} |
| 提交内容 | GET /comments/{id} |
| 用户信息 | GET /user/{username}/about |
| 提交帖子 | POST /api/submit |
| 投票 | POST /api/vote |
每周安装次数
111
代码仓库
GitHub 星标数
538
首次出现
2026年1月20日
安全审计
安装于
opencode94
gemini-cli92
codex88
cursor83
claude-code83
github-copilot78
Load with: base.md + [language].md
For integrating Reddit data into applications - fetching posts, comments, subreddits, and user data.
Sources: Reddit API Docs | OAuth2 Wiki | PRAW Docs
script - For personal use / bots you controlweb app - For server-side apps with user authinstalled app - For mobile/desktop appshttp://localhost:8000/callback (for dev)client_id (under app name) and client_secret# .env
REDDIT_CLIENT_ID=your_client_id
REDDIT_CLIENT_SECRET=your_client_secret
REDDIT_USER_AGENT=YourApp/1.0 by YourUsername
REDDIT_USERNAME=your_username # For script apps only
REDDIT_PASSWORD=your_password # For script apps only
User-Agent Format : <platform>:<app_id>:<version> (by /u/<username>)
| Tier | Limit | Notes |
|---|---|---|
| OAuth authenticated | 100 QPM | Per OAuth client ID |
| Non-authenticated | Blocked | Must use OAuth |
User-Agent header to avoid blocksX-Ratelimit-* response headerspip install praw
# or
uv add praw
import praw
from pydantic_settings import BaseSettings
class RedditSettings(BaseSettings):
reddit_client_id: str
reddit_client_secret: str
reddit_user_agent: str
reddit_username: str
reddit_password: str
class Config:
env_file = ".env"
settings = RedditSettings()
reddit = praw.Reddit(
client_id=settings.reddit_client_id,
client_secret=settings.reddit_client_secret,
user_agent=settings.reddit_user_agent,
username=settings.reddit_username,
password=settings.reddit_password,
)
# Verify authentication
print(f"Logged in as: {reddit.user.me()}")
import praw
reddit = praw.Reddit(
client_id="your_client_id",
client_secret="your_client_secret",
user_agent="YourApp/1.0 by YourUsername",
)
# Read-only mode - can browse, can't post/vote
reddit.read_only = True
# Get subreddit posts
subreddit = reddit.subreddit("python")
# Hot posts
for post in subreddit.hot(limit=10):
print(f"{post.title} - {post.score} upvotes")
# New posts
for post in subreddit.new(limit=10):
print(post.title)
# Search posts
for post in subreddit.search("pydantic", limit=5):
print(post.title)
# Get specific post
submission = reddit.submission(id="abc123")
print(submission.title)
print(submission.selftext)
# Get comments
submission.comments.replace_more(limit=0) # Flatten comment tree
for comment in submission.comments.list():
print(f"{comment.author}: {comment.body[:100]}")
# Submit text post
subreddit = reddit.subreddit("test")
submission = subreddit.submit(
title="Test Post",
selftext="This is the body of my post."
)
# Submit link post
submission = subreddit.submit(
title="Check this out",
url="https://example.com"
)
# Vote
submission.upvote()
submission.downvote()
submission.clear_vote()
# Comment
submission.reply("Great post!")
# Reply to comment
comment = reddit.comment(id="xyz789")
comment.reply("I agree!")
# Stream new posts
for post in reddit.subreddit("python").stream.submissions():
print(f"New post: {post.title}")
# Process post...
# Stream new comments
for comment in reddit.subreddit("python").stream.comments():
print(f"New comment by {comment.author}: {comment.body[:50]}")
# Get user info
user = reddit.redditor("spez")
print(f"Karma: {user.link_karma + user.comment_karma}")
# User's posts
for post in user.submissions.new(limit=5):
print(post.title)
# User's comments
for comment in user.comments.new(limit=5):
print(comment.body[:100])
npm install snoowrap
# or
pnpm add snoowrap
import Snoowrap from "snoowrap";
const reddit = new Snoowrap({
userAgent: "YourApp/1.0 by YourUsername",
clientId: process.env.REDDIT_CLIENT_ID!,
clientSecret: process.env.REDDIT_CLIENT_SECRET!,
username: process.env.REDDIT_USERNAME!,
password: process.env.REDDIT_PASSWORD!,
});
// Configure rate limiting
reddit.config({
requestDelay: 1000, // 1 second between requests
continueAfterRatelimitError: true,
});
// Get hot posts from subreddit
const posts = await reddit.getSubreddit("typescript").getHot({ limit: 10 });
posts.forEach((post) => {
console.log(`${post.title} - ${post.score} upvotes`);
});
// Search posts
const results = await reddit.getSubreddit("programming").search({
query: "typescript",
sort: "relevance",
time: "month",
limit: 10,
});
// Get specific post
const submission = await reddit.getSubmission("abc123").fetch();
console.log(submission.title);
// Get comments
const comments = await submission.comments.fetchAll();
comments.forEach((comment) => {
console.log(`${comment.author.name}: ${comment.body.slice(0, 100)}`);
});
// Submit text post
const post = await reddit.getSubreddit("test").submitSelfpost({
title: "Test Post",
text: "This is the body.",
});
// Submit link
const linkPost = await reddit.getSubreddit("test").submitLink({
title: "Check this out",
url: "https://example.com",
});
// Vote and comment
await post.upvote();
await post.reply("Great post!");
import httpx
import base64
from pydantic import BaseModel
class RedditClient:
def __init__(self, client_id: str, client_secret: str, user_agent: str):
self.client_id = client_id
self.client_secret = client_secret
self.user_agent = user_agent
self.access_token: str | None = None
self.client = httpx.AsyncClient()
async def authenticate(self) -> None:
"""Get application-only OAuth token."""
auth = base64.b64encode(
f"{self.client_id}:{self.client_secret}".encode()
).decode()
response = await self.client.post(
"https://www.reddit.com/api/v1/access_token",
headers={
"Authorization": f"Basic {auth}",
"User-Agent": self.user_agent,
},
data={
"grant_type": "client_credentials",
},
)
response.raise_for_status()
self.access_token = response.json()["access_token"]
async def get_posts(self, subreddit: str, sort: str = "hot", limit: int = 10) -> list[dict]:
"""Get posts from a subreddit."""
if not self.access_token:
await self.authenticate()
response = await self.client.get(
f"https://oauth.reddit.com/r/{subreddit}/{sort}",
headers={
"Authorization": f"Bearer {self.access_token}",
"User-Agent": self.user_agent,
},
params={"limit": limit},
)
response.raise_for_status()
return [post["data"] for post in response.json()["data"]["children"]]
async def close(self) -> None:
await self.client.aclose()
# Usage
async def main():
client = RedditClient(
client_id="your_id",
client_secret="your_secret",
user_agent="YourApp/1.0",
)
try:
posts = await client.get_posts("python", limit=5)
for post in posts:
print(f"{post['title']} - {post['score']} upvotes")
finally:
await client.close()
interface RedditPost {
title: string;
score: number;
url: string;
selftext: string;
author: string;
created_utc: number;
}
class RedditClient {
private accessToken: string | null = null;
constructor(
private clientId: string,
private clientSecret: string,
private userAgent: string
) {}
async authenticate(): Promise<void> {
const auth = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString("base64");
const response = await fetch("https://www.reddit.com/api/v1/access_token", {
method: "POST",
headers: {
Authorization: `Basic ${auth}`,
"User-Agent": this.userAgent,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
});
const data = await response.json();
this.accessToken = data.access_token;
}
async getPosts(subreddit: string, sort = "hot", limit = 10): Promise<RedditPost[]> {
if (!this.accessToken) await this.authenticate();
const response = await fetch(
`https://oauth.reddit.com/r/${subreddit}/${sort}?limit=${limit}`,
{
headers: {
Authorization: `Bearer ${this.accessToken}`,
"User-Agent": this.userAgent,
},
}
);
const data = await response.json();
return data.data.children.map((child: any) => child.data);
}
}
For apps where users log in with their Reddit account:
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
import httpx
import secrets
app = FastAPI()
state_store: dict[str, bool] = {}
REDDIT_CLIENT_ID = "your_client_id"
REDDIT_CLIENT_SECRET = "your_client_secret"
REDIRECT_URI = "http://localhost:8000/callback"
@app.get("/login")
async def login():
state = secrets.token_urlsafe(16)
state_store[state] = True
auth_url = (
f"https://www.reddit.com/api/v1/authorize"
f"?client_id={REDDIT_CLIENT_ID}"
f"&response_type=code"
f"&state={state}"
f"&redirect_uri={REDIRECT_URI}"
f"&duration=permanent"
f"&scope=identity read submit vote"
)
return RedirectResponse(auth_url)
@app.get("/callback")
async def callback(code: str, state: str):
if state not in state_store:
return {"error": "Invalid state"}
del state_store[state]
# Exchange code for token
async with httpx.AsyncClient() as client:
response = await client.post(
"https://www.reddit.com/api/v1/access_token",
auth=(REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET),
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
},
headers={"User-Agent": "YourApp/1.0"},
)
tokens = response.json()
# Store tokens securely, associate with user session
return {"access_token": tokens["access_token"][:10] + "..."}
| Scope | Description |
|---|---|
identity | Access username and signup date |
read | Access posts and comments |
submit | Submit links and comments |
vote | Upvote/downvote content |
edit | Edit posts and comments |
history | Access voting history |
Full list: https://www.reddit.com/api/v1/scopes
project/
├── src/
│ ├── reddit/
│ │ ├── __init__.py
│ │ ├── client.py # Reddit client wrapper
│ │ ├── models.py # Pydantic models for posts/comments
│ │ └── scraper.py # Data collection logic
│ └── main.py
├── .env
└── pyproject.toml
from pydantic import BaseModel
from datetime import datetime
class RedditPost(BaseModel):
id: str
title: str
author: str
subreddit: str
score: int
upvote_ratio: float
url: str
selftext: str
created_utc: datetime
num_comments: int
is_self: bool
@classmethod
def from_praw(cls, submission) -> "RedditPost":
return cls(
id=submission.id,
title=submission.title,
author=str(submission.author),
subreddit=submission.subreddit.display_name,
score=submission.score,
upvote_ratio=submission.upvote_ratio,
url=submission.url,
selftext=submission.selftext,
created_utc=datetime.fromtimestamp(submission.created_utc),
num_comments=submission.num_comments,
is_self=submission.is_self,
)
class RedditComment(BaseModel):
id: str
author: str
body: str
score: int
created_utc: datetime
parent_id: str
is_submitter: bool
X-Ratelimit-* headersMoreComments - Use replace_more() in PRAW.stream for real-time data# PRAW installation
pip install praw
# Snoowrap installation
npm install snoowrap
# Test authentication
python -c "import praw; r = praw.Reddit(...); print(r.user.me())"
| Operation | Endpoint |
|---|---|
| Auth token | POST https://www.reddit.com/api/v1/access_token |
| API requests | https://oauth.reddit.com/... |
| Subreddit posts | GET /r/{subreddit}/{sort} |
| Submission | GET /comments/{id} |
| User info | GET /user/{username}/about |
| Submit post | POST /api/submit |
Weekly Installs
111
Repository
GitHub Stars
538
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykWarn
Installed on
opencode94
gemini-cli92
codex88
cursor83
claude-code83
github-copilot78
Lark CLI IM 即时消息管理工具:机器人/用户身份操作聊天、消息、文件下载
31,500 周安装
subscribe| Manage subreddit subscriptions |
mysubreddits | Access subscribed subreddits |
privatemessages | Access private messages |
save | Save/unsave content |
| Vote | POST /api/vote |