Skip to content

Repository files navigation

Divar Telegram Bot

A scheduled crawler and notifier for Divar (Iran's largest classifieds app) that watches one or more cities/categories for new listings and posts them — with rich details, auto-generated hashtags, and optional "likely sold/rented" alerts — to a Telegram chat or channel.

This is a heavily modified fork of debMan/divar-telegram-bot (originally ehcaning/divar-telegram-bot). Divar changed its unofficial API since the original project was written, so the crawling logic, project structure, and feature set here are substantially different.

Features

  • Runs on GitHub Actions — no server to host or pay for. A scheduled workflow runs the bot every few minutes.
  • Multi-city search — search across several cities at once (SEARCH_CITY_IDS).
  • Rich ad details — pulls structured fields Divar shows on the ad page (area, room count, capacity, nightly rates, amenities, etc.), not just title/price/description.
  • Auto-generated hashtags — combines:
    • keyword-based tags detected in the ad text (property type, known local areas, deal type)
    • Divar's own breadcrumb category chain (e.g. #اجارهٔ_کوتاه_مدت_ویلا_و_باغ)
  • Channel-ready formatting — sends photos/albums with an HTML-formatted caption and a fixed contact/footer block, no direct outbound link.
  • "Likely sold/rented" alerts (optional, heuristic) — periodically rechecks previously-posted ads and notifies the channel if one seems to have disappeared from Divar.
  • Admin-controlled filters (optional) — authorized admins can DM the bot commands to change which cities/category it searches, without touching the repo.

Project structure

main.py             # entry point / orchestration
config.py           # env vars and constants (search filters, footer text, etc.)
divar_client.py      # talks to Divar's API, extracts ad fields
hashtags.py          # keyword + breadcrumb hashtag generation
telegram_client.py   # Telegram formatting and rich-media delivery
messenger_client.py  # Bale, Rubika, and Eitaa text delivery
storage.py            # tokens.json state (per-messenger delivery tracking)
admin_commands.py    # optional: admin DM commands for changing filters
status_checker.py    # optional: re-checks old ads for removal
requirements.txt
.github/workflows/run-bot.yml

How it works

Because free hosting doesn't give you a place to run a long-lived process, the bot doesn't run continuously. Instead, a GitHub Actions workflow runs it on a schedule (e.g. every 10 minutes). Each run:

  1. Polls for any pending admin DM commands (if ADMIN_USER_IDS is set) and updates search filters accordingly.
  2. Searches Divar for the configured cities/category, sorted by newest.
  3. Sends every new ad to each configured messenger.
  4. Optionally rechecks a batch of older ads to see if they look removed, and announces those.
  5. Commits the updated state (tokens.json, and filters.json/admin_state.json if used) back to the repo, so the next run picks up where this one left off.

Setup

1. Create your bot

Open @BotFather in Telegram, create a bot, and note its token.

2. Get your chat/channel ID

  • Private chat: message your bot, then visit https://api.telegram.org/bot<TOKEN>/getUpdates and read the chat.id field.
  • Public channel: you can just use its @username directly as the chat ID.
  • Private channel/group: add the bot as an admin with "Post Messages" permission, send a message in it, then check getUpdates the same way — the ID will be a large negative number.

3. Find your city ID(s) and category slug

Go to divar.ir, pick your city and category, and open the browser's Network tab (DevTools) while browsing search results. Look for the city_ids and category values in the request sent to api.divar.ir/v8/postlist/w/search. Alternatively, the URL shown when browsing divar.ir/s/... often reflects the category slug (e.g. real-estate, villa, temporary-rent).

4. Fork this repo, then add repository secrets

Go to Settings → Secrets and variables → Actions in your fork and add:

Secret Required Example Notes
BOT_TOKEN optional 123456:ABC-DEF... Telegram bot token from BotFather
BOT_CHATID optional -1001234567890 or @mychannel Telegram destination chat/channel
BALE_BOT_TOKEN optional Bale bot token
BALE_CHATID optional Bale destination chat/channel
RUBIKA_BOT_TOKEN optional Rubika bot token
RUBIKA_CHATID optional Rubika destination chat/channel
EITAA_TOKEN optional EitaaYar API token
EITAA_CHATID optional Eitaa destination chat/channel
SEARCH_CITY_IDS 823,1996,1999 Comma-separated numeric city IDs
SEARCH_CATEGORY real-estate Divar category slug
PROXY_URL optional Only needed if your runner can't reach Divar/Telegram directly
ADMIN_USER_IDS optional 111111,222222 Telegram numeric user IDs allowed to change filters via DM (see below)
STATUS_CHECK_LIMIT optional 20 Max old ads rechecked per run for the "likely removed" feature

Configure at least one token/chat-ID pair. Telegram keeps its rich photo or album delivery. Bale sends the first listing image followed by the formatted ad text; Rubika and Eitaa receive the formatted ad as text. The non-Telegram clients use compatible Bot API endpoints and can be pointed at alternative gateways with the optional BALE_API_BASE_URL, RUBIKA_API_BASE_URL, or EITAA_API_BASE_URL environment variables.

tokens.json now records delivery per platform. If one platform fails, the next run retries only that platform, avoiding duplicate posts on the platforms that succeeded.

5. Enable Actions write permissions

Settings → Actions → General → Workflow permissions → select "Read and write permissions" (needed so the workflow can commit tokens.json back to the repo).

6. Run it

Go to the Actions tab → select the workflow → Run workflow. On success it'll run automatically on the schedule defined in .github/workflows/run-bot.yml.

Admin filter commands

If ADMIN_USER_IDS is set, authorized users can DM the bot (private chat, not the channel):

/set_cities 823,1996,1999
/set_category real-estate
/show_filters
/help

Changes take effect starting the next scheduled run and only affect future searches — the bot never edits or deletes messages it already sent.

Local development

git clone https://github.com/<your-username>/divar-teleg-bot.git
cd divar-teleg-bot
pip install -r requirements.txt
export BOT_TOKEN=...
export BOT_CHATID=...
export SEARCH_CITY_IDS=823,1996
export SEARCH_CATEGORY=real-estate
echo '{}' > tokens.json
python main.py

Known limitations

  • This uses Divar's unofficial web API (the same one divar.ir itself calls), reverse-engineered from browser traffic. It can break again if Divar changes headers, endpoints, or response shapes.
  • The "likely sold/rented" detection is a heuristic (an ad becoming unreachable), not an explicit status field from Divar, since none is exposed on this endpoint. It can occasionally misfire; see status_checker.py for details and a debug flag to help refine it.
  • Hashtag detection is keyword/substring-based, so unusual phrasing in an ad's text may be missed.

License

See the original upstream project — no separate license has been added in this fork.

About

Multi-messenger bot that crawls Divar.ir for new ads and posts rich details + hashtags to Telegram, Bale, Rubika & Eitaa (runs on GitHub Actions)

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages