I'm new to telethon and python. I have installed telethon in python3 and I want to get all members of a telegram channel or a group . I was searching a lot in the internet and found below code . And I'm trying really hard to understand it .Telegram documentation is not enough to do this . Is there a better solution ?
from telethon import TelegramClient
from telethon.tl.functions.contacts import ResolveUsernameRequest
from telethon.tl.functions.channels import GetAdminLogRequest
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.types import ChannelParticipantsRecent
from telethon.tl.types import InputChannel
from telethon.tl.types import ChannelAdminLogEventsFilter
from telethon.tl.types import InputUserSelf
from telethon.tl.types import InputUser
# These example values won't work. You must get your own api_id and
# api_hash from https://my.telegram.org, under API Development.
api_id = 12345
api_hash = '8710a45f0f81d383qwertyuiop'
phone_number = '+123456789'
client = TelegramClient(phone_number, api_id, api_hash)
client.session.report_errors = False
client.connect()
if not client.is_user_authorized():
client.send_code_request(phone_number)
client.sign_in(phone_number, input('Enter the code: '))
channel = client(ResolveUsernameRequest('channelusername')) # Your channel username
user = client(ResolveUsernameRequest('admin')) # Your channel admin username
admins = [InputUserSelf(), InputUser(user.users[0].id, user.users[0].access_hash)] # admins
admins = [] # No need admins for join and leave and invite filters
filter = None # All events
filter = ChannelAdminLogEventsFilter(True, False, False, False, True, True, True, True, True, True, True, True, True, True)
cont = 0
list = [0,100,200,300]
for num in list:
result = client(GetParticipantsRequest(InputChannel(channel.chats[0].id, channel.chats[0].access_hash), filter, num, 100))
for _user in result.users:
print( str(_user.id) + ';' + str(_user.username) + ';' + str(_user.first_name) + ';' + str(_user.last_name) )
with open(''.join(['users/', str(_user.id)]), 'w') as f: f.write(str(_user.id))
But I'm getting this error . What have I missed ?
Traceback (most recent call last):
File "run.py", line 51, in <module>
result = client(GetParticipantsRequest(InputChannel(channel.chats[0].id, channel.chats[0].access_hash), filter, num, 100))
TypeError: __init__() missing 1 required positional argument: 'hash'
Sean answer won't make any difference.
Your code works for older Telethon versions. In the new versions, a new argument hash is added to GetParticipantsRequest method. Therefore, you need to pass hash as an argument too. Add hash=0 like this:
result = client(GetParticipantsRequest(InputChannel(channel.chats[0].id, channel.chats[0].access_hash), filter, num, 100, 0))
Note that the hash of the request is not the channel hash. It's a special hash calculated based on the participants you already know about, so Telegram can avoid resending the whole thing. You can just leave it to 0.
Here is an up-to-date example from official Telethon wiki.
channel = client(ResolveUsernameRequest('channel_name'))
user_list = client.iter_participants(entity=channel)
for _user in user_list:
print(_user)
or
user_list = client.get_participants(entity=channel)
for _user in user_list:
print(_user)
from
I think You can use this code in the new version of Telethon
from telethon import TelegramClient
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.functions.channels import GetFullChannelRequest
from telethon.tl.types import ChannelParticipantsSearch
api_id = XXXXX
api_hash = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
phone_number = '+98XXXXXXXX'
################################################
channel_username = 'tehrandb'
################################################
client = TelegramClient('session_name',api_id,api_hash)
assert client.connect()
if not client.is_user_authorized():
client.send_code_request(phone_number)
me = client.sign_in(phone_number, input('Enter code: '))
# ---------------------------------------
offset = 0
limit = 200
my_filter = ChannelParticipantsSearch('')
all_participants = []
while_condition = True
# ---------------------------------------
channel = client(GetFullChannelRequest(channel_username))
while while_condition:
participants = client(GetParticipantsRequest(channel=channel_username, filter=my_filter, offset=offset, limit=limit, hash=0))
all_participants.extend(participants.users)
offset += len(participants.users)
if len(participants.users) < limit:
while_condition = False
I used Telethon V0.19, but the previous versions are pretty much the same
you can try the code below, it works, I tested. But I do have a question, because the Telethon library doesn't extra all the users, it only extra like 90% of the users. I think it somehow skipped some ones... don't know why.
from telethon.sync import TelegramClient
from telethon.tl.functions.messages import GetDialogsRequest
from telethon.tl.types import InputPeerEmpty
import csv
api_id = 123456
api_hash = 'YOUR_API_HASH'
phone = '+111111111111'
client = TelegramClient(phone, api_id, api_hash)
client.connect()
if not client.is_user_authorized():
client.send_code_request(phone)
client.sign_in(phone, input('Enter the code: '))
chats = []
last_date = None
chunk_size = 200
groups=[]
result = client(GetDialogsRequest(
offset_date=last_date,
offset_id=0,
offset_peer=InputPeerEmpty(),
limit=chunk_size,
hash = 0
))
chats.extend(result.chats)
for chat in chats:
try:
if chat.megagroup== True:
groups.append(chat)
except:
continue
print('Choose a group to scrape members from:')
i=0
for g in groups:
print(str(i) + '- ' + g.title)
i+=1
g_index = input("Enter a Number: ")
target_group=groups[int(g_index)]
print('Fetching Members...')
all_participants = []
all_participants = client.get_participants(target_group, aggressive=True)
print('Saving In file...')
with open("members.csv","w",encoding='UTF-8') as f:
writer = csv.writer(f,delimiter=",",lineterminator="\n")
writer.writerow(['username','user id', 'access hash','name','group', 'group id'])
for user in all_participants:
if user.username:
username= user.username
else:
username= ""
if user.first_name:
first_name= user.first_name
else:
first_name= ""
if user.last_name:
last_name= user.last_name
else:
last_name= ""
name= (first_name + ' ' + last_name).strip()
writer.writerow([username,user.id,user.access_hash,name,target_group.title, target_group.id])
print('Members scraped successfully.')
The simple way to get all users of a telegram channel using telethon. And make sure that you have valid permissions used for the channel or group (caused by GetParticipantsRequest).
from telethon.tl.functions.contacts import ResolveUsernameRequest
channel = await client(ResolveUsernameRequest('channel_name'))
async for _user in client.iter_participants(entity=channel):
print(_user)
Use client.invoke() instead of client().
You can refer to official guide.
Related
I am using following code for scrapping messages from a telegram group but getting error;
Please guide me how to solve this or suggest any-other efficient solution.
RuntimeError: You must use "async with" if the event loop is running (i.e. you are inside an "async def")
Code:
from telethon.sync import TelegramClient
import datetime
import pandas as pd
import configparser
config = configparser.ConfigParser()
config.read("telethon.config")
api_id = config["telethon_credentials"]["api_id"]
api_hash = config["telethon_credentials"]["api_hash"]
chats = ['cryptodubai7']
client = TelegramClient('test', api_id, api_hash)
df = pd.DataFrame()
for chat in chats:
with TelegramClient('test', api_id, api_hash) as client:
for message in client.iter_messages(chat, offset_date=datetime.date.today() , reverse=True):
print(message)
data = { "group" : chat, "sender" : message.sender_id, "text" : message.text, "date" : message.date}
temp_df = pd.DataFrame(data, index=[1])
df = df.append(temp_df)
df['date'] = df['date'].dt.tz_localize(None)
You are creating 2 TelegramClient's, doesn't seem needed
You need to client.start()
Like the error suggest, you need to use async
Also an await is needed for retrieving the messages
I'd recommend using an event loop, like asyncio
Something like this should get you in the right direction:
Untested!
from telethon.sync import TelegramClient
import datetime
import pandas as pd
import asyncio
import configparser
config = configparser.ConfigParser()
config.read("telethon.config")
api_id = config["telethon_credentials"]["api_id"]
api_hash = config["telethon_credentials"]["api_hash"]
chats = ['cryptodubai7']
client = TelegramClient('test', api_id, api_hash)
client.start()
async def main():
df = pd.DataFrame()
for chat in chats:
messages = await client.iter_messages(chat, offset_date=datetime.date.today() , reverse=True)
for message in messages:
print(message)
data = { "group" : chat, "sender" : message.sender_id, "text" : message.text, "date" : message.date}
temp_df = pd.DataFrame(data, index=[1])
df = df.append(temp_df)
df['date'] = df['date'].dt.tz_localize(None)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
I'm using peewee to store participants in a telegram channel. How do I get only new participants, i.e. those who have not been previously added?
Maybe we can offset by time? or offset by those who are already in the database?
Not so sure how to perform offsets in GetParticipantsRequest
from telethon import TelegramClient
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.types import ChannelParticipantsSearch
from time import sleep
from schema import channel_users as cudb
from datetime import datetime
import json
from dotenv import load_dotenv
load_dotenv()
import os
api_id = os.getenv('API_ID')
api_hash = os.getenv('API_HASH')
PHONE = os.getenv('PHONE')
USERNAME = os.getenv('USERNAME')
# Remember to use your own values from my.telegram.org!
client = TelegramClient('anon', api_id, api_hash)
async def main():
# Getting information about yourself
me = await client.get_me()
my_channel = 'https://t.me/some_channel_url'
offset = 0
limit = 100
all_participants = []
while True:
participants = await client(GetParticipantsRequest(
my_channel, ChannelParticipantsSearch(''), offset, limit,
hash=0
))
if not participants.users:
break
all_participants.extend(participants.users)
offset += len(participants.users)
all_user_details = []
for participant in all_participants:
now = datetime.now()
date_added = now.strftime("%d/%m/%Y, %H:%M:%S")
channel_user_id, created = cudb.get_or_create(
id = participant.id,
defaults = {'first_name' : participant.first_name,
'last_name' : participant.last_name,
'username' : participant.username,
'phone' : participant.phone,
'is_bot' : participant.bot,
'date_added' : date_added}
)
if (created):
print(f'successfully created channel_usersID = {channel_user_id}')
else:
print(f'did not create anything, user information found in channel_usersID {channel_user_id}')
with client:
client.loop.run_until_complete(main())
ok I've sort of solved it with this. Problem is - Now trying to figure out how to update every time new user joins
while True:
participants = await client(GetParticipantsRequest(
my_channel, ChannelParticipantsSearch(''), offset, limit,
hash=0
))
number_of_participants = len(participants.users)
print(f'{len(participants.users)} length')
max_cudb = cudb.select(fn.MAX(cudb.channel_usersID)).scalar()
if max_cudb == len(participants.users):
print('id is same as number of participants in group, hence nothing new')
break
if not participants.users:
break
# calculate the difference between number of participants and last user added to DB
number_to_add = number_of_participants - max_cudb
# adds missing users chronologically from oldest to most recent
print(f'number_to_add = {number_to_add}')
for i in range(number_to_add-1,-1,-1):
print(f'i = {i}')
participant = participants.users[i]
now = datetime.now()
date_added = now.strftime("%d/%m/%Y, %H:%M:%S")
channel_user_id, created = cudb.get_or_create(
id = participant.id,
defaults = {'first_name' : participant.first_name,
'last_name' : participant.last_name,
'username' : participant.username,
'phone' : participant.phone,
'is_bot' : participant.bot,
'date_added' : date_added}
)
# Prints status of DB addition
if (created):
print(f'successfully created channel_usersID = {channel_user_id}')
else:
print(f'did not create anything, user information found in channel_usersID {channel_user_id}')
https://docs.telethon.dev/en/stable/quick-references/events-reference.html?highlight=chataction#chataction here you are the docs for chataction, exactly what you need just make sure to filter the event.
I'm new to python and i'm making discord bot. So here i have twitch notification function, but when someone is live bot just starts spamming, i think because idk how to get content out of an embed. please help me. the code:
import os
import json
import discord
import requests
from discord.ext import tasks, commands
from discord.utils import get
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='$', intents=intents)
TOKEN = os.getenv('token')
# Authentication with Twitch API.
client_id = os.getenv('client_id')
client_secret = os.getenv('Dweller_token')
body = {
'client_id': client_id,
'client_secret': client_secret,
"grant_type": 'client_credentials'
}
r = requests.post('https://id.twitch.tv/oauth2/token', body)
keys = r.json()
headers = {
'Client-ID': client_id,
'Authorization': 'Bearer ' + keys['access_token']
}
'''user_info = twitch.get_users(logins=['turb4ik'])
user_id = user_info['data'][0]['id']
print(user_info)'''
# Returns true if online, false if not.
def checkuser(streamer_name):
stream = requests.get('https://api.twitch.tv/helix/streams?user_login=' + streamer_name, headers=headers)
stream_data = stream.json()
if len(stream_data['data']) == 1:
return True, stream_data
else:
return False, stream_data
# Executes when bot is started
#bot.event
async def on_ready():
# Defines a loop that will run every 10 seconds (checks for live users every 10 seconds).
#tasks.loop(seconds=10)
async def live_notifs_loop():
# username = stream_data['data'][0]['user_name']
# stream_title = stream_data['data'][0]['title']
# game_being_played = stream_data['data'][0]['game_name']
# Opens and reads the json file
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Makes sure the json isn't empty before continuing.
if streamers is not None:
# Gets the guild, 'twitch streams' channel, and streaming role.
guild = bot.get_guild(690995360411156531)
channel = bot.get_channel(798127930295058442)
role = get(guild.roles, id=835581408272580649)
# Loops through the json and gets the key,value which in this case is the user_id and twitch_name of
# every item in the json.
for user_id, twitch_name in streamers.items():
print("checking" + " " + str(twitch_name))
# Takes the given twitch_name and checks it using the checkuser function to see if they're live.
# Returns either true or false.
status, stream_data = checkuser(twitch_name)
# Gets the user using the collected user_id in the json
user = bot.get_user(int(user_id))
# Makes sure they're live
if status is True:
# Checks to see if the live message has already been sent.
async for message in channel.history(limit=200):
print("yes")
twitch_embed = discord.Embed(
title=f":red_circle: **LIVE**\n{user.name} is now streaming on Twitch! \n \n {stream_data['data'][0]['title']}",
color=0xac1efb,
url=f'\nhttps://www.twitch.tv/{twitch_name}'
)
twitch_embed.add_field(
name = '**Game**',
value = stream_data['data'][0]['game_name'],
inline = True
)
twitch_embed.add_field(
name = '**Viewers**',
value = stream_data['data'][0]['viewer_count'],
inline = True
)
twitch_embed.set_author(
name = str(twitch_name),
icon_url = stream_data['data'][0]['thumbnail_url']
)
twitch_embed.set_image(url = f'https://www.twitch.tv/{twitch_name}')
print("yes2")
try:
embed_title = twitch_embed.title
embed_description = twitch_embed.description
except Exception as e:
break
print("yes3")
# If it has, break the loop (do nothing).
if embed_title == True:
break
# If it hasn't, assign them the streaming role and send the message.
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and
# they're live, give them the streaming role.
if member.id == int(user_id):
await member.add_roles(role)
# Sends the live notification to the 'twitch streams' channel then breaks the loop.
await channel.send(
content = f"Hey #everyone! {user.name} is now streaming on Twitch! Go check it out: https://www.twitch.tv/{twitch_name}", embed=twitch_embed)
print(f"{user} started streaming. Sending a notification.")
break
# If they aren't live do this:
else:
# Gets all the members in your guild.
async for member in guild.fetch_members(limit=None):
# If one of the id's of the members in your guild matches the one from the json and they're not
# live, remove the streaming role.
if member.id == int(user_id):
await member.remove_roles(role)
# Checks to see if the live notification was sent.
async for message in channel.history(limit=200):
try:
embed_title = message.embeds[0].title
embed_description = message.embeds[0].description
except Exception as e:
break
# If it was, delete it.
if user.mention in embed_title and "is now playing" in embed_title:
print(f"{user} stopped streaming. Removing the notification.")
await message.delete()
# Start your loop.
live_notifs_loop.start()
# Command to add Twitch usernames to the json.
#bot.command(name='addtwitch', help='Adds your Twitch to the live notifs.', pass_context=True)
async def add_twitch(ctx, twitch_name):
# Opens and reads the json file.
with open('streamers.json', 'r') as file:
streamers = json.loads(file.read())
# Gets the users id that called the command.
user_id = ctx.author.id
# Assigns their given twitch_name to their discord id and adds it to the streamers.json.
streamers[user_id] = twitch_name
# Adds the changes we made to the json file.
with open('streamers.json', 'w') as file:
file.write(json.dumps(streamers))
# Tells the user it worked.
await ctx.send(f"Added {twitch_name} for {ctx.author} to the notifications list.")
print('Server Running')
bot.run(TOKEN)
Just for others context, he had shown me the error on discord, so I am answering him through this question!
So mate, I found the error.
The line 106 in your code is:
await message.channel.send(msg)
Now this msg variable send all the details but we just want the content of it and not anything else.
So change that to:
await message.channel.send(msg.content)
Thank You! :D
This is the first script which get's data from a website:
import requests
def get_prices():
name = "SeedifyFund"
crypto_data = requests.get("https://api.pancakeswap.info/api/tokens").json()["data"]
data = None
for i in crypto_data:
current = crypto_data[i]
if current['name'] == name:
data = {
"PriceUSD": current["price"],
"PriceBNB": current["price_BNB"],
}
return data
if __name__ == "__main__":
print(get_prices())
The code above outputs the following: {'PriceUSD': '1.022239219137518991087869433174527', 'PriceBNB': '0.002452203037583603303073246037795846'}
I'm having issue an issue with the second script. I want it to use the data that it has collected above and print it in a telegram bot when the user types /price. The code for the second script:
import telegram
from telegram.ext import Updater
from telegram.ext import CommandHandler
from tracker import get_prices
telegram_bot_token = "API TOKEN"
updater = Updater(token=telegram_bot_token, use_context=True)
dispatcher = updater.dispatcher
def price(update, context):
chat_id = update.effective_chat.id
message = ""
crypto_data = get_prices()
for i in crypto_data:
bnbprice = crypto_data[i]["pricebnb"]
usdprice = crypto_data[i]["priceusd"]
message += f"1 SFUND = \n${usdprice:,.2f} USD\n{bnbprice:.3f} BNB\n\n"
context.bot.send_message(chat_id=chat_id, text=message)
dispatcher.add_handler(CommandHandler("price", price))
updater.start_polling()
When the user types /price in the telegram chat it give this error:
coin = crypto_data[i]["pricebnb"]
TypeError: string indices must be integers
Could someone tell me what I'm doing wrong and help me solve the issue. Many thanks
Help: Relatively new to telethon and was having issue with delete_messages()function. It "seems" to do nothing for me...
Initially I am getting the message id from send_message, from the return object's id value. It returns values like 1, 2, etc. Not sure this is the message id though.
I send it to delete_messages as delete_messages(channel, [id])
I get the channel (It's a private channel) from:
def resolve_channel_id(self, name):
try:
if name in self.__channel_ids:
return self.__channel_ids[name]
channel_id = self.client(ResolveUsernameRequest(name))
self.__channel_ids[name] = channel_id
return channel_id
# except UserNameNotOccupiedError as err:
except Exception as err:
# try for private channel
chatinvite = self.client(CheckChatInviteRequest(name))
channel_id = chatinvite.chat.id
access_hash_channel = chatinvite.chat.access_hash
channel_id = InputChannel(channel_id, access_hash_channel)
self.__channel_ids[name] = channel_id
return channel_id
I hope this example is useful for friends :
by this code, if a message with a Hello text is sent to a group with ID -1001300989487, that text will be deleted.
import logging
from telethon import TelegramClient, events
logging.basicConfig(level=logging.INFO)
api_id = XXXXXX
api_hash = 'XXXXXXXXXXXXXXXXXXXXXXX'
phone_number = '+989XXXXXXXX'
################################################
client = TelegramClient('session_name',
api_id,
api_hash,
)
#client.on(events.NewMessage(chats=(-1001300989487)))
async def my_event_handler(event):
if 'hello' in event.raw_text:
await event.delete()
client.start()
client.run_until_disconnected()
print('finish')
Works by updating to latest telethon: 1.0.3, and following documentation... https://telethon.readthedocs.io/en/latest/extra/basic/asyncio-magic.html