<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0">

<channel>

<title>Блог об аналитике, визуализации данных, data science и BI, заметки с тегом: telegram</title>
<link>http://test.leftjoin.ru/tags/telegram/</link>
<description></description>
<generator>E2 (v3365; Aegea)</generator>

<item>
<title>Бот для преобразования данных из Coinkeeper</title>
<guid isPermaLink="false">101</guid>
<link>http://test.leftjoin.ru/all/coinkeeper-data-bot/</link>
<comments>http://test.leftjoin.ru/all/coinkeeper-data-bot/</comments>
<description>
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/@2x-copy.png.jpg" width="2560" height="1707" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://about.coinkeeper.me"&gt;Coinkeeper&lt;/a&gt; — кроссплатформенное приложение для учёта финансов. Внутри можно выпустить виртуальную банковскую карту Visa с бесплатным годовым обслуживанием, которая будет присылать уведомления, если вы тратите больше, чем запланировали. Помимо уведомлений, приложение ведёт историю трат и позволяет выгрузить сводный отчёт в формате csv. Данные, которое выгружает приложение ещё не готовы к анализу и выглядят так:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/1-27.png" width="846" height="647" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Азат Шарипов сделал скрипт обработки данных в пригодный для Tableau вид и подготовил &lt;a href="https://public.tableau.com/profile/azat3313#!/vizhome/CoinKeeperanalytics/Dashboard1"&gt;Tableau Public книгу&lt;/a&gt;, а &lt;a href="https://t.me/revealthedata"&gt;Рома Бунин&lt;/a&gt; в рамках своего проекта «Переверстка» &lt;a href="https://public.tableau.com/profile/roman4734#!/vizhome/CoinKeeper/CoinKeeper"&gt;переработал дашборд&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Мы решили тоже поучаствовать, и с нашей стороны Елизавета Мазурова сделала &lt;a href="https://t.me/coinkeeper_export_bot"&gt;чат-бота&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Чат-бот крутой! Помимо того, что он может как и прежде отдавать обратно .csv-файл, он позволяет автоматизировать рутину по обновлению отчета через Google-таблицы. Как, наверное, многие помнят, Tableau Public может работать на гугл-таблицах или csv файлах, но не разрешает подключение к данным. Бот умный: он создаст за вас гугл-таблицу и когда вы повторно отправите ему новый файл обновит ее.&lt;/p&gt;
&lt;h2&gt;Использование бота&lt;/h2&gt;
&lt;p&gt;Перейдите в диалог с &lt;a href="https://t.me/coinkeeper_export_bot"&gt;ботом&lt;/a&gt; и введите команду /start — в ответе бот расскажет немного о себе. Для продолжения работы нажмите на кнопку «Начать».&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/2-26.png" width="717" height="184" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Сразу после можно отправить csv-файл, выгруженный из Coinkeeper:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/3-22.png" width="489" height="58" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Выберите тип файла — csv или таблицу в Google Spreadsheets.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/4-13.png" width="782" height="174" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;В случае выбора csv-файла бот пришлёт его:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/5-14.png" width="481" height="115" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;А в случае ссылки в первый раз нужно будет пройти небольшую регистрацию — указать почту и наименование для файла.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/6-14.png" width="524" height="56" alt="" /&gt;
&lt;/div&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/7-8.png" width="477" height="57" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Затем бот пришлёт ссылку на файл:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/8-9.png" width="666" height="119" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Скрипт преобразовал данные, и таблицу можно указать в качестве источника данных в Tableau. А благодаря тому, что в случае загрузки нового файла создаётся не новая таблица, а обновляется старая, отчёт в Tableau тоже обновится. В результате открывается возможность еженедельно присылать боту новую таблицу и сразу переходить в обновлённый отчёт.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/9-8.png" width="1217" height="432" alt="" /&gt;
&lt;/div&gt;
</description>
<pubDate>Tue, 09 Mar 2021 17:28:36 +0300</pubDate>
</item>

<item>
<title>Сбор информации о подписчиках Telegram-канала</title>
<guid isPermaLink="false">95</guid>
<link>http://test.leftjoin.ru/all/tg-api-parse/</link>
<comments>http://test.leftjoin.ru/all/tg-api-parse/</comments>
<description>
&lt;p&gt;На 2021 год боты в Telegram так и не имеют метода, позволяющего получать информацию о подписчиках канала. Тем не менее, существует достаточно сложное в освоении Telegram API и построенная на нём библиотека Telethon. Сегодня мы посмотрим, как при помощи библиотеки выгрузить информацию о подписчиках своего канала.&lt;/p&gt;
&lt;h2&gt;Создание приложения&lt;/h2&gt;
&lt;p&gt;Для начала необходимо создать приложение, через которое будут отправляться запросы к API. Перейдите на &lt;a href="https://my.telegram.org"&gt;https://my.telegram.org&lt;/a&gt; и авторизуйтесь в Telegram-аккаунте:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/1-24.png" width="532" height="299" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;После успешной авторизации перейдите на страницу API development tools:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/2-22.png" width="397" height="190" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Заполните все поля и жмите на создание приложения:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/3-20.png" width="645" height="478" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Из полученной конфигурации нам необходим app api_id и app api_hash:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/5-13.png" width="629" height="123" alt="" /&gt;
&lt;/div&gt;
&lt;h2&gt;Запрос к API&lt;/h2&gt;
&lt;p&gt;Импортируем telethon — он поможет сформировать запрос, и pandas — полученный ответ мы запишем в DataFrame.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;from telethon import TelegramClient
import pandas as pd&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Вводим api_id, api_hash, наш номер телефона и ссылку на канал, информацию о подписчиках которого хотим получить. Доступ к информации о подписчиках есть только у администраторов канала.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;api_id = 1234567
api_hash = '1b42hj25kd8jw42b234kwj242c'
phone = '+71234567890'
channel_href = 'https://t.me/leftjoin'&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Создаём новую сессию — вместо session_name можно подставить любое другое название. Методы в библиотеке работают асинхронно, поэтому ответа от них требуется ожидать:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;client = TelegramClient('session_name', api_id, api_hash)
client = await client.start()
dialogs = await client.get_dialogs()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Собираем все каналы текущего пользователя. Из ссылки забираем часть с именем канала и вытаскиваем из словаря нужный:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;channels = {d.entity.username: d.entity
            for d in dialogs
            if d.is_channel}
my_channel = channel_href.split('/')[-1]
channel = channels[my_channel]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Подписчиков, доступ к которым не ограничен приватностью, можно получить методом get_participants. С 20 июля 2018 года Telegram установил ограничение в 200 подписчиков для вызова метода, и установка параметра aggressive на True поможет получить всех подписчиков за раз.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;members_telethon_list = await client.get_participants(channel, aggressive=True)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Из полученных библиотечных структур извлекаем информацию о пользователях — их имена и телефоны:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;username_list = [member.username for member in members_telethon_list]
first_name_list = [member.first_name for member in members_telethon_list]
last_name_list = [member.last_name for member in members_telethon_list]
phone_list = [member.phone for member in members_telethon_list]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Из четырёх списков собираем DataFrame и пишем его в csv-таблицу:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;df = pd.DataFrame()
df['username'] = username_list
df['first_name'] = first_name_list
df['last_name'] = last_name_list
df['phone'] = phone_list
df.to_csv('subscribers.csv', index=False)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Результат работы — такая таблица:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="http://test.leftjoin.ru/pictures/6-13.png" width="327" height="191" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Для запуска в Jupyter Notebook описанный ниже код можно просто вставить в ячейку, но при запуске из Python-файла будет такая ошибка:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;SyntaxError: 'await' outside function&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Устранить проблему можно, записав весь код в асинхронную функцию. Целиком выглядеть код будет так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code&gt;from telethon import TelegramClient
import pandas as pd
import asyncio

async def main():
        api_id = 1234567
        api_hash = '1b42hj25kd8jw42b234kwj242c'
        phone = '+71234567890'
        channel_href = 'https://t.me/leftjoin'

	client = TelegramClient('session_name', api_id, api_hash)
	client = await client.start()
	dialogs = await client.get_dialogs()

	channels = {d.entity.username: d.entity
				for d in dialogs
				if d.is_channel}
	my_channel = channel_href.split('/')[-1]
	channel = channels[my_channel]

	members_telethon_list = await client.get_participants(channel, aggressive=True)

	username_list = [member.username for member in members_telethon_list]
	first_name_list = [member.first_name for member in members_telethon_list]
	last_name_list = [member.last_name for member in members_telethon_list]
	phone_list = [member.phone for member in members_telethon_list]

	df = pd.DataFrame()
	df['username'] = username_list
	df['first_name'] = first_name_list
	df['last_name'] = last_name_list
	df['phone'] = phone_list
	df.to_csv('subscribers.csv', index=False)

if __name__ == '__main__':
	loop = asyncio.get_event_loop()
	loop.run_until_complete(main())&lt;/code&gt;&lt;/pre&gt;</description>
<pubDate>Mon, 08 Feb 2021 15:19:17 +0300</pubDate>
</item>


</channel>
</rss>