How read slack channel messages using python-slackclient - python

I want to get messages from my slack channel "general", may be with parameter like retrieve last 50 Messages.
I checked documents, there are all stuff like sending message, listing channels, leaving channels, finding channel ID's etc. But I didn't found anything which can help me to get channel's messages "once" using that channel ID.
Is this function available in python-slackclient. Or any workaround?

You are looking for the conversations.history method, which pulls the last 100 message events of a conversation. The sample code is pretty straightforward:
import os
# Import WebClient from Python SDK (github.com/slackapi/python-slack-sdk)
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
# WebClient insantiates a client that can call API methods
# When using Bolt, you can use either `app.client` or the `client` passed to listeners.
client = WebClient(token=os.environ.get("SLACK_BOT_TOKEN"))
# Store conversation history
conversation_history = []
# ID of the channel you want to send the message to
channel_id = "C12345"
try:
# Call the conversations.history method using the WebClient
# conversations.history returns the first 100 messages by default
# These results are paginated, see: https://api.slack.com/methods/conversations.history$pagination
result = client.conversations_history(channel=channel_id)
conversation_history = result["messages"]
# Print results
logger.info("{} messages found in {}".format(len(conversation_history), id))
except SlackApiError as e:
logger.error("Error creating conversation: {}".format(e))

After getting Channel ID's you can use api_calls to retrieve messages like this
history = client.api_call(api_method='conversations.history',data={'channel':'CHANNEL_ID_HERE'})
print(history)

Related

How can I publish custom broker messages in minos?

I want to send a message to notify about something in one of my microservices, but I don't want to do that through a domain event, which requires to create, update or delete one of the entities of the microservice.
Is there another way to send a message such that another microservices can handle them?
Yes! You can do that directly using the BrokerPublisher instance injected in the corresponding service.
If you want to send a message you can do as follows:
from minos.common import ModelType
from minos.cqrs import Service
from minos.networks import Request, enroute
MyContent = ModelType.build("MyContent", {"text": str, "number": int})
class MySenderService(Service):
#enroute.rest.command("/send/my-channel", "POST")
async def handle_send_my_channel(self, request: Request) -> Response:
# First, create the message.
message = BrokerMessageV1(
"MyChannel", BrokerMessageV1Payload(MyContent("foo", 56))
)
# Then, send it!
await self.broker_publisher.send(message)
In this case, "MyChannel" refers to the channel (or topic) on which the message will be sent.
Note that MyContent is a convenient ModelType created just to give the message's content some structure (but it could be another type, like int, str, dict and so on).
Finally, if you want to handle it in another microservice, you can do that as any other message:
from minos.cqrs import Service
from minos.networks import Request, enroute
class MyReceiverService(Service):
#enroute.broker.event("MyChannel")
async def handle_my_channel(self, request: Request):
# Print the received message's content!
print(await request.content())

How to get caption from Telegramm message(Pyrogram)

I'm newbie at Python. I want to parse certain dialog(contains only captions to pics) with Pyrogram. But if i use iter_history() methog it returns none if message contains pic+text.Like that.
import asyncio
from pyrogram import Client
app = Client("my_acc")
target = "dialog_example" # "me" refers to your own chat (Saved Messages)
with app:
for message in app.iter_history(target):
print(message.text)
None
Process finished with exit code 0
message.text is a message's text. If you want the caption of a message (or document rather), access message.caption.

Best practice in sending message in python telegram bot from a 3d party listener

I have a custom code that does its routine and I want to send a message to myself in Telegram if something goes wrong. In my case I use python-telegram-bot library along with apscheduler and its listeners, where certain events could be catched.
I came up with such working code, but my question is: is it possible to make it better, namely without using global variable? This was done to overcome the problem that listeners do not accept arguments needed for bot to send a message.
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR
from telegram.ext import Updater, CommandHandler
import copy
import my_custom_library
saved_update = None
def my_listener(event): # not related with bot
if event.exception:
if saved_update is not None:
alert(saved_update, 'Scheduler threw event.exception.') # should have bot related args
else:
record = event.retval # get returned value from my_custom_library.repetitive_function
try:
processed_record = my_custom_library.my_unsafe_business_logic(record) # something might go wrong here
my_custom_library.add_to_db(processed_record) # and here
except Exception as e:
if saved_update is not None:
alert(saved_update, e) # should have bot related args
def start(update, context):
global saved_update
saved_update = copy.deepcopy(update) # this is what I don't like
update.message.reply_text('You have subscribed for notifications.')
def alert(update, reason):
update.message.reply_text('Something went wrong: {}'.format(reason))
def main():
scheduler = BackgroundScheduler()
scheduler.add_listener(my_listener, EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
scheduler.add_job(my_custom_library.repetitive_function, args=(my_args,), trigger='interval', minutes=1)
scheduler.start()
# bot
updater = Updater(TOKEN, use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler("start", callback=start))
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
The Telegram Bot API is fairly simple, you just ned to send an HTTP GET Request to this URL:
https://api.telegram.org/bot_token_/sendMessage?chat_id=123&text=Hello%20World!
Just create a bot with Botfather and send the Bot a message.
With the specified Token from Botfather and this URL:
https://api.telegram.org/bot_token_/getUpdates
You can get the messages which were sent to the Bot and the chat_id.
The simplest way would be to use the requests module and send the output of the updater to the first URL as the text parameter.
In my scripts I often use callbacks. It's a clean solution that provides separation between the two scripts. The send_message function can accept kwargs, so you can essentially create a dictionary, and update it when sending the message. The first part (channel ID) is something you know on the bot-side, and the second part (the text itself) is something you know one the third-party side.
In your third-party, provide a set_cb function that accepts a callback and a dictionary. Like so:
def set_cb(self, callback, params):
self.callback = callback
self.callback_params = params
In your bot script, set the callback before updater.idle()
# Start the Bot
updater = Updater("TOKEN")
updater.start_polling()
# Set the callback
r.set_cb(updater.bot.send_message, {"chat_id": 123456})
Then, in your third-party, once you want to send a message, simply add the message text call the following:
self.callback_params.update({"text": text})
self.callback(**self.callback_params) # converts the dict to kwargs

Telethon: delete a message

I am trying to delete a message using telegram API and Telethon.
Here is my code:
from telethon import InteractiveTelegramClient
from telethon.tl.types.input_peer_channel import InputPeerChannel
from telethon.tl.functions.messages.delete_messages import DeleteMessagesRequest
#...
total_count, messages, senders = client.get_message_history(
chat, limit=1)
msg = messages[0]
result = client.invoke(DeleteMessagesRequest([msg.id]))
But first of all nothing happens, and second, it doesn't look right, since msg.id is like 5 or 220 and it doesn't look like a unique number.
Here is the message:
msg: (message (ID: 0xc09bexxx) = (out=None, mentioned=None, media_unread=None, silent=None, post=True, id=5, from_id=None, to_id=(peerChannel (ID: 0xbdddexxx) = (channel_id=1234)), fwd_from=None, via_bot_id=None, reply_to_msg_id=None, date=2017-06-14 14:39:23, message=test33, media=None, reply_markup=None, entities=None, views=1, edit_date=None))
I also tried with the hex number 0xc09bexxx but that gives an exception.
So how can I delete a message in a channel?
So far I looked at this github issue to get started with the delete message. My guess is that maybe the following import is not the right one and I should import the version in the Channels package, which gets a channel id and a message id?
from telethon.tl.functions.messages.delete_messages import DeleteMessagesRequest
Using the other delete from channels package I was able to get the delete message working, but I am still curious to know how to get the delete from messages.delete_messages working.
from telethon.tl.functions.channels.delete_messages import DeleteMessagesRequest
channel = InputPeerChannel(channel_id, access_hash)
result = client.invoke(DeleteMessagesRequest(channel, [msg.id]))
and it will delete the message from the channel.
from telethon import TelegramClient
client = TelegramClient('cookie', '123', 'XXX')
id_group = -1001231231231
id_message = 3
await client.delete_messages(entity=id_group, message_ids=[id_message])
For example if u want to obtain all the msgs-ids in the channel and after of it delete all messages... this code works to me:
from telethon import TelegramClient
client = TelegramClient('cookiename', Apiid, 'api_hash')
id_group = -XXXX
async def getmsgs(client,id_group):
messagesid = []
async for message in client.iter_messages(id_group):
print(message.id)
messagesid.append(message.id)
return messagesid
async def delmsgs(client,id_group,list_msgs_id):
await client.delete_messages(entity=id_group, message_ids=list_msgs_id)
with client:
messages = client.loop.run_until_complete(getmsgs(client,id_group))
client.loop.run_until_complete(delmsgs(client,id_group,messages))

How can I download the chat history of a group in Telegram?

I would like to download the chat history (all messages) that were posted in a public group on Telegram. How can I do this with python?
I've found this method in the API https://core.telegram.org/method/messages.getHistory which I think looks like what I'm trying to do. But how do I actually call it? It seems there's no python examples for the MTproto protocol they use.
I also looked at the Bot API, but it doesn't seem to have a method to download messages.
You can use Telethon. Telegram API is fairly complicated and with the telethon, you can start using telegram API in a very short time without any pre-knowledge about the API.
pip install telethon
Then register your app (taken from telethon):
the link is: https://my.telegram.org/
Then to obtain message history of a group (assuming you have the group id):
chat_id = YOUR_CHAT_ID
api_id=YOUR_API_ID
api_hash = 'YOUR_API_HASH'
from telethon import TelegramClient
from telethon.tl.types.input_peer_chat import InputPeerChat
client = TelegramClient('session_id', api_id=api_id, api_hash=api_hash)
client.connect()
chat = InputPeerChat(chat_id)
total_count, messages, senders = client.get_message_history(
chat, limit=10)
for msg in reversed(messages):
# Format the message content
if getattr(msg, 'media', None):
content = '<{}> {}'.format( # The media may or may not have a caption
msg.media.__class__.__name__,
getattr(msg.media, 'caption', ''))
elif hasattr(msg, 'message'):
content = msg.message
elif hasattr(msg, 'action'):
content = str(msg.action)
else:
# Unknown message, simply print its class name
content = msg.__class__.__name__
text = '[{}:{}] (ID={}) {}: {} type: {}'.format(
msg.date.hour, msg.date.minute, msg.id, "no name",
content)
print (text)
The example is taken and simplified from telethon example.
With an update (August 2018) now Telegram Desktop application supports saving chat history very conveniently.
You can store it as json or html formatted.
To use this feature, make sure you have the latest version of Telegram Desktop installed on your computer, then click Settings > Export Telegram data.
https://telegram.org/blog/export-and-more
The currently accepted answer is for very old versions of Telethon. With Telethon 1.0, the code can and should be simplified to the following:
# chat can be:
# * int id (-12345)
# * str username (#chat)
# * str phone number (+12 3456)
# * Peer (types.PeerChat(12345))
# * InputPeer (types.InputPeerChat(12345))
# * Chat object (types.Chat)
# * ...and many more types
chat = ...
api_id = ...
api_hash = ...
from telethon.sync import TelegramClient
client = TelegramClient('session_id', api_id, api_hash)
with client:
# 10 is the limit on how many messages to fetch. Remove or change for more.
for msg in client.iter_messages(chat, 10):
print(msg.sender.first_name, ':', msg.text)
Applying any formatting is still possible but hasattr is no longer needed. if msg.media for example would be enough to check if the message has media.
A note, if you're using Jupyter, you need to use async directly:
from telethon import TelegramClient
client = TelegramClient('session_id', api_id, api_hash)
# Note `async with` and `async for`
async with client:
async for msg in client.iter_messages(chat, 10):
print(msg.sender.first_name, ':', msg.text)
Now, you can use TDesktop to export chats.
Here is the blog post about Aug 2018 update.
Original Answer:
Telegram MTProto is hard to use to newbies, so I recommend telegram-cli.
You can use third-party tg-export script, but still not easy to newbies too.
You can use the Telethon library. for this you need to register your app and connect your client code to it (look at this).
Then to obtain message history of a entry (such as channel, group or chat):
from telethon.sync import TelegramClient
from telethon.errors import SessionPasswordNeededError
client = TelegramClient(username, api_id, api_hash, proxy=("socks5", proxy_ip, proxy_port)) # if in your country telegram is banned, you can use the proxy, otherwise remove it.
client.start()
# for login
if not client.is_user_authorized():
client.send_code_request(phone)
try:
client.sign_in(phone, input('Enter the code: '))
except SessionPasswordNeededError:
client.sign_in(password=input('Password: '))
async for message in client.iter_messages(chat_id, wait_time=0):
messages.append(Message(message))
# write your code

Categories