name: public-data-brand-monitoring description: "Build crisis-first, public-data-only brand monitoring systems. Covers WAF by-pass (Google News RSS proxy), source feasibility testing, 4-layer pipeline architecture, storage decisions, and delivery cadence." version: 1.0.0 author: Hermes + CEO Nhi metadata: hermes: tags: [Brand-Monitoring, RSS, Pipeline, WAF, Crisis-Management] related_skills: [research-pipeline, hermes-kanban]
Trigger: User wants to monitor brand health / reputation using only publicly available data and no private API access.
[Source Intake] → [Normalize & Dedupe] → [Score & Crisis Gate] → [Store & Deliver]
Each source belongs to one of three fetch strategies:
| Strategy | Method | Example |
|----------|--------|---------|
| Public RSS | feedparser on RSS/Atom feed | Google News RSS, VnExpress RSS |
| Public page scrape | requests + HTML parse on tag/search page | VietnamPlus tag, Tuổi Trẻ search |
| Search only | Query via search engine (no direct scrape) | site:fulbright.edu.vn via Google News |
| Component | Points |
|---|---|
| Core entity in title | +30 |
| Crisis trigger keyword | +25 |
| Brand variant match | +15 |
| Core entity in body | +15 |
| Policy context match | +10 |
| Source tier A/B | +5 |
Crisis Gate — if Negative sentiment + Relevance ≥ 70: HOT ALERT (deliver immediately). All other entries go into the periodic digest queue.
.jsonl.gz (raw items) with 90-day DB retentionWhen a target domain returns HTTP 403 (e.g. Azure WAF):
Google News RSS proxy — always try first:
https://news.google.com/rss/search?q=site:<blocked_domain>&hl=vi&gl=VN&ceid=VN:vi
Google's crawler passes most WAFs. Data includes: title, source, published date, link.
Verified working (tested against fulbright.edu.vn, fsppm.fulbright.edu.vn).
Sitemap.xml — check /sitemap.xml, /sitemap_index.xml, /post-sitemap.xml.
WAFs sometimes bypass these. (Did NOT work in test against Azure WAF.)
RSS feed guessing — try /feed/, /rss/, /news/feed/, /en/feed/.
(Did NOT work against Azure WAF.)
Bing News API — alternative search engine with site: query.
Free tier 1K queries/month.
Do NOT use cloudscraper, cheap rotating proxies, or default-headless Selenium — these are easily detected by Azure WAF and waste time.
| Job | Cadence | Notes |
|---|---|---|
| RSS collect | Every 6 hours | feedparser on news sources |
| Sentinel crisis check | Every 1 hour | Narrow Google News query with crisis keywords |
| Report digest | Mon/Wed/Fri 09:00 VN | Full sentiment breakdown + alerts |
| Archive | Daily at 23:00 VN | Compress raw → .jsonl.gz |
| Cleanup raw | Weekly | Remove raw > 90 days (already archived) |
Before building the full pipeline, test each candidate source:
# 1. HTTP status check
urllib.request.urlopen(url, timeout=8) # expect 200
# 2. RSS parseability
import feedparser
feed = feedparser.parse(url) # expect > 0 entries, parsed title/source/date
# 3. Content relevance (tag/search pages)
import re
body = response.read().decode('utf-8', errors='replace')
matches = len(re.findall(r'brand_keyword', body, re.IGNORECASE)) # expect > 0
Save results as JSON for IT to reference. See references/ for a full feasibility test transcript.
Avoid sending single-article alerts. Use an aggregated digest format with the following structure:
1. Header: 📢 FULBRIGHT BRAND MONITORING UPDATE + 🕒 Date period: [dd/mm/yyyy] → [dd/mm/yyyy].
2. Summary: 🧾 Alerts: [count] pending.
3. Item details (grouped by Source):
- 📰 Source: [Source Name] (e.g. VnExpress)
- 📅 Air date: [dd/mm/yyyy]
- 🔗 Article: [Hyperlink Title](URL) (always use hyperlink to minimize text block width)
- ✨ Fulbright highlight: Extract a clean 1-2 sentence context snippet containing the keyword.
- 📊 Sentiment / Brand health: [sentiment] / [crisis_label] | score [relevance_score]
- ⚠️ Discussion: Include brief explanation of the crisis reason (e.g. crisis_trigger:học phí) if triggered.
#Fulbright or Tin tức, hình ảnh, video clip mới nhất về ..., reject it even if the URL looks parseable.consent.google.com or news.google.com/rss/articles/...). Do not fetch or scrape these URLs directly with simple HTTP libraries. Instead, parse original source URLs safely or switch to native RSS feeds from target domains (like VnExpress or Tuổi Trẻ RSS) to retrieve readable body texts/snippets.snippet) might contain HTML junk or simple titles instead of actual content. Always fetch and sanitise the summary/description fields from entries, extract brand keywords dynamically, and fallback to title substrings rather than leaving highlights empty or using static placeholders.report.yaml) for receiver topics.references/fulbright-feasibility-test-20260714.md for the source feasibility transcript and failure modes.thread_id directly in the project config (report.yaml). This prevents "ghost profiles" from cluttering the system.2016, 2019, 2025 when checking 07/2026), discard it to prevent historical noise.