HTML Diff
1 added 1 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#статьи</a></p>
1 <p><a>#статьи</a></p>
2 <ul><li>17 окт 2022</li>
2 <ul><li>17 окт 2022</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><p>Собираем данные о подписчиках телеграм-каналов и чатов с помощью библиотеки Telethon.</p>
4 </ul><p>Собираем данные о подписчиках телеграм-каналов и чатов с помощью библиотеки Telethon.</p>
5 <p>Иллюстрация: Катя Павловская для Skillbox Media</p>
5 <p>Иллюстрация: Катя Павловская для Skillbox Media</p>
6 <p>Изучает Python, его библиотеки и занимается анализом данных. Любит путешествовать в горах.</p>
6 <p>Изучает Python, его библиотеки и занимается анализом данных. Любит путешествовать в горах.</p>
7 <p>Для анализа телеграм-каналов и чатов используют парсеры данных. Это специальные программы, которые позволяют получить информацию о подписчиках, публикациях и обсуждениях с помощью механизмов самого мессенджера (API). Существует немало коммерческих парсеров, однако создать их можно и самостоятельно - используя специальные библиотеки для языков программирования.</p>
7 <p>Для анализа телеграм-каналов и чатов используют парсеры данных. Это специальные программы, которые позволяют получить информацию о подписчиках, публикациях и обсуждениях с помощью механизмов самого мессенджера (API). Существует немало коммерческих парсеров, однако создать их можно и самостоятельно - используя специальные библиотеки для языков программирования.</p>
8 <p>В этой статье мы научимся работать с библиотекой Telethon для Python, которая автоматизирует работу по сбору данных из мессенджера: напишем на ней простой парсер для получения информации о подписчиках телеграм-групп или каналов. Это первая часть урока - во <a>второй части</a>будем парсить уже сообщения пользователей.</p>
8 <p>В этой статье мы научимся работать с библиотекой Telethon для Python, которая автоматизирует работу по сбору данных из мессенджера: напишем на ней простой парсер для получения информации о подписчиках телеграм-групп или каналов. Это первая часть урока - во <a>второй части</a>будем парсить уже сообщения пользователей.</p>
9 <p>Написать парсер для Telegram можно на любом языке программирования, позволяющем работать с API: Python, JavaScript, Go и так далее. Каждый из них имеет свою универсальную библиотеку для работы с любыми API, а некоторые - даже специализированные библиотеки для Telegram.</p>
9 <p>Написать парсер для Telegram можно на любом языке программирования, позволяющем работать с API: Python, JavaScript, Go и так далее. Каждый из них имеет свою универсальную библиотеку для работы с любыми API, а некоторые - даже специализированные библиотеки для Telegram.</p>
10 <p>Мы остановимся на Python - одном из самых популярных языков программирования. В экосистеме Python есть удобная асинхронная библиотека для работы с API Telegram - Telethon. Её используют для парсинга информации из мессенджера, управления сообществами и создания ботов. У Telethon два больших преимущества:<a>подробная документация</a>и большая популярность в комьюнити. Работает библиотека тоже отлично :)</p>
10 <p>Мы остановимся на Python - одном из самых популярных языков программирования. В экосистеме Python есть удобная асинхронная библиотека для работы с API Telegram - Telethon. Её используют для парсинга информации из мессенджера, управления сообществами и создания ботов. У Telethon два больших преимущества:<a>подробная документация</a>и большая популярность в комьюнити. Работает библиотека тоже отлично :)</p>
11 <p>В мессенджере две сущности: каналы и чаты. Они различаются тем, что в каналах пишут только администратор или модераторы, а в чатах может писать любой пользователь. Нам это интересно потому, что возможности парсинга для них различаются.</p>
11 <p>В мессенджере две сущности: каналы и чаты. Они различаются тем, что в каналах пишут только администратор или модераторы, а в чатах может писать любой пользователь. Нам это интересно потому, что возможности парсинга для них различаются.</p>
12 <p><strong>Канал.</strong>Если к каналу не подключены комментарии, то список пользователей можно спарсить только при выполнении следующих условий:</p>
12 <p><strong>Канал.</strong>Если к каналу не подключены комментарии, то список пользователей можно спарсить только при выполнении следующих условий:</p>
13 <ul><li>это ваш канал;</li>
13 <ul><li>это ваш канал;</li>
14 <li>в нём более 200 подписчиков.</li>
14 <li>в нём более 200 подписчиков.</li>
15 </ul><p>Если одно из условий не выполняется, получить информацию о пользователях будет невозможно. Если же к каналу подключён чат, то работа с ним не отличается от парсинга чатов.</p>
15 </ul><p>Если одно из условий не выполняется, получить информацию о пользователях будет невозможно. Если же к каналу подключён чат, то работа с ним не отличается от парсинга чатов.</p>
16 <p><strong>Чат.</strong>Ограничений на парсинг нет. Главное - чтобы вы были участником этого чата. Если вас в нём нет и он закрыт, спарсить ничего не получится.</p>
16 <p><strong>Чат.</strong>Ограничений на парсинг нет. Главное - чтобы вы были участником этого чата. Если вас в нём нет и он закрыт, спарсить ничего не получится.</p>
17 <p>Перейдём к написанию кода: получим данные для доступа к API Telegram и напишем парсер списка участников.</p>
17 <p>Перейдём к написанию кода: получим данные для доступа к API Telegram и напишем парсер списка участников.</p>
18 <h2><strong>Регистрируемся в разделе инструментов разработчика Telegram</strong></h2>
18 <h2><strong>Регистрируемся в разделе инструментов разработчика Telegram</strong></h2>
19 <p>Для работы с API Telegram нам необходимо получить<strong>api_id</strong><strong></strong>и <strong>api_hash</strong>. Сделать это можно в разделе<a>инструментов разработчика Telegram</a>. Это обязательное действие не только при создании нашего бота, но и при создании любого бота или парсера, который задействует API мессенджера.</p>
19 <p>Для работы с API Telegram нам необходимо получить<strong>api_id</strong><strong></strong>и <strong>api_hash</strong>. Сделать это можно в разделе<a>инструментов разработчика Telegram</a>. Это обязательное действие не только при создании нашего бота, но и при создании любого бота или парсера, который задействует API мессенджера.</p>
20 <p>Переходим по ссылке и авторизуемся, используя номер телефона, привязанный к вашему профилю в мессенджере. После авторизации необходимо выбрать пункт API development tools:</p>
20 <p>Переходим по ссылке и авторизуемся, используя номер телефона, привязанный к вашему профилю в мессенджере. После авторизации необходимо выбрать пункт API development tools:</p>
21 <em>Скриншот: Telethon / Skillbox Media</em><p>В открывшейся форме заполняем пустые поля. Всё заполнять необязательно, главное - указать полное и краткое имя приложения:</p>
21 <em>Скриншот: Telethon / Skillbox Media</em><p>В открывшейся форме заполняем пустые поля. Всё заполнять необязательно, главное - указать полное и краткое имя приложения:</p>
22 <em>Скриншот: Telethon / Skillbox Media</em><p>После нажатия Create application откроется страница, на которой нас интересует два параметра:</p>
22 <em>Скриншот: Telethon / Skillbox Media</em><p>После нажатия Create application откроется страница, на которой нас интересует два параметра:</p>
23 <ul><li><strong>api-id</strong> - 18377495;</li>
23 <ul><li><strong>api-id</strong> - 18377495;</li>
24 <li><strong>api-hash</strong> - a0c785ad0fd3e92e7c131f0a70987987.</li>
24 <li><strong>api-hash</strong> - a0c785ad0fd3e92e7c131f0a70987987.</li>
25 </ul><p><strong>Важно!</strong></p>
25 </ul><p><strong>Важно!</strong></p>
26 <p>Не отправляйте свои api-id и api-hash третьим лицам. Их могут использовать для работы с мессенджером от вашего имени.</p>
26 <p>Не отправляйте свои api-id и api-hash третьим лицам. Их могут использовать для работы с мессенджером от вашего имени.</p>
27 <p>Для написания кода парсера мы будем использовать Visual Studio Code. Это стандартная IDE, которую можно заменить на любую другую - например, на PyCharm или онлайн-редактор типа Google Colab.</p>
27 <p>Для написания кода парсера мы будем использовать Visual Studio Code. Это стандартная IDE, которую можно заменить на любую другую - например, на PyCharm или онлайн-редактор типа Google Colab.</p>
28 <p>Если вы никогда не работали на своём компьютере с Python, его будет необходимо установить. Сделать это проще всего<a>по нашей инструкции</a>.</p>
28 <p>Если вы никогда не работали на своём компьютере с Python, его будет необходимо установить. Сделать это проще всего<a>по нашей инструкции</a>.</p>
29 <p>Теперь откроем вкладку "Терминал" в нашей IDE и установим библиотеку для парсинга данных:</p>
29 <p>Теперь откроем вкладку "Терминал" в нашей IDE и установим библиотеку для парсинга данных:</p>
30 python3 -m pip install telethon<p>Импортируем её и дополнительные библиотеки:</p>
30 python3 -m pip install telethon<p>Импортируем её и дополнительные библиотеки:</p>
31 from telethon.sync import TelegramClient import csv from telethon.tl.functions.messages import GetDialogsRequest from telethon.tl.types import InputPeerEmpty<p>Разберём все импорты построчно:</p>
31 from telethon.sync import TelegramClient import csv from telethon.tl.functions.messages import GetDialogsRequest from telethon.tl.types import InputPeerEmpty<p>Разберём все импорты построчно:</p>
32 <ul><li>from telethon.sync import TelegramClient - класс, позволяющий нам подключаться к клиенту мессенджера и работать с ним;</li>
32 <ul><li>from telethon.sync import TelegramClient - класс, позволяющий нам подключаться к клиенту мессенджера и работать с ним;</li>
33 <li>from telethon.tl.functions.messages import GetDialogsRequest - функция, позволяющая работать с сообщениями в чате;</li>
33 <li>from telethon.tl.functions.messages import GetDialogsRequest - функция, позволяющая работать с сообщениями в чате;</li>
34 <li>from telethon.tl.types import InputPeerEmpty - конструктор для работы с InputPeer, который передаётся в качестве аргумента в GetDialogsRequest;</li>
34 <li>from telethon.tl.types import InputPeerEmpty - конструктор для работы с InputPeer, который передаётся в качестве аргумента в GetDialogsRequest;</li>
35 <li>import csv - библиотека для работы с файлами в формате CSV.</li>
35 <li>import csv - библиотека для работы с файлами в формате CSV.</li>
36 </ul><p>После импорта библиотек запустим клиент Telegram API. Для этого добавим код с нашими api-id, api-hash и номером телефона:</p>
36 </ul><p>После импорта библиотек запустим клиент Telegram API. Для этого добавим код с нашими api-id, api-hash и номером телефона:</p>
37 api_id = 18377495 api_hash = 'a0c785ad0fd3e92e7c131f0a70987987' phone = 'ваш номер телефона, привязанный к профилю' client = TelegramClient(phone, api_id, api_hash)<p>Теперь остаётся запустить клиент:</p>
37 api_id = 18377495 api_hash = 'a0c785ad0fd3e92e7c131f0a70987987' phone = 'ваш номер телефона, привязанный к профилю' client = TelegramClient(phone, api_id, api_hash)<p>Теперь остаётся запустить клиент:</p>
38 client.start()<p>Сохраним и запустим код парсера. В терминале нам предложат ввести номер телефона, который мы использовали для получения api-id и api-hash, а после этого в мессенджер придёт пятизначный код, который также потребуется вести. Важно, что номер мы вводим без символа +. Если данные верны, появится сообщение о том, что авторизация прошла успешно:</p>
38 client.start()<p>Сохраним и запустим код парсера. В терминале нам предложат ввести номер телефона, который мы использовали для получения api-id и api-hash, а после этого в мессенджер придёт пятизначный код, который также потребуется вести. Важно, что номер мы вводим без символа +. Если данные верны, появится сообщение о том, что авторизация прошла успешно:</p>
39 <em>Скриншот: Telethon / Skillbox Media</em><p>После входа в систему в папке с кодом появится файл .session. Это файл базы данных, который делает сессию постоянной, то есть как бы не даёт нам разлогиниться. База данных благодаря библиотеке Telethon создаётся автоматически (формат - SQLite) - в ней хранится информация о текущей сессии парсинга: хеш, IP-адрес, с которого она производится, время сессии и другие технические данные подключения.</p>
39 <em>Скриншот: Telethon / Skillbox Media</em><p>После входа в систему в папке с кодом появится файл .session. Это файл базы данных, который делает сессию постоянной, то есть как бы не даёт нам разлогиниться. База данных благодаря библиотеке Telethon создаётся автоматически (формат - SQLite) - в ней хранится информация о текущей сессии парсинга: хеш, IP-адрес, с которого она производится, время сессии и другие технические данные подключения.</p>
40 <p>Будем собирать информацию из чатов, на которые подписан пользователь. Это удобно, так как позволяет обращаться к ним, не указывая конкретный адрес, а выбирая из списка.</p>
40 <p>Будем собирать информацию из чатов, на которые подписан пользователь. Это удобно, так как позволяет обращаться к ним, не указывая конкретный адрес, а выбирая из списка.</p>
41 <p>Начнём с создания пустых списков, которые пригодятся для хранения списка чатов, и инициализируем две переменные (они используются для фильтрации чатов):</p>
41 <p>Начнём с создания пустых списков, которые пригодятся для хранения списка чатов, и инициализируем две переменные (они используются для фильтрации чатов):</p>
42 chats = [] last_date = None size_chats = 200 groups=[]<p>Теперь создадим два списка: chats и groups. Первый будем использовать, чтобы получать список чатов. А во второй будем складывать список чатов после проверки. Кроме того, ограничим максимальное количество получаемых групп с помощью переменной size_chats (присвоим ей значение 200) и создадим переменную last_date со значением None, которой воспользуемся позже.</p>
42 chats = [] last_date = None size_chats = 200 groups=[]<p>Теперь создадим два списка: chats и groups. Первый будем использовать, чтобы получать список чатов. А во второй будем складывать список чатов после проверки. Кроме того, ограничим максимальное количество получаемых групп с помощью переменной size_chats (присвоим ей значение 200) и создадим переменную last_date со значением None, которой воспользуемся позже.</p>
43 <p>Напишем запрос для получения списка групп:</p>
43 <p>Напишем запрос для получения списка групп:</p>
44 result = client(GetDialogsRequest( offset_date=last_date, offset_id=0, offset_peer=InputPeerEmpty(), limit=size_chats, hash = 0 )) chats.extend(result.chats)<p>offset_date и offset_peer мы передаём с пустыми значениями. Обычно они используются для фильтрации полученных данных, но здесь мы хотим получить весь список. Лимит по количеству элементов в ответе задаём 200, передавая в параметр limit переменную size_chats.</p>
44 result = client(GetDialogsRequest( offset_date=last_date, offset_id=0, offset_peer=InputPeerEmpty(), limit=size_chats, hash = 0 )) chats.extend(result.chats)<p>offset_date и offset_peer мы передаём с пустыми значениями. Обычно они используются для фильтрации полученных данных, но здесь мы хотим получить весь список. Лимит по количеству элементов в ответе задаём 200, передавая в параметр limit переменную size_chats.</p>
45 <p>Так как мы планируем, что парсер будет работать только с каналами, а не с личными чатами (то есть перепиской) пользователя, необходимо добавить ещё одну проверку:</p>
45 <p>Так как мы планируем, что парсер будет работать только с каналами, а не с личными чатами (то есть перепиской) пользователя, необходимо добавить ещё одну проверку:</p>
46 for chat in chats: try: if chat.megagroup== True: groups.append(chat) except: continue<p>Проверка работает очень просто: если у группы будет стандартный параметр megagroup, то мы добавляем её в наш список. Если параметра нет, мы пропускаем группу.</p>
46 for chat in chats: try: if chat.megagroup== True: groups.append(chat) except: continue<p>Проверка работает очень просто: если у группы будет стандартный параметр megagroup, то мы добавляем её в наш список. Если параметра нет, мы пропускаем группу.</p>
47 <p>Настроим выведение списка всех полученных групп, чтобы пользователь мог самостоятельно выбрать нужную. Создадим простой цикл, который выведет названия групп с их номерами:</p>
47 <p>Настроим выведение списка всех полученных групп, чтобы пользователь мог самостоятельно выбрать нужную. Создадим простой цикл, который выведет названия групп с их номерами:</p>
48 print('Выберите номер группы из перечня:') i=0 for g in groups: print(str(i) + '- ' + g.title) i+=1<p>Теперь дадим пользователю возможность выбрать нужную группу из списка для последующего парсинга:</p>
48 print('Выберите номер группы из перечня:') i=0 for g in groups: print(str(i) + '- ' + g.title) i+=1<p>Теперь дадим пользователю возможность выбрать нужную группу из списка для последующего парсинга:</p>
49 g_index = input("Введите нужную цифру: ") target_group=groups[int(g_index)]<p>Теперь всё готово к парсингу.</p>
49 g_index = input("Введите нужную цифру: ") target_group=groups[int(g_index)]<p>Теперь всё готово к парсингу.</p>
50 <p>Перейдём к парсингу. Напишем код и разберёмся в его логике:</p>
50 <p>Перейдём к парсингу. Напишем код и разберёмся в его логике:</p>
51 print('Узнаём пользователей...') all_participants = [] all_participants = client.get_participants(target_group) print('Сохраняем данные в файл...') with open("members.csv","w",encoding='UTF-8') as f: writer = csv.writer(f,delimiter=",",lineterminator="\n") writer.writerow(['username','name','group']) 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,name,target_group.title]) print('Парсинг участников группы успешно выполнен.')<p>В первой части кода мы создаём переменную all_participants, в которой сохраняем данные пользователей, полученные в результате парсинга. Сам парсинг происходит в одну строку - мы используем стандартный метод Telethon client.get_participants(), где в скобках передаём целевую группу или канал, откуда хотим парсить данные.</p>
51 print('Узнаём пользователей...') all_participants = [] all_participants = client.get_participants(target_group) print('Сохраняем данные в файл...') with open("members.csv","w",encoding='UTF-8') as f: writer = csv.writer(f,delimiter=",",lineterminator="\n") writer.writerow(['username','name','group']) 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,name,target_group.title]) print('Парсинг участников группы успешно выполнен.')<p>В первой части кода мы создаём переменную all_participants, в которой сохраняем данные пользователей, полученные в результате парсинга. Сам парсинг происходит в одну строку - мы используем стандартный метод Telethon client.get_participants(), где в скобках передаём целевую группу или канал, откуда хотим парсить данные.</p>
52 <p>После этого переходим к сохранению данных в файл формата CSV. Для этого мы используем стандартный модуль csv, позволяющий работать с этим типом файлов. Подробнее о модуле можно узнать<a>из его документации</a>.</p>
52 <p>После этого переходим к сохранению данных в файл формата CSV. Для этого мы используем стандартный модуль csv, позволяющий работать с этим типом файлов. Подробнее о модуле можно узнать<a>из его документации</a>.</p>
53 <p>Для начала откроем файл в режиме записи (если файла с таким названием в директории нет, он автоматически создаётся), явно указав кодировку UTF-8. Это важно, так как пользователи в мессенджере часто устанавливают себе имена не в кодировке ASCII. Затем создадим объект CSV writer и запишем первую строку (заголовок) в CSV-файл. Теперь остаётся пройтись по каждому элементу списка all_participants и записать все элементы в CSV-файл.</p>
53 <p>Для начала откроем файл в режиме записи (если файла с таким названием в директории нет, он автоматически создаётся), явно указав кодировку UTF-8. Это важно, так как пользователи в мессенджере часто устанавливают себе имена не в кодировке ASCII. Затем создадим объект CSV writer и запишем первую строку (заголовок) в CSV-файл. Теперь остаётся пройтись по каждому элементу списка all_participants и записать все элементы в CSV-файл.</p>
54 <p>Парсим для каждого участника его юзернейм, имя и название группы. Так как имя может состоять из имени и фамилии, то для присвоения значения конечной переменной name воспользуемся конкатенацией строк, объединив имя и фамилию в одну строку.</p>
54 <p>Парсим для каждого участника его юзернейм, имя и название группы. Так как имя может состоять из имени и фамилии, то для присвоения значения конечной переменной name воспользуемся конкатенацией строк, объединив имя и фамилию в одну строку.</p>
55 <p><strong>Важно!</strong></p>
55 <p><strong>Важно!</strong></p>
56 <p>Не каждый пользователь имеет юзернейм, видимый для нас. Если у пользователя нет юзернейма, API вернёт None. Чтобы избежать записи None, явно укажем в условиях добавление вместо этого пустой строки. Аналогичную опцию сделаем для имени и фамилии.</p>
56 <p>Не каждый пользователь имеет юзернейм, видимый для нас. Если у пользователя нет юзернейма, API вернёт None. Чтобы избежать записи None, явно укажем в условиях добавление вместо этого пустой строки. Аналогичную опцию сделаем для имени и фамилии.</p>
57 <p>Теперь запустим и проверим работоспособность нашего парсера. Для этого открываем терминал и переходим в папку, где сохранён наш код:</p>
57 <p>Теперь запустим и проверим работоспособность нашего парсера. Для этого открываем терминал и переходим в папку, где сохранён наш код:</p>
58 <em>Скриншот: Telethon / Skillbox Media</em><p>Запустим файл main.py. Для этого напишем в терминале:</p>
58 <em>Скриншот: Telethon / Skillbox Media</em><p>Запустим файл main.py. Для этого напишем в терминале:</p>
59 python3 main.py<p>В ответ на это мы получим запрос на выбор группы для парсинга:</p>
59 python3 main.py<p>В ответ на это мы получим запрос на выбор группы для парсинга:</p>
60 <em>Скриншот: Telethon / Skillbox Media</em><p>Выберем любую группу, введя в терминал нужную цифру. В нашем случае это будет группа "Вастрик.ЗОЖ".</p>
60 <em>Скриншот: Telethon / Skillbox Media</em><p>Выберем любую группу, введя в терминал нужную цифру. В нашем случае это будет группа "Вастрик.ЗОЖ".</p>
61 <em>Скриншот: Telethon / Skillbox Media</em><p>Теперь мы видим текстовые сообщения, которые "зашивали" в код. И главное, понимаем, что парсинг прошёл удачно.</p>
61 <em>Скриншот: Telethon / Skillbox Media</em><p>Теперь мы видим текстовые сообщения, которые "зашивали" в код. И главное, понимаем, что парсинг прошёл удачно.</p>
62 <p>Откроем нашу папку. В ней появился файл members.csv:</p>
62 <p>Откроем нашу папку. В ней появился файл members.csv:</p>
63 <em>Скриншот: Telethon / Skillbox Media</em><p>Откроем его и посмотрим на содержимое:</p>
63 <em>Скриншот: Telethon / Skillbox Media</em><p>Откроем его и посмотрим на содержимое:</p>
64 Часть файла members.csv<em>Скриншот: Telethon / Skillbox Media</em><p>Всё получилось! В файле мы видим всех пользователей группы с указанием их юзернейма и имени, включающего также фамилию с дополнительными символами.</p>
64 Часть файла members.csv<em>Скриншот: Telethon / Skillbox Media</em><p>Всё получилось! В файле мы видим всех пользователей группы с указанием их юзернейма и имени, включающего также фамилию с дополнительными символами.</p>
65 <p>В <a>следующей части</a>мы научимся парсить сообщения из чатов. Изучим новые методы и объекты библиотеки Telethon и поработаем с форматом JSON, который особенно удобен для хранения текстовой информации.</p>
65 <p>В <a>следующей части</a>мы научимся парсить сообщения из чатов. Изучим новые методы и объекты библиотеки Telethon и поработаем с форматом JSON, который особенно удобен для хранения текстовой информации.</p>
66 <p>Python для всех</p>
66 <p>Python для всех</p>
67 - <p>Вы освоите Python на практике и создадите проекты для портфолио - телеграм-бот, веб-парсер и сайт с нуля. А ещё получите готовый план выхода на удалёнку и фриланс. Спикер - руководитель отдела разработки в "Сбере".</p>
67 + <p>Вы освоите Python на практике и создадите проекты для портфолио - телеграм-бот, веб-парсер и сайт с нуля. А ещё получите готовый пла выхода на удалёнку и фриланс. Спикер - руководитель отдела разработки в "Сбере".</p>
68 <p><a>Пройти бесплатно</a></p>
68 <p><a>Пройти бесплатно</a></p>
69 <a><b>Бесплатный курс по разработке на Python ➞</b>Пройдите бесплатный курс по Python и создайте с нуля телеграм-бот, веб-парсер и сайт. Спикер - руководитель отдела разработки в "Сбере". Пройти курс</a>
69 <a><b>Бесплатный курс по разработке на Python ➞</b>Пройдите бесплатный курс по Python и создайте с нуля телеграм-бот, веб-парсер и сайт. Спикер - руководитель отдела разработки в "Сбере". Пройти курс</a>