telegram-harvest · git:20261024.04abae1 · 2026-10-24 · sha256 7d13a982942836a7
telegram-harvest git:20261024.04abae1A
Immutable. This exact content never changes and is served at /api/v1/blob/7d13a982942836a7.
---
name: telegram-harvest
description: >
Programmatic, no-LLM Telegram channel harvest: tgspyder scrape -> offline language
detection + translation (Argos) -> rule-based field extraction -> XLSX with clue
columns, plus listings.jsonl and a capture batch for EV evidence. Built for
marketplace / account-sale / fraud-vendor channels. Use when: "harvest these
telegram channels", "scrape telegram listings into a spreadsheet", "telegram
marketplace sweep", "account procurement sheet".
NOT for: private groups the case has no lawful access to, or identifying a person
behind a channel (clues only; attribution needs T1/T2 crosslinks).
---
# telegram-harvest
Port of the founder's `assafkip/account-procurement-tools` pipeline (see `NOTICE.md`).
Deterministic: keyword dictionaries + regexes, no LLM, no external API at run time.
```
channels.txt -> tgspyder (scrape + invite links) -> lingua detect -> Argos translate (offline)
-> extract.py rules (type, price, PIN, verified, qty, handles, links)
-> geo_clues.py (clues only, never a country verdict)
-> telegram-harvest.xlsx + listings.jsonl + urls.tsv
```
## Setup (once per machine)
```bash
bash skills/telegram-harvest/setup.sh # venv, deps, tgspyder, Argos models
# tgspyder is not vendored: TGSPYDER_SRC=<checkout> bash .../setup.sh if it is elsewhere
skills/telegram-harvest/.venv/bin/tgspyder @somechannel --chats # one interactive login
```
Telegram login uses a real account session: founder decision per case. Sessions are
secrets; never commit them.
## Run
```bash
PY=skills/telegram-harvest/.venv/bin/python
H=skills/telegram-harvest/scripts/harvest.py
# live scrape into the active case (raw-collections/<ts>-telegram-harvest/)
$PY $H --channels <case>/investigation/evidence/telegram-channels.txt --case
# via SOCKS proxy
$PY $H --channels channels.txt --case --proxy socks5://127.0.0.1:9050
# offline: re-process an existing tgspyder messages CSV, no models needed
python3 $H --from-csv messages_x.csv --channel @x --case --no-translate
# a different rule profile (copy config/keywords.json and edit the terms)
$PY $H --channels channels.txt --case --keywords path/to/keywords.json
```
Bounded: `--max-messages` per channel (default 5000).
## Output columns
The sheet keeps the 23 template columns in order (Date of Finding ... Screenshot 4),
then helper columns prefixed `»`: Confidence (high/medium/low), Needs Review, Clue:
Language, Clue: Country Words, Clue: Phone Country, Clue: TG Handles, Source Channel,
Message ID, Message Date, Original Text, English Text. `Vendor Type`, `Ecosystem (Geo)`
and `Geo of Acc.` are left blank and highlighted: **a human makes the country call**.
## Evidence routing (required before citing)
- Every row is **T3** (automated extraction). The workbook is working material.
- Capture each message you will cite as an EV item:
`bash skills/osint/scripts/capture-evidence.sh --batch <run-dir>/urls.tsv --case <case>`
(trim urls.tsv to the rows you need first; add `--social` per line for media).
- If the workbook itself goes to a client, register it:
`ingest-client-document.sh <run-dir>/telegram-harvest.xlsx <slug> document --provided-by "telegram-harvest run <ts>"`.
- Handles, phone prefixes and country words are clues. A shared handle across
channels is not the same operator without a crosslink (`.claude/rules/q-investigation.md`).
## Extending the rules
- `config/keywords.json`: account types, flags, quantity/payment/transfer/spend/history/age
terms, in any language. Short Latin terms match on word boundaries; longer or CJK
terms match as substrings.
- `config/countries.json`: country names, demonyms and local terms for the clue column.
## Tests
`python3 -m pytest skills/osint/tests/test_telegram_harvest.py -q`
(offline: extraction, clues, confidence, workbook columns, CSV mode).