Дневник разработчицы
407 subscribers
111 photos
9 videos
14 files
145 links
Откровенные истории о проектах, работе, учебе и открытиях в мире программирования. Присоединяйтесь и вдохновляйтесь вместе со мной!
Download Telegram
В одном из моих проектов есть функционал сбора новостей из разных rss-каналов. Да, rss все еще живы. Я обрабатываю более 140 источников. Тут наткнулась на сайт https://sledcom.ru, увидела у них rss, но, видимо, не судьба... Все мои попытки достучаться до них были обречены на провал.

В браузере все открывается ок, на сертификат нареканий нет, а вот при запросе через requests падает ошибка [SSL: WRONG_SIGNATURE_TYPE]. Все мои попытки отключить валидацию сертификата были провальными. Мои попытки и ошибка: https://pastebin.com/DXnFZidT

Такие дела.
Недавно в своем проекте поженила асинхронный telethon с django3.1. Авторизацию сделала на коленке через админку.
Честно, понимаю, что можно было бы нормально через view с шаблончиками, но не хотелось заморачиваться. Поэтому сделала очень примитивно с помощью логики, зашитой в обработку полей после сохранения нового объекта https://pastebin.com/SJSwhNYG

Жутенький код, конечно, но он работает. Локально все заработало прекрасно. Я авторизовала несколько клиентов, запустила их, начала получать от них сообщения (с помощью другого метода).

После деплоя на сервер от aws (я использую elastic beanstalk на базе docker linux) я столкнулась с тем, что, судя по логам, код отправляется, телеграмм возвращает корректный ответ на запрос отправки кода, но вот до пользователя он не доходит. И я такая не одна, судя по гуглу. Создатель библиотеки предлагает создавать сессии локально и загружать их на сервер. Я так и сделала, конечно, в итоге, но это ужасно неудобно.(
Вот описание проблемы на стаковерфлоу https://stackoverflow.com/questions/61293179/code-is-not-delievered-by-sendcoderequest-without-error-and-this-happens-only-on
👍1
Продолжая тему rss и асинхронных задач в django. История про aiohttp и django3.1. Изначально в проекте я сделала логику, в рамках которой периодически запускалась задача на парсинг одной rss-ленты (не чаще, чем раз в минуту). Все мои 140+ rss обходились за 7-12 минут. В принципе, результат был более ли менее. Но потом я начала изучать asyncio и решила попробовать как оно будет работать с rss.
Переделала логику https://pastebin.com/uUheywAE
Задача на парсинг также запускает через celery, как и раньше. Но только запускаю я ее раз в 30 секунд. Получение данных, парсинг и сохранение в бд выполняется за 5-20 секунд (как правило, не все rss сразу). Теперь все rss обрабатываются в течение 2 минут.
Не все rss одинаково классно проходят с помощью этого метода. Некоторые падают по таймауту (единицы). Ради них пришлось оставить старый метод, который добирает остатки необработанных rss.

Хочется выделить курс https://www.udemy.com/course/bestpython/, где автор довольно подробно разобрал тему многопоточности в Python. Хотя, признаю, далеко не все понято с первого раза. Но завтра будет лучше... #Python, #Django
Мои конспекты в Xmind. Они постоянно дополняются и развиваются. Всем рекомендую эту программу, удобно конспектировать, удобно возвращаться к необходимой информации. #Tools
Я за сегодня сделала только 1 маленькую вещь: сделала в боте для генерации utm-меток обрезание всех параметров в исходной ссылке.

Да, у меня есть простой бот в телеграмме для smm-специалистов. Они отправляют боту голые ссылки, а бот им отвечает списками этих ссылок по соответствующими utm-метками для разных соц.сетей. Простая в реализации штука. Для нее нужно уметь работать с api телеграмм https://core.telegram.org/bots/api, также я использовала регулярные выражения для получения ссылки (https://regexr.com/3h8nh здесь можно найти готовые шаблоны и потестировать свои), для хранения и изменения списка меток использую табличку в виде csv-файла. Приложение крутится в AWS Lambda. Я его сделала за пару дней через пару месяцев изучения программирования. Это был уже не первый мой подобный проект.

В общем, в логах к моему приложению было обнаружено, что ребята присылают на вход ссылку с чужими utm-метками. Конечно, неправильно рубить все параметры url, так как там может быть что-то полезное, а стоило бы обрабатывать эту ситуацию с помощью условий, мягче, оставляя полезные параметры. Но, я знаю, что на проекте нет таких, поэтому не стала заморачиваться. Если вдруг понадобится обходить параметры, всегда можно доработать. А так, три строчки кода и проблема решена.

О таких нюансах можно не знать на старте, но при этом на самом деле не страшно запустить приложение с "проблемами", если им уже можно пользоваться и оно уже может решать какие-то задачи эффективнее.

Я что хочу сказать, даже простой функционал может упростить кому-то жизнь. Если вы только в начале пути разработчика, посмотрите вокруг себя, возможно вы можете улучшить жизнь себе и окружающим. В этом же и есть вся прелесть программирования.

Вот пример гайда как сделать простого бота на aws https://dev.to/nqcm/-building-a-telegram-bot-with-aws-api-gateway-and-aws-lambda-27fg
FYI вместо библиотеки requests я использовала встроенную urllib.request, что позволяет делать без дополнительных зависимостей.

https://github.com/mandrianova/telegram_bot а это мой первый проект, который я развиваю до сих пор, но уже на другом технологическом стеке и в рамках другого репозитория. В данном репозитории можно как раз подсмотреть логику работы с lambda. #Работа, #AWS
👍1🔥1
С каждой задачей я все больше начинаю понимать, меньше допускать примитивных ошибок, некоторые вещи перестают быть страшными.

Продолжаю использовать telethon в django. Сегодня делала функционал получения подписок и саму подписку на каналы.


telegram_client = create_client(client.session)
with telegram_client:
dialogs = telegram_client.get_dialogs()
...


def subscribe(client: TelegramBotClient, channel: Channel):
telegram_client = create_client(client.session)
with telegram_client:
result = telegram_client(functions.channels.JoinChannelRequest(f"@{channel.username}"))
add_log("join channel", result)


Простые, казалось бы функции, но для меня стало открытием, что можно использовать with, чтобы создать подключение на время выполнения подписки и получения списка диалогов. Если что это это условно синхронные функции telethon, которые на самом деле также используют asyncio.

Кстати, под капотом create_client зашито создание отдельного event loop для клиента:


api_id = os.getenv('TG_API_ID')
api_hash = os.getenv('TG_API_HASH')
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
client = TelegramClient(StringSession(session), int(api_id), api_hash, loop=loop)
client.parse_mode = 'html' # <- Render things nicely
return client


Теперь можно будет немного поправить функцию авторизации, так как теперь я знаю магию with.
Плюс заметила в логах, что я криво сделала сбор сообщений в каналах, так как на каждое сообщение я запрашивала информацию о чате с помощью бота телеграмма.
Переделала логику, стало немного лучше. Теперь я сначала проверяю наличие чата в своей бд.

Итого за сегодня:
- Примерно набросала в блокноте список функций для подписки
- Создала модель для хранения подписок и добавила ее в админку
- Сделала функцию получения списка подписок для клиента и собрала существующие подписки,
- Написала функцию для подписки и проверила ее, завтра по аналогии допишу функцию отписки

На завтра:
- Доделать логику подписки и отписки, сделать возможность управления через админку
- Автоматизировать подписки на новые каналы
- Выкатить новый функционал "на прод" #Работа
Сегодня уж очень медленно работает подключение к aws. И вот, пока мои обновления пытаются выехать на мой условный прод, я напишу о сегодняшнем дне.

Мой план был доделать подписки и я их доделала. Осталось вот задеплоить.

Теперь можно подписываться и отписываться от каналов вручную и автоматически. Кстати, у телеграмма есть какое-то ограничение на количество подписок в какой-то период времени. После 30 каналов он выплюнул мне предупреждение во флуде и ограничил меня на 300 секунд. Поэтому придется как-то плавно обрабатывать всю ту массу каналов, на которые хочется подписаться.

Меня тут разговоры про ООП заставили задуматься о том, что я с безумной радостью почти весь код пишу функциями. Я подсмотрела в ютубе на канале Диджитализируй идею про то, что логику в Django стоит выносить в папку services, я ее создала и разразилась там в своих проектах на джанге множеством функций. Так вот, сегодня я сделала странную вещь. Не знаю на сколько это вообще легитимно (скорее всего не очень), но я в класс модели для телеграмм клиента перенесла все базовые функции для клиента (подключение, авторизацию, проверку логина, отправку кода, подписку, отписку). Это так удобно, хотя модель стала просто жутко жирной.

Еще один момент про telethon. Ранее я писала про открытие с with. Так вот, сегодня решила отрефакторить свою функцию авторизации и выяснила, что с with библиотека пытается стартануть клиент и требует авторизацию, если нет авторизованной сессии. Пришлось все неавторизованные функции оборачивать самостоятельно в connect и disconnect. Например:



client = self.client
client.connect()
sent = client.send_code_request(phone=self.phone)
add_log(f'sent code {self.phone}', str(sent), 1)
self.session = StringSession.save(client.session)
TelegramBotClient.objects.filter(id=self.id).update(session=self.session)
client.disconnect()
Пока пишу, приложение задеплоилось. Первый выкат прошел не очень, так как я накосячила с миграциями. Решила поправить один момент, сделать проверку на уникальность для связки двух полей в модели сообщений (message_id и chat). Так как в теории в базе могли возникнуть дубли, то в миграции добавила функцию по дедубликации. Так вот, извлекла урок:
- тяжелые миграции лучше делать отдельным файлом миграций. Создать ручную миграцию можно с помощью команды
python manage.py makemigrations --empty yourappname
Про свои функции в миграциях можно почитать тут https://docs.djangoproject.com/en/3.1/ref/migration-operations/#runpython
Я их уже делала ранее для индексации текстов материалов для полнотекстового поиска. Я создала поле SearchVectorField и мне надо было его наполнить для старых материалов.

В этот раз я нашла на просторах интернета готовое решение по дедубликации материалов. Не очень красивое (очень некрасивое), но мне лень было придумывать самой:



Entry = apps.get_model("telegram", "Message")
for row in Entry.objects.all().reverse():
if Entry.objects.filter(message_id=row.message_id, chat=row.chat).count() > 1:
row.delete()
Функция выполняется довольно долго, поэтому при деплое все пошло не так. В логах информации об ошибках не было, только заглянув в таблицу django_migrations я увидела, что моя миграция не прошла. Впрочем, просто сделав запрос в бд, я поняла, что на проде такая дедубликация мне бы и не понадобилась. В итоге я просто повторно выкатила приложение и на второй раз все завелось успешно. Единственное, что я сделала, это перенесла операцию по дедубликации в конец списка, хотя не думаю, что это имело какой-либо смысл. Со второго раза миграции выполнились. #Работа, #AWS, #Django
Ура! Я за 1,5 месяца наконец-то перенесла весь изначальный функционал проекта полностью на сервер. То, что было сделано на коленке за несколько дней и запущено в виде простеньких скриптов на локальном компе, наконец-таки более ли менее оформлено в нормальную управляемую систему. А ведь изначально этим "сервисом" можно было управлять через файл конфига, а запуск проходил с помощью старта скрипта с бесконечным циклом.

Можно открывать шампанское и переходить к улучшению интерфейсов.

Следующий мой шаг - сделать управление через телеграмм бота, чтобы пользователям не нужно было заходить в админку. #Работа
Я - чертов графоман)
😁1
Отгадываю загадки от api телеграмма.

По идее с помощью api бота можно получать информацию о публичных чатах и каналах по chat_id. Id чата может считаться либо цифры идентификатора, либо юзернейм с @. Сообщения по api клиента мне приходят с идентификатором канала. Я подумала, чтобы не напрягать клиент, буду я доставать всю нужную информацию о каналах с помощью бота. Это все присказка. Сказка вот в чем:
- Запрашиваю ботом инфу о канале с помощью идентификатора (метод getChat), получаю 400, канал не найден пишет мне телега
- Нахожу ручками юзернейм этого же канала, запрашиваю тем же ботом, но с помощью юзернейм, получаю нормальный ответ, id сходится.
- Повторно делаю первый запрос, ответ 200, все сходится.

Да что происходит то вообще??!! #Работа
Мда, а я хотела интерфейсами позаниматься. В итоге пришолсь искать вариант реализации для получения данных о новых каналах, как писала выше, api бота не справилось с этой задачей. Настроила в итоге методы get_chat() и forward.get_chat() для получения данных.
Выглядит это примерно так:


async def handler(event):
if hasattr(event.message.to_id, 'channel_id'):
info = await event.message.get_chat()
...

if event.message.fwd_from and event.message.fwd_from.channel_id:
info = await event.message.forward.get_chat()
...


Есть подозрение, что телеграмм за частый запрос информации, может кинуть страйк за флуд. Но пока полет нормальный. Хотя мне не нравится то, как это получилось. Придется еще наводить порядок в этом функционале. А пока отлавливаю страйки и новые каналы.

И еще сегодня проснулись пользователи с новыми хотелками. Беклог подрос. Разработка - процесс бесконечный. #Работа
Меня иногда спрашивают в личку, какой мой путь в программировании.

Обучение:

1. Когда-то давно (несколько лет назад) я проходила курс по основам программирования и кое-что пробовала делать на php и js. У меня даже остались конспекты.

2. Потом пробовала пройти курс джанго герлз, но ничего толком не поняла.
Опять же возвращаясь к питону, начала с джанги (курс по 1.9 типа https://youtu.be/-oQvMHpKkms), но мне посоветовали освоить сначала основы.

3. Дергалась по нескольким базовым курсам, пока не набрела на базовый курс "Полное руководство по Python 3: от новичка до специалиста" (https://www.udemy.com/course/bestpython/), который дал мне хорошую опорную точку. Прошла его за пару недель, буквально почти не вылезая из-за компа.

4. После него начинала курс по алгоритмам, но не прошла его до конца (надеюсь пройду позже) http://judge.mipt.ru/mipt_cs_on_python3/. Остановилась на 7 лекции.

5. Потом мне подкинули курсы cs50. Шикарные, сложные, интересные:
https://cs50.harvard.edu/x/2020/ - прошла полностью, получила сертификат
https://cs50.harvard.edu/web/2020/ - сдала половину проектов, прошла все теорию, потом пришлось переключиться на свои проекты.

Хочу когда-нибудь добраться до их курса по AI

6. Прошла курс по webpack и по docker (уже не помню ссылок), но добралась до того, что могу развернуть себе контейнеры. Основные проекты у меня сейчас на базе докера. Webpack пока почти не использовала.

7. Прошла полностью туториал Create a Twitter-like App with Python Django JavaScript and React. Full TUTORIAL https://youtu.be/f1R_bykXHGE, чтобы потрогать DRF и React. Ни одно, ни другое пока не использую в своих проектах, поэтому имею только поверхностное представление.

8. В планах пройти курс по JS + React. Пока он ждет.

Проекты:

1. У меня были какие-то попытки с php и js. Потом попытки поднять бложек на джанге, но все это было несерьезно.

2. Бот для местного сообщества. Я уже скидывала его первый репозиторий. https://github.com/mandrianova/telegram_bot

3. Проекты для cs50 web (https://github.com/mandrianova/Flack - чат на Flask, https://github.com/mandrianova/books - каталог книг на Flask, и немного верстки на Bootstrap)

4. Мелкие боты (для генерации utm, для оповещения о новых материалах на сайте)

5. Ну и самый мой большой мой проект - система для мониторинга сми, который я делаю последние пару месяцев.

Полноценным стартом изучения программирования считаю весну этого года. Все что было раньше, было несерьезно. #Учеба, #Жизнь, #Курсы
🔥2
А что вы сделали за сегодня? Я вот чутка добавила фильтров в админку, рассказала одному программисту про свой проект и смотрела коня боджека) А ведь хотела посмотреть что-нибудь из курсов. Хехе. Ну, и медитирую на цифры, которые стремительно растут... #Работа
ORM - прекрасная штука, Но сегодня я собирала данные о своей системе для презентации и поэтому пришлось немного пописать на сыром sql. Вот такие запросы у меня сегодня были:
У меня в системе уже больше 0,5 млн разных материалов. Из них около 442 500 собрано за последний месяц. При этом от публикации материала до доставки ее в соответствующую тему сейчас в среднем 73 секунды. Хехей! #Работа
Вот задачка-незадачка. В админке страница с ссылками на локальной машине загружается меньше, чем за секунду (данных всего в 2 раза меньше, чем на сервере), а на сервере за 16 секунд. С остальными страничками в админке такой проблемы не наблюдается.

Пойду запишу себе баг. Если есть идеи в чем может быть проблема - пишите в личку)

Сортировок нет, данных из других моделей на странице не запрашивается.
Есть подозрение, что проблема в самих данных, где-то что-то пошло не так, из-за этого тормозит. Но надо проверять. #Работа
Дневник разработчицы
Вот задачка-незадачка. В админке страница с ссылками на локальной машине загружается меньше, чем за секунду (данных всего в 2 раза меньше, чем на сервере), а на сервере за 16 секунд. С остальными страничками в админке такой проблемы не наблюдается. Пойду…
Сходила в бд, сделала просто select
` select * from data_flow_link order by id desc limit 20;
```Вернулась на страницу, страница загрузилась за 1 секунду. Попробовала использовать поиск из админки, который работает как like, результат отдавался 15 секунд, что в принципе нормально, так как материалов много, а индексации самого текста нет. На тесте такой поиск отрабатывает за 3 секунды.
И что это было? #Работа