After the start of the bans of accounts connected to my project, I changed the system for receiving new messages in the telegram account. Previously, I implemented it through a handler, now it is possible to connect several accounts, performing actions with unread messages on each one in turn. Code:
async def start_wtf_blyat():
global client, current_session_account
while True:
for cl in clients:
current_session_account = cl[0]
client = cl[1]
print(f'Choosing {current_session_account.session_name}')
if current_session_account.start_time is not None:
if current_session_account.start_time > dt.datetime.utcnow():
print(
f"{current_session_account.session_name}: {current_session_account.start_time.strftime('%d.%m.%Y %H:%M:%S')} > {dt.datetime.utcnow().strftime('%d.%m.%Y %H:%M:%S')}")
s_d = (current_session_account.start_time - dt.datetime.utcnow().replace(
microsecond=0)) * random.randrange(
1, 3)
print(f'{current_session_account.session_name} needs to sleep {s_d.seconds} seconds')
await asyncio.sleep(s_d.seconds)
print(f'{current_session_account.session_name}: Sleep complete!')
current_session_account.start_time = dt.datetime.utcnow().replace(microsecond=0)
current_session_account.activate()
async with client:
print(f'Starting {current_session_account.session_name}')
await check_news()
print(
f'{current_session_account.session_name}: Work complete! END: {current_session_account.end_time.strftime("%d.%m.%Y %H:%M:%S")}')
Then the necessary messages are selected in the check_news():
async def check_news():
global current_session_account, ME
ME = await client.get_me()
await asyncio.sleep(random.randrange(1, 5, 1))
# try:
x = [[d.unread_count, d.entity.id, d.title] for d in await client.get_dialogs() if
not getattr(d.entity, 'is_private', False) and type(d.entity) == Channel
and d.unread_count != 0 and d.entity.id in INPUT_CHANNELS_IDS]
if not x:
rnd_sleep = random.randrange(180, 300)
print(f'{current_session_account.session_name}: No channels, sleep for {rnd_sleep} seconds')
end_time = dt.datetime.utcnow().replace(microsecond=0)
start_time = current_session_account.start_time
if start_time is not None:
if start_time < end_time:
delta = end_time - start_time + dt.timedelta(seconds=rnd_sleep)
else:
delta = dt.timedelta(seconds=rnd_sleep)
print(f'{current_session_account.session_name} START: {start_time.strftime("%d.%m.%Y %H:%M:%S")}, '
f'END: {end_time.strftime("%d.%m.%Y %H:%M:%S")}, '
f'DELTA: {delta}, '
f'NEXT START {(end_time + delta).strftime("%d.%m.%Y %H:%M:%S")}')
current_session_account.set_times(delta)
current_session_account.deactivate()
return
for da in x:
print(f'{current_session_account.session_name}: {x.index(da) + 1} of {len(x)}')
await asyncio.sleep(random.randrange(1, 5, 1))
async for msg in client.iter_messages(da[1], limit=da[0]):
await asyncio.sleep(random.randrange(3, 5, 1))
await msg.mark_read()
if msg.text is None:
continue
comm_result_true = await Magic.detect_commercial(msg.text)
antiplagiat_result = await antiplagiat(msg)
if not comm_result_true and antiplagiat_result:
await send_this_post(msg, da[1])
else:
print(f'{current_session_account.session_name}: Commercial or plagiat!')
# finally:
end_time = dt.datetime.utcnow().replace(microsecond=0)
start_time = current_session_account.start_time
if start_time is not None:
if start_time < end_time:
delta = end_time - start_time + dt.timedelta(seconds=1)
else:
delta = dt.timedelta(seconds=2)
print(f'{current_session_account.session_name} START: {start_time.strftime("%d.%m.%Y %H:%M:%S")}, '
f'END: {end_time.strftime("%d.%m.%Y %H:%M:%S")}, '
f'DELTA: {delta}, '
f'NEXT START {(end_time + delta).strftime("%d.%m.%Y %H:%M:%S")}')
current_session_account.set_times(delta)
current_session_account.deactivate()
return
Finally, the message is processed, the media is downloaded, if any, the text is saved. And other actions are no longer related to the telegram api.
async def send_this_post(msg, result):
chan = db.get_input_channel(result)
if db.using_ai(chan[1]):
check = await Magic.detect_theme(msg.text)
if check:
msg_category = CAT_DEF[f'{check}']
else:
return
else:
msg_category = db.get_category_by_input_channel_name(chan[1])
print(f'Theme - {msg_category}')
test = await MSG(msg_cat=msg_category, txt=msg.text, title=chan[2], username=chan[1], datetime=msg.date)
await test.create_media(msg)
await test.create_voice()
await test.create_translates()
await send_to_users_test(test)
return
Everything starts as follows:
if __name__ == '__main__':
logging.warning('IZVESTNIK STARTED.')
loop = asyncio.get_event_loop()
bot.start(bot_token=settings.bot_TOKEN)
logging.warning(f'BOT {settings.bot_username} just launched.')
loop.create_task(usr_periods_activity())
loop.create_task(usr_msg_queue_activity())
loop.create_task(start_wtf_blyat())
bot.loop.run_forever()
In fact, all that each account does is receive unread messages, download media, mark them as read, but even the launch of 8 accounts resulted in the ban of each of them for 3 days, either in general without an error, or with an Account deactivated/deleted error (Caused get_dialogs request).
Although many users of the telegram application do many times more actions. Recently rereading the documentation, I came across this:
Text from documentation.
Perhaps the reason is that I am from Russia, and I use Russian SIM cards to register accounts, but a friend from England bought SIM cards for me there several times, but they also received a ban. The project release is located on the WDM server, the ip is also Russian, maybe that's the problem?
I also recommend to use different version
pip install Telethon==1.1
this version can't ban your account
The solution of this issue is just write an "impulse" activity script against pooling script. Also use SIM cards from another country for telegram accounts and proxy.
Related
I am creating a bot that displays Bitcoin statistics. The bot changes its activity to Bitcoin statistics every 3 seconds. But at some point the bot stops every time without error, I restart the bot and I get an error discord.http: We are being rate limited. Responded with 429. What to do, how do I need to redo the code?
import requests_html
import time
import discord
from discord.ext import commands
from discord.utils import get
from discord.ext import commands, tasks
import asyncio
intents = discord.Intents.default()
intents.message_content = True
intents.members = True
bot = commands.Bot(command_prefix='.', intents=intents)
Count = 0
#bot.command()
async def crypto_statistic(ctx):
while True:
global Count
await bot.wait_until_ready()
session = requests_html.HTMLSession()
r = session.get('https://www.coingecko.com/en/coins/bitcoin') #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ListOfStatistic = []
#Цена
for item in r.html.xpath('/html/body/div[5]/div[5]/div[1]/div/div[1]/div[3]/div/div[1]/span[1]/span'):
Price = item.text
#Процент за 1 час
for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[1]/span'):
ListOfStatistic.append("1h: " + item.text)
#Процент за 24 часа
for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[2]/span'):
h24 = item.text
ListOfStatistic.append("24h: " + item.text)
#Процент за 7 дней
for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[3]/span'):
ListOfStatistic.append("7d: " + item.text)
#Процент за 30 дней
for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[5]/span'):
ListOfStatistic.append("30d: " + item.text)
#Процент за год
for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[1]/div[3]/div[2]/div[6]/span'):
ListOfStatistic.append("1y: " + item.text)
#Лоу за 24 часа
for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[3]/div[2]/div[1]/table/tbody/tr[2]/td/span/span/span[1]'):
ListOfStatistic.append("24h Low: " + item.text)
#Макс за 24 часа
for item in r.html.xpath('/html/body/div[5]/div[7]/div[1]/div/div/div/div[1]/div[1]/div[3]/div[2]/div[1]/table/tbody/tr[2]/td/span/span/span[2]'):
ListOfStatistic.append("24h High: " + item.text)
guild = discord.utils.get(bot.guilds, name="тесты") #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
member = guild.get_member(1066093484890656951) #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if float(h24[:-1]) >= 0:
await member.edit(nick = Price + " (↗)")
else:
await member.edit(nick = Price + " (↘)")
if Count == 6:
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name = ListOfStatistic[Count]))
print(1)
Count = 0
await asyncio.sleep(3)
else:
await bot.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name = ListOfStatistic[Count]))
print(2)
Count += 1
await asyncio.sleep(3)
#bot.event
async def on_ready():
await crypto_statistic(bot.get_context)
if __name__ == "__main__":
bot.run('MyTokenHere') #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
I tried many ways, I also looped this command through #tasks.loop and it didn't work. Some ways helped, but then my stats in bot activity which should go in that order: 1h, 24h, 7d, 30d, 1y..., went in the same order but some stats were just missing and not displayed in bot activity!
The HTTP status 429 means Too many requests, as you can see here. The Discord API has a limit to the number of requests you can make in a given time. A smart thing you can do is to intercept the status code of the response, and whether it's 429 then you do a sleep() and then redo the request!
Like so (this is a pseudo-code):
request_url = ""
request_headers = {}
response = discord_requests.get(url, headers)
if response.status_code == "429"
sleep(5)
response = discord_requests.get(url, headers)
Note that this isn't the best practice. the best practice is to know the exact amount of requests that the API can handle, calculate how many requests your script can do in that time and put a sleep()
I don't precisely know how to get the status code from the request, but through debug it should be pretty simple to understand!
Indeed, I had to do something exactly like this for a data-import script, using requests library.
I'm new to programming and I'm trying to implement function to my Telegram bot, which should check data from database, compare time and send notification if time has come.
However I have this type of mistake:
DeprecationWarning: There is no current event loop loop =
asyncio.get_event_loop()
Here is a function code:
async def run_notify():
while True:
base = sq.connect("actions.db")
cur = base.cursor()
all_data = cur.execute("SELECT * FROM actions").fetchall()
delta = timedelta(days=1)
for each_train in all_data:
each_train = str(each_train)
each_train = re.sub("[(|)|'|,]", "", each_train)
data_info = datetime.strptime(each_train, "%d %m %Y %H:%M")
today = datetime.now()
if today == (data_info - delta):
await bot.send_message(chat_id=-530468333, text= f"Reminder {data_info}")
await asyncio.sleep(1)
And the main part:
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.create_task(run_notify())
executor.start_polling(dp, skip_updates=True, on_startup=on_startup)
How can I fix this Error and are there any other possible ways to implement Notifications?
Thanks
I'm trying to make a queue command but these two parts wont work {0.source.title} and {0.source.url} keep giving me this error
embed = (discord.Embed(description=f'**Music Queue ({len(ctx.voice_state.songs)} track)**\n**Now Playing:**\n[{0.source.title}]({0.source.url}) {self.source.duration_left} Left\n{queue}', color = discord.Colour.dark_red())
Error:
Unexpected token at end of expression Pylance [427, 144]
Here is the full code:
#commands.command(name='queue')
async def _queue(self, ctx: commands.Context, *, page: int = 1):
"""Shows the player's queue.
You can optionally specify the page to show. Each page contains 10 elements.
"""
source = self.source
if len(ctx.voice_state.songs) == 0:
return await ctx.send('Empty queue.')
items_per_page = 10
pages = math.ceil(len(ctx.voice_state.songs) / items_per_page)
start = (page - 1) * items_per_page
end = start + items_per_page
queue = ''
for i, song in enumerate(ctx.voice_state.songs[start:end], start=start):
queue += '`{0}` [**{1.source.title}**]({1.source.url})\n'.format(i + 1, song)
if queue == 1:
embed = (discord.Embed(description=f'**Music queue ({{len(ctx.voice_state.songs)}} track)**\n**Now Playing:**\n[{0.source.title}]({0.source.url}) {self.source.duration_left} Left\n{queue}', color = discord.Colour.dark_red())
.set_footer(text='Viewing page {}/{}'.format(page, pages)))
await ctx.send(embed=embed)
else:
embed = (discord.Embed(description=f'**Music Queue ({len(ctx.voice_state.songs)} tracks)**\n**Now Playing:**\n[{0.source.title}]({0.source.url}) {self.source.duration_left} Left\n{queue}', color = discord.Colour.dark_red())
.set_footer(text='Viewing page {}/{}'.format(page, pages)))
await ctx.send(embed=embed)
I' trying to listen to two websockets at the same time with asyncio. This doesn't work. How can I do this?
I want to get whichever messages comes first, and print it out.
async with websockets.connect(sock_uri_1) as w1, \
websockets.connect(sock_uri_2) as w2:
msg1 = ensure_future(w1.recv())
msg2 = ensure_future(w2.recv())
while True:
if msg1.done():
print(msg1.result())
msg1 = ensure_future(w1.recv())
if msg2.done():
print(msg1.result())
msg2 = ensure_future(w2.recv())
time.sleep(1) # Want to avoid this!
First, you should use await asyncio.sleep(1) rather than time.sleep(1). Your approach can work without sleeping by using asyncio.wait(when_done=FIRST_COMPLETED) to wait for one (or both) of the messages to arrive:
async with websockets.connect(sock_uri_1) as w1, \
websockets.connect(sock_uri_2) as w2:
msg1 = ensure_future(w1.recv())
msg2 = ensure_future(w2.recv())
while True:
await asyncio.wait([msg1, msg2], when_done=asyncio.FIRST_COMPLETED)
if msg1.done():
print(msg1.result())
msg1 = ensure_future(w1.recv())
if msg2.done():
print(msg1.result())
msg2 = ensure_future(w2.recv())
I find managing explicit tasks somewhat tedious, especially when the number of sources can vary. In this case I'd use a queue to combine the messages into a single channel:
async with websockets.connect(sock_uri_1) as w1, \
websockets.connect(sock_uri_2) as w2:
channel = asyncio.Queue()
async def transmit(w, source):
while True:
msg = await w.recv()
await channel.put((source, msg))
asyncio.create_task(transmit(w1, 'source1')
asyncio.create_task(transmit(w2, 'source2')
while True:
source, msg = await channel.get()
if source == 'source1':
print(sock_uri_1, msg)
elif source == 'source2':
print(sock_uri_2, msg)
I have a Django project with Tornado websocket opened and is subscribed to a topic in my Redis Pub/Sub. I am using asyncio and aioredis. Before page refresh, browser close or navigation out of that page, I will call for the websocket to close, which will unsubscribe from that topic.
The issue here is sometimes when I change pages or refresh the page, a bunch of messages from the past will be pumped back into the newly opened websocket. It doesn't happen every time, and I'm not sure what else I can do to make sure the past messages don't come back on page refresh. I've already made sure the websocket will close and unsubscribe from the topic on page refresh/window unload.
Does Redis Pub/Sub keep old messages somewhere while the client is unsubscribed? And when the client subscribes back to the same topic, the old messages are sent out? Is this normal behaviour for Redis Pub/Sub? I'm under the impression that Redis Pub/Sub doesn't persist messages and if client is unsubscribed, the messages just get dropped for that client.
I need to make sure when page reloads, the old messages don't get pumped back to the websocket.
This is how I wrote the RedisChannel to execute the pub/sub functions:
import aioredis
class RedisChannel(object):
'''
Redis backed pub-sub websocket channel.
'''
async def subscribe(self, **kwargs):
'''
Subscribe to topics
'''
topics = kwargs.get('topics')
return await self.conn.subscribe(*topics)
async def unsubscribe(self, **kwargs):
'''
Unsubscribe to topics
'''
topics = kwargs.get('topics')
return await self.conn.unsubscribe(*topics)
async def send(self, **kwargs):
data = {}
# If client socket is provided, only send to this socket.
ws = kwargs.get('ws')
# Topic for this message. Compulsory for broadcast.
topic = kwargs.get('topic')
# Usually JSON
if kwargs.get('data'):
data['data'] = kwargs.get('data')
# I'm using 60 seconds right now just to try to limit the list of past messages
# But the behaviour I need is 0 past messages on page reload in browser
push_event = True
if kwargs.get('timestamp'):
event_timestamp = kwargs.get("timestamp", 0)
data['timestamp'] = event_timestamp
# logger.debug(data)
current_time = timezone.now()
if event_timestamp:
event_dt = get_utc_time(datetime.utcfromtimestamp(event_timestamp))
if event_dt:
time_apart = current_time - event_dt
duration = abs(time_apart.total_seconds())
logger.debug("Time apart between event and current time = {}".format(duration))
if duration >= 60:
push_event = False
if not push_event:
data = {}
return await self.conn.publish_json(topic, json.dumps(data, separators=(',', ': ')))
async def connect(self):
redis_settings = settings['redis']['channel']
self.conn = await aioredis.create_redis_pool(
(
redis_settings.get('host'),
redis_settings.get('port')
),
db=redis_settings.get('db'),
minsize=2,
maxsize=redis_settings.get('max_connections'),
encoding='utf-8'
)
This is how I wrote the websocket handler to subscribe/unsubscribe to a Redis topic:
import asyncio, json
ws_channel = RedisChannel()
asyncio.get_event_loop().create_task(ws_channel.connect())
async def reader(ch, ws):
while (await ch.wait_message()):
data = await ch.get_json()
if data:
ws.write_message(data)
await asyncio.sleep(0.001)
# time.sleep
class ResultsWsHandler(tornado.websocket.WebSocketHandler):
def open(self):
try:
self.write_message(json.dumps('Websocket opened.'))
except Exception as e:
logger.error(str(e))
def on_message(self, message):
asyncio.ensure_future(self.on_message_async(message))
async def on_message_async(self, message):
# async def on_message(self, message):
data = json.loads(message)
action = data.get('action', None)
topics = data.get('cameras', [])
if topics or action is not None:
try:
action = int(action)
if action == 0: # 0 - heartbeat
logger.debug('Heartbeat.')
param = {'type': 0}
self.write_message(json.dumps(param))
elif action == 1: # 1 - subscribe
channels = await ws_channel.subscribe(topics=topics)
logger.debug(f'Successfully subscribed from {topics}.')
self.write_message(json.dumps(f'Successfully subscribed to {topics}.'))
task_list = []
for c in channels:
task_list.append(asyncio.ensure_future(reader(c, self)))
await asyncio.wait(task_list)
elif action == 2: # 2 - unsubscribe
await ws_channel.unsubscribe(topics=topics)
logger.debug(f'Successfully unsubscribe from {topics}.')
self.write_message(json.dumps(f'Successfully unsubscribe from {topics}.'))
else:
logger.debug(f'Other: {data}')
except Exception as e:
logger.error(json.dumps(str(e), separators=(',', ': ')))
self.write_message(json.dumps(str(e), separators=(',', ': ')))