Les discussions sur Reddit contiennent des opinions non filtrées sur les produits, marques et industries que les sondages et sites d'avis ne captent pas. Suivre manuellement le sentiment dans les subreddits est irréaliste : les fils avancent vite et couvrent des centaines de communautés. Ce tutoriel construit un agent Python qui utilise l'API Scavio pour rechercher des publications liées à une marque sur Reddit, applique un classificateur de sentiment simple basé sur des mots-clés, et agrège les résultats en un rapport quotidien avec un score de sentiment global, les fils les plus positifs, les fils les plus négatifs et les préoccupations tendances. L'approche n'utilise pas de modèles de ML, juste un score pondéré par mots-clés basé sur des regex qui s'exécute instantanément et ne coûte rien au-delà des appels API.
Prérequis
- Python 3.8 ou version ultérieure installé
- Bibliothèque requests installée
- Une clé API Scavio depuis scavio.dev
- Mots-clés de marque ou noms de produits à suivre
Parcours
Étape 1: Définir les mots-clés de marque et le lexique de sentiment
Configurez les termes de marque à rechercher et un lexique simple de mots-clés pondérés pour la classification de sentiment. Les mots positifs et négatifs portent chacun un score.
BRAND_QUERIES = [
"scavio api",
"scavio search",
"scavio mcp"
]
POSITIVE_WORDS = ["love", "great", "fast", "reliable", "cheap", "easy", "best", "solid", "recommend", "impressed"]
NEGATIVE_WORDS = ["slow", "expensive", "broken", "hate", "worst", "terrible", "buggy", "unreliable", "scam", "overpriced"]Étape 2: Récupérer les publications Reddit via l'API Scavio
Recherchez Reddit via le endpoint Scavio en utilisant le paramètre platform. Collectez le titre, l'extrait, le lien et le subreddit pour chaque résultat.
import os
import requests
API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
def search_reddit(query: str) -> list[dict]:
r = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"query": query, "platform": "reddit"}
)
r.raise_for_status()
return r.json().get("organic_results", [])Étape 3: Évaluer le sentiment de chaque publication
Appliquez le lexique de mots-clés à chaque titre et extrait de publication. Additionnez les hits positifs et négatifs pour produire un score net de sentiment par publication.
def score_sentiment(text: str) -> dict:
text_lower = text.lower()
pos = sum(1 for w in POSITIVE_WORDS if w in text_lower)
neg = sum(1 for w in NEGATIVE_WORDS if w in text_lower)
net = pos - neg
if net > 0:
label = "positive"
elif net < 0:
label = "negative"
else:
label = "neutral"
return {"positive": pos, "negative": neg, "net": net, "label": label}
def analyze_post(post: dict) -> dict:
text = f"{post.get('title', '')} {post.get('snippet', '')}"
sentiment = score_sentiment(text)
return {
"title": post.get("title", ""),
"link": post.get("link", ""),
"subreddit": post.get("source", ""),
"sentiment": sentiment
}Étape 4: Générer le rapport quotidien de sentiment
Agrégez le sentiment sur toutes les publications, identifiez les fils les plus positifs et négatifs, et rédigez un rapport récapitulatif.
import json
from datetime import date
def generate_report(brand_queries: list[str]) -> dict:
all_posts = []
for query in brand_queries:
results = search_reddit(query)
analyzed = [analyze_post(p) for p in results]
all_posts.extend(analyzed)
total = len(all_posts)
positive = [p for p in all_posts if p["sentiment"]["label"] == "positive"]
negative = [p for p in all_posts if p["sentiment"]["label"] == "negative"]
neutral = [p for p in all_posts if p["sentiment"]["label"] == "neutral"]
report = {
"date": str(date.today()),
"total_posts": total,
"positive": len(positive),
"negative": len(negative),
"neutral": len(neutral),
"sentiment_ratio": round(len(positive) / total, 2) if total else 0,
"top_positive": sorted(positive, key=lambda p: p["sentiment"]["net"], reverse=True)[:3],
"top_negative": sorted(negative, key=lambda p: p["sentiment"]["net"])[:3]
}
with open(f"reddit_sentiment_{report['date']}.json", "w") as f:
json.dump(report, f, indent=2)
print(f"Report: {total} posts, {len(positive)} positive, {len(negative)} negative")
return report
generate_report(BRAND_QUERIES)Exemple Python
import os
import json
import requests
from datetime import date
API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
ENDPOINT = "https://api.scavio.dev/api/v1/search"
POSITIVE = ["love", "great", "fast", "reliable", "cheap", "easy", "best", "solid", "recommend", "impressed"]
NEGATIVE = ["slow", "expensive", "broken", "hate", "worst", "terrible", "buggy", "unreliable", "scam", "overpriced"]
def search_reddit(query: str) -> list[dict]:
r = requests.post(
ENDPOINT,
headers={"x-api-key": API_KEY},
json={"query": query, "platform": "reddit"}
)
r.raise_for_status()
return r.json().get("organic_results", [])
def score(text: str) -> dict:
t = text.lower()
pos = sum(1 for w in POSITIVE if w in t)
neg = sum(1 for w in NEGATIVE if w in t)
net = pos - neg
label = "positive" if net > 0 else "negative" if net < 0 else "neutral"
return {"pos": pos, "neg": neg, "net": net, "label": label}
def track_sentiment(queries: list[str]) -> dict:
posts = []
for q in queries:
for result in search_reddit(q):
text = f"{result.get('title', '')} {result.get('snippet', '')}"
posts.append({
"title": result.get("title", ""),
"link": result.get("link", ""),
"sentiment": score(text)
})
total = len(posts)
pos_count = sum(1 for p in posts if p["sentiment"]["label"] == "positive")
neg_count = sum(1 for p in posts if p["sentiment"]["label"] == "negative")
report = {
"date": str(date.today()),
"total": total,
"positive": pos_count,
"negative": neg_count,
"neutral": total - pos_count - neg_count,
"ratio": round(pos_count / total, 2) if total else 0,
"top_positive": sorted([p for p in posts if p["sentiment"]["label"] == "positive"],
key=lambda x: x["sentiment"]["net"], reverse=True)[:3],
"top_negative": sorted([p for p in posts if p["sentiment"]["label"] == "negative"],
key=lambda x: x["sentiment"]["net"])[:3]
}
output = f"reddit_sentiment_{report['date']}.json"
with open(output, "w") as f:
json.dump(report, f, indent=2)
print(f"{total} posts: {pos_count} positive, {neg_count} negative")
return report
if __name__ == "__main__":
track_sentiment(["scavio api", "scavio search"])Exemple JavaScript
const fs = require("fs");
const API_KEY = process.env.SCAVIO_API_KEY || "your_scavio_api_key";
const ENDPOINT = "https://api.scavio.dev/api/v1/search";
const POSITIVE = ["love", "great", "fast", "reliable", "cheap", "easy", "best", "solid", "recommend"];
const NEGATIVE = ["slow", "expensive", "broken", "hate", "worst", "terrible", "buggy", "unreliable"];
async function searchReddit(query) {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ query, platform: "reddit" })
});
const data = await res.json();
return data.organic_results || [];
}
function score(text) {
const t = text.toLowerCase();
const pos = POSITIVE.filter(w => t.includes(w)).length;
const neg = NEGATIVE.filter(w => t.includes(w)).length;
const net = pos - neg;
return { pos, neg, net, label: net > 0 ? "positive" : net < 0 ? "negative" : "neutral" };
}
async function trackSentiment(queries) {
const posts = [];
for (const q of queries) {
const results = await searchReddit(q);
for (const r of results) {
const text = `${r.title || ""} ${r.snippet || ""}`;
posts.push({ title: r.title, link: r.link, sentiment: score(text) });
}
}
const pos = posts.filter(p => p.sentiment.label === "positive").length;
const neg = posts.filter(p => p.sentiment.label === "negative").length;
console.log(`${posts.length} posts: ${pos} positive, ${neg} negative`);
const today = new Date().toISOString().split("T")[0];
fs.writeFileSync(`reddit_sentiment_${today}.json`, JSON.stringify({ date: today, total: posts.length, positive: pos, negative: neg }, null, 2));
}
trackSentiment(["scavio api", "scavio search"]).catch(console.error);Sortie attendue
{
"date": "2026-05-17",
"total": 24,
"positive": 9,
"negative": 4,
"neutral": 11,
"ratio": 0.38,
"top_positive": [
{
"title": "Scavio is the best cheap alternative to SerpApi",
"link": "https://reddit.com/r/webdev/comments/abc123",
"sentiment": { "pos": 2, "neg": 0, "net": 2, "label": "positive" }
}
],
"top_negative": [
{
"title": "Any search APIs that are not slow and overpriced?",
"link": "https://reddit.com/r/artificial/comments/def456",
"sentiment": { "pos": 0, "neg": 2, "net": -2, "label": "negative" }
}
]
}