Telegram channels are where a lot of news, crypto, product and community announcements land first. If you want to archive a channel, track keywords across several channels, or feed posts into an LLM, the official route (MTProto via Telethon) needs an API ID, a phone number and a logged-in session. For public channels there is a simpler way.
The trick: the public web preview
Every public channel has a read-only web preview at https://t.me/s/<channel>. It is plain HTML, works without login, and shows the latest ~20 posts with dates, view counts and text.
# pip install requests beautifulsoup4 import requests from bs4 import BeautifulSoup def latest_posts(channel): html = requests.get(f"https://t.me/s/{channel}", timeout=20).text soup = BeautifulSoup(html, "html.parser") for msg in soup.select(".tgme_widget_message"): text = msg.select_one(".tgme_widget_message_text") views = msg.select_one(".tgme_widget_message_views") yield { "url": "https://t.me/" + msg["data-post"], "date": msg.select_one(".tgme_widget_message_date time")["datetime"], "views": views.text if views else None, "text": text.get_text(" ", strip=True) if text else "", } for p in latest_posts("telegram"): print(p["date"], p["views"], p["url"], p["text"][:60]) Output:
2026-08-26T19:12:24+00:00 1.87M https://t.me/telegram/459 Signed Gifts. You can now add your signature and a comment t 2026-08-26T19:12:34+00:00 2.12M https://t.me/telegram/460 For all the info from today's update and a look back at 13 y Gotchas if you extend this yourself:
- Only ~20 posts per page. Older posts need
?before=<postId>pagination, looping until you pass your start date. - Views come as
1.87M/12.3Kstrings; convert them before sorting. - Use the
timeinside.tgme_widget_message_date— videos also contain<time>elements (durations) without adatetimeattribute, which crashes a naiveselect_one("time"). - Forwards, replies, reactions, media URLs and edited flags each live in different elements.
- Channels with the preview disabled return no messages at all.
If you don't want to maintain that
Disclosure: I built a small Apify Actor that does the pagination, date range, keyword filter and field parsing above: Telegram Channel Posts Scraper. It costs $1.50 per 1,000 posts (Apify's free monthly credit covers a few thousand) and you can call it with plain requests:
# pip install requests import os, requests URL = ("https://api.apify.com/v2/acts/bachiembmt~telegram-channel-posts-scraper" "/run-sync-get-dataset-items") run_input = { "channels": ["durov", "https://t.me/telegram"], "maxPostsPerChannel": 60, "fromDate": "2026-01-01", "keywords": ["gift", "update"], "includeChannelInfo": False, } items = requests.post(URL, json=run_input, timeout=300, headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"}).json() for post in items: print(post.get("date"), post.get("views"), post.get("url"), (post.get("text") or "")[:60]) 2026-02-10T17:44:05+00:00 1940000 https://t.me/telegram/426 Gift Crafting. Collectible gifts can now be combined to crea 2026-01-07T18:17:53+00:00 2730000 https://t.me/telegram/423 Happy New Year! Telegram released 13 major updates in 2025 – Each post has channel, postId, url, date, text, views (as an integer), forwardedFrom, replyTo, hasMedia, mediaType, mediaUrls, links, reactions, edited. The dataset exports to CSV/Excel/JSON from the Apify console, and you can schedule the run daily to build a keyword alert.
Limits, honestly
- Public channels with the web preview enabled only. No private channels, groups or comments.
- It reads the same public HTML as the snippet above, so if Telegram changes the markup both break until fixed.
- Respect each channel's content rights when you republish anything.
If the DIY snippet is enough for you, use it — it is genuinely 20 lines. The Actor is for when you need many channels, history and a schedule without babysitting a parser.

