🔷 Requests. POST application/json
POST/application-json використовується для надсилання json даних на сервер (REST API)
Замість параметру data треба використовувати параметр json
У цьому випадку бібліотека requests виставляє заголовок:
Реальне API мені не вдалось знайти тому використаємо для прикладу тестове API:
⚠️ Зверніть увагу що статус кодом який повертається може бути 201, а не 200 що відповідає створенню ресурсу.
Основні статус коди
#http #requests #POST
POST/application-json використовується для надсилання json даних на сервер (REST API)
Замість параметру data треба використовувати параметр json
У цьому випадку бібліотека requests виставляє заголовок:
Content-Type: application/jsonРеальне API мені не вдалось знайти тому використаємо для прикладу тестове API:
import requests
url = "https://jsonplaceholder.typicode.com/posts"
json_payload = {
"title": "foo",
"body": "bar",
"userId": 1
}
response = requests.post(url, json=json_payload)
response.raise_for_status()
print(response.status_code)
print(response.json())
201
{'title': 'foo', 'body': 'bar', 'userId': 1, 'id': 101}
⚠️ Зверніть увагу що статус кодом який повертається може бути 201, а не 200 що відповідає створенню ресурсу.
Основні статус коди
#http #requests #POST
👍1
🔶 Requests. POST multipart/form-data
multipart/form-data використовується у формах з надсилання файлів на сервер.
У цьому випадку бібліотека requests виставляє заголовок:
Для прикладу завантажимо наш qrcode з попереднього прикладу на файлообмінник.
Також будемо вдавати браузер Mozilla.
Для відправки файлів використовується словник files з вказанням:
1️⃣ назви файлу
2️⃣ самого файлу
3️⃣ типу файлу
#http #requests #POST
multipart/form-data використовується у формах з надсилання файлів на сервер.
У цьому випадку бібліотека requests виставляє заголовок:
Content-Type: multipart/form-data; boundary=...Для прикладу завантажимо наш qrcode з попереднього прикладу на файлообмінник.
Також будемо вдавати браузер Mozilla.
Для відправки файлів використовується словник files з вказанням:
1️⃣ назви файлу
2️⃣ самого файлу
3️⃣ типу файлу
import requests
with open("qr_code.png", "rb") as file:
url = "https://catbox.moe/user/api.php"
files = {
"fileToUpload": ("qr_code.png", file, "image/png"),
}
data = {
"reqtype": "fileupload",
"userhash": "",
}
headers = {
"User-Agent" : "Mozilla/5.0 "
"(Windows NT 10.0; Win64; x64; rv:142.0)"
"Gecko/20100101 Firefox/142.0"
}
r = requests.post(url, files=files, data=data, headers=headers)
r.raise_for_status()
print(r.text.strip()) # вивод url
https://files.catbox.moe/lmcc82.png
#http #requests #POST
👎1
🔷 Requests. Використання сесій.
У Python бібліотека requests дозволяє зручно працювати з HTTP-запитами. Якщо потрібно виконати кілька запитів до одного сайту — варто використовувати сесію.
Що дає використання сесії:
1️⃣ Автоматично підтримувати cookies між запитами.
2️⃣ Дозволяють повторно використовувати одні ті самі заголовки.
3️⃣ Використовують одне TCP-з’єднання для кількох запитів → запити виконуються швидше.
Приклад коду з використанням сесій:
#http #requests #session
У Python бібліотека requests дозволяє зручно працювати з HTTP-запитами. Якщо потрібно виконати кілька запитів до одного сайту — варто використовувати сесію.
Що дає використання сесії:
1️⃣ Автоматично підтримувати cookies між запитами.
2️⃣ Дозволяють повторно використовувати одні ті самі заголовки.
3️⃣ Використовують одне TCP-з’єднання для кількох запитів → запити виконуються швидше.
Приклад коду з використанням сесій:
import requests
url = "https://httpbin.org/headers"
with requests.Session() as session:
# Виставляємо заголовоки для всіх запитів у сесії
headers = {
"User-Agent" : "Mozilla/5.0 "
"(Windows NT 10.0; Win64; x64; rv:142.0)"
"Gecko/20100101 Firefox/142.0"
}
session.headers.update(headers)
r1 = session.get(url)
r1.raise_for_status()
print(r1.json())
r2 = session.get(url)
r2.raise_for_status()
print(r2.json())
#http #requests #session
👍1
🟣 Selectolax. Парсинг HTML
selectolax одна з найшвидших бібліотек для парсингу html. Для пошуку тегів використовується css selectors.
Вона швидша за BeautifulSoup4 і немає проблем з анотаціями типів.
Давайте розглянемо задачу коли треба з html спарсити всі фрукти з такої html сторінки
Для початку створимо об'єкт парсеру:
Шукаєм один тег по id
⚠️ Якщо тег не знайдено метод парсеру вертає None тому завжди варто перевіряти цей момент щоб отримати помилку зі зрозумілим описом. Для цього можна використовувати assert або використати if і кидати Exception.
В середині знайденого тегу шукаємо список по імені тегу:
Використовуємо пошук по імені класу тега щоб знайти всі елементи списку
🔺 strip=True - видаляє зайві пробіли всередині тексту дочірніх тегів
🔺 separator - задає розділювач між текстами з різних дочірніх тегів
🔺 .strip() - обрізає пробіли (та переводи рядків) з початку і кінця рядка
Вивід коду:
#selectolax #parsing #scraping
selectolax одна з найшвидших бібліотек для парсингу html. Для пошуку тегів використовується css selectors.
Вона швидша за BeautifulSoup4 і немає проблем з анотаціями типів.
Давайте розглянемо задачу коли треба з html спарсити всі фрукти з такої html сторінки
html_content = """
<html>
<body>
<section id="fruits">
<h2>Fruits</h2>
<ul>
<li class="item red-item">🍎 Apple</li>
<li class="item">🍌 Banana</li>
<li class="item"> 🍊 <span style="color: orange;">Orange</span> </li>
</ul>
</section>
<section id="vegetables">
<h2>Vegetables</h2>
<ul>
<li class="item">🥕 Carrot</li>
<li class="item" data-id="42">🥔 Potato</li>
<li class="item" data-id="69">🍆 Eggplant</li>
</ul>
</section>
<a href="https://t.me/Python_Materials_For_Beginners/170">Parsing</a>
</body>
</html>
"""
Для початку створимо об'єкт парсеру:
from selectolax.lexbor import LexborHTMLParser, LexborNode
parser = LexborHTMLParser(html_content)
Шукаєм один тег по id
container_el: LexborNode | None = parser.css_first("section#fruits")
assert container_el, "Fruits container not found!"⚠️ Якщо тег не знайдено метод парсеру вертає None тому завжди варто перевіряти цей момент щоб отримати помилку зі зрозумілим описом. Для цього можна використовувати assert або використати if і кидати Exception.
В середині знайденого тегу шукаємо список по імені тегу:
list_el = container_el.css_first("ul")
assert list_el, "List of fruits not found!"Використовуємо пошук по імені класу тега щоб знайти всі елементи списку
item_els: list[LexborNode] = list_el.css("li.item")
for item_el in item_els:
text = item_el.text(strip=True, separator="-").strip()
print(text)🔺 strip=True - видаляє зайві пробіли всередині тексту дочірніх тегів
🔺 separator - задає розділювач між текстами з різних дочірніх тегів
🔺 .strip() - обрізає пробіли (та переводи рядків) з початку і кінця рядка
Вивід коду:
🍎 Apple
🍌 Banana
🍊-Orange-
#selectolax #parsing #scraping
🟠 Selectolax. Парсинг HTML. Частина 2.
🔺 Поєднанний пошук.
Пошук по CSS-селекторах дозволяє одразу поєднувати все в одному рядку запиту:
❗️ Але я наполегливо не рекомендував би цим зловживати. Короткий запис — це добре, але у випадку помилки буде важко зрозуміти, з яким саме тегом проблема.
🔺 Пошук тега який має декілька класів
🔺 Атрибути тегу
Для отримання атрибуту тегу :
▪️attributes – це read-only словник. Ти можеш з нього читати, але не змінювати напряму.
▪️attrs – це mutable dict-like (звичайний словник), який можна змінювати.
🔺 Пошук по атрибуту:
#selectolax #parsing #scraping
🔺 Поєднанний пошук.
Пошук по CSS-селекторах дозволяє одразу поєднувати все в одному рядку запиту:
item_els = parser.css("section#fruits ul li.item")
for item_el in item_els:
text = item_el.text(strip=True, separator=" ").strip()
print(text)❗️ Але я наполегливо не рекомендував би цим зловживати. Короткий запис — це добре, але у випадку помилки буде важко зрозуміти, з яким саме тегом проблема.
🔺 Пошук тега який має декілька класів
# <li class="item red-item"> ... </li>
red_item_el = parser.css_first("li.item.red-item")
assert red_item_el
print(red_item_el.text()) # 🍎 Apple
🔺 Атрибути тегу
# <a href=" ... ">Parsing</a>
link_el = parser.css_first("a")
assert link_el
url = link_el.attributes["href"]
print(url) # https://t.me/Python_Materials_For_Beginners/170
Для отримання атрибуту тегу :
▪️attributes – це read-only словник. Ти можеш з нього читати, але не змінювати напряму.
▪️attrs – це mutable dict-like (звичайний словник), який можна змінювати.
🔺 Пошук по атрибуту:
data_els = parser.css("li.item[data-id]")
for data_el in data_els:
data_id = data_el.attributes["data-id"]
print(data_id) # 42 69data_el = parser.css_first("li.item[data-id='42']")
assert data_el
print(data_el.html) # <li class="item" data-id="42"> ... Potato</li>#selectolax #parsing #scraping
👍1
🟢 Selectolax. Парсинг HTML. Підсумки та рекомендації.
Для пошуку тегів ми можемо використовувати:
▪️ id тега
▪️ назву тега
▪️ клас тега
▪️ атрибути тега
❗️ У коректному HTML id завжди повинен бути унікальним, тому пошук по ньому — найнадійніший.
Якщо ж шукати по назві/класу/атрибутам, результатів може бути кілька, і серед них можуть траплятися елементи, які ви не очікували знайти.
У нашому прикладі, якщо ми хочемо тільки фрукти й напишемо:
То отримаємо не лише фрукти, а й овочі — це видно одразу у нашому простому HTML-коду. Реальні html-сторінки по розміру значно більші і можна не помітити десь ще на сторінці використовуються схожі теги але у зовсім іншому контексті, як наслідок — незрозумілі помилки у коді.
👉 Тому рекомендую завжди звужувати пошук: спершу знайдіть найближчий батьківський елемент із логічним id, класом чи атрибутом, а вже потім отримуйте потрібні дочірні теги.
👉 Важливо, щоб назви класів, id чи атрибутів, до яких ви прив’язуєтеся, були логічними та «говорили самі за себе». Так менша ймовірність отримати помилкові результати, а код буде легше читати й підтримувати.
👉 Є певна термінологія в HTML: тег зазвичай називають елементом (DOM element) або нодою (Node). Я відповідно додаю суфікс
#selectolax #parsing #scraping
Для пошуку тегів ми можемо використовувати:
▪️ id тега
▪️ назву тега
▪️ клас тега
▪️ атрибути тега
❗️ У коректному HTML id завжди повинен бути унікальним, тому пошук по ньому — найнадійніший.
Якщо ж шукати по назві/класу/атрибутам, результатів може бути кілька, і серед них можуть траплятися елементи, які ви не очікували знайти.
У нашому прикладі, якщо ми хочемо тільки фрукти й напишемо:
item_els = parser.css("li.item") То отримаємо не лише фрукти, а й овочі — це видно одразу у нашому простому HTML-коду. Реальні html-сторінки по розміру значно більші і можна не помітити десь ще на сторінці використовуються схожі теги але у зовсім іншому контексті, як наслідок — незрозумілі помилки у коді.
👉 Тому рекомендую завжди звужувати пошук: спершу знайдіть найближчий батьківський елемент із логічним id, класом чи атрибутом, а вже потім отримуйте потрібні дочірні теги.
👉 Важливо, щоб назви класів, id чи атрибутів, до яких ви прив’язуєтеся, були логічними та «говорили самі за себе». Так менша ймовірність отримати помилкові результати, а код буде легше читати й підтримувати.
👉 Є певна термінологія в HTML: тег зазвичай називають елементом (DOM element) або нодою (Node). Я відповідно додаю суфікс
_el або _els до змінних, які містять об’єкти тегів. Це не принципово, але, на мою думку, так код читається краще й спрощується іменування змінних.#selectolax #parsing #scraping
👍1
💎 httpx+selectolax. Data scraping.
Розглянимо приклад коду який наводив у чаті . Код достатньо довгий тому Git-Gist
1️⃣ Часті запити на сайт можуть призвести до:
▪️ відповіді HTTP 429 Too Many Requests
▪️ обриву з'єднання сервером
▪️ появу капчі
▪️ блокуванню по IP
Тому варто обмежувати кількість запитів у секунду. Для цього існує бібліотека asynciolimiter яка дає можливість це зробити за допомогою Limiter: перед кожним запитом варто викликати його метод limiter.wait()
2️⃣ При скрапінгу даних використовуємо сесії. Це пришвидшує виконання запитів і дає підтримку cookie.
3️⃣ Щоб згрупувати дані разом варто використовувати класи, dataclasses, NamedTuple або як я моделі pydantic
4️⃣ Код варто розбивати на функції, класи, модулі і пакети уникаючи награмодження коду. В даному прикладі я показую розбиття на ф-ції але можна було всю роботу з сайтом винести у модуль або пакет. Також можна було зробити клас QuoteScraper з відповідними методами (це дозволило б не передавати постійно session та limiter у параметрах).
📦
┣━━ 📜
┣━━ ⚙️
┣━━ 🧾
┣━━ 🔎
┗━━ 🕷
📜
Структура має бути не обов'язково така сама, але вона має
бути. Коли весь проєкт у одному файлі — це не норм.
5️⃣ Особисто я використовую такий неймінг:
5.1. Функції які займаютья парсингом HTML назвиваю як
parse_ *
5.2. Функціїї які роблять запити: scrape_*
також можна назвивати get_* або fetch_*
6️⃣ Для перевірки наявності потрібних використовую assert але можна також кидати Exception/RuntimeError
7️⃣ Використання logging дає змогу налаштовувати кількість/рівень повідомлень у консоль як власного коду так і коду використаних бібліотек.
8️⃣ Використання генераторів та ітераторів дає можливість більш гнучко використовувати написаний код. (наприклад зупинити ітерацію по сторінкам коли знайдена потрібна цитата)
#httpx #selectolax #parsing #scraping
Розглянимо приклад коду який наводив у чаті . Код достатньо довгий тому Git-Gist
1️⃣ Часті запити на сайт можуть призвести до:
▪️ відповіді HTTP 429 Too Many Requests
▪️ обриву з'єднання сервером
▪️ появу капчі
▪️ блокуванню по IP
Тому варто обмежувати кількість запитів у секунду. Для цього існує бібліотека asynciolimiter яка дає можливість це зробити за допомогою Limiter: перед кожним запитом варто викликати його метод limiter.wait()
2️⃣ При скрапінгу даних використовуємо сесії. Це пришвидшує виконання запитів і дає підтримку cookie.
3️⃣ Щоб згрупувати дані разом варто використовувати класи, dataclasses, NamedTuple або як я моделі pydantic
4️⃣ Код варто розбивати на функції, класи, модулі і пакети уникаючи награмодження коду. В даному прикладі я показую розбиття на ф-ції але можна було всю роботу з сайтом винести у модуль або пакет. Також можна було зробити клас QuoteScraper з відповідними методами (це дозволило б не передавати постійно session та limiter у параметрах).
📦
quote_scraper┣━━ 📜
__init__.py ┣━━ ⚙️
config.py - константи, наприклад BASE_URL ┣━━ 🧾
schemas.py - моделі даних┣━━ 🔎
parsers.py - функції для парсингу html┗━━ 🕷
scrapers.py - функції для запит+парсинг 📜
main.pyСтруктура має бути не обов'язково така сама, але вона має
бути. Коли весь проєкт у одному файлі — це не норм.
5️⃣ Особисто я використовую такий неймінг:
5.1. Функції які займаютья парсингом HTML назвиваю як
parse_ *
5.2. Функціїї які роблять запити: scrape_*
також можна назвивати get_* або fetch_*
6️⃣ Для перевірки наявності потрібних використовую assert але можна також кидати Exception/RuntimeError
7️⃣ Використання logging дає змогу налаштовувати кількість/рівень повідомлень у консоль як власного коду так і коду використаних бібліотек.
8️⃣ Використання генераторів та ітераторів дає можливість більш гнучко використовувати написаний код. (наприклад зупинити ітерацію по сторінкам коли знайдена потрібна цитата)
#httpx #selectolax #parsing #scraping
👍1
🤖 Про телеграм боти.
Телеграм бот це програма яка отримує події/оновлення (Updates) від телеграм сервера і реагує на них, або ігнорує.
Боти можна розділяти по способу отримання оновлень (Update):
1️⃣ Long Polling
2️⃣ Webhook
Long Polling — бот періодично запитує сервер Телеграм, чи є нові оновлення. Цей варіант підходить для більшості ботів.
Webhook — бот отримує оновлення відразу, як тільки вони надходять, бо Телеграм відправляє їх на заданий Вами URL. Цей варіант для високонавантажених ботів.
На відміну від Long polling, для Webhook потрібен публічний IP або домен з SSL, щоб Телеграм міг надсилати запити безпосередньо на твій сервер.
#tg_bots
Телеграм бот це програма яка отримує події/оновлення (Updates) від телеграм сервера і реагує на них, або ігнорує.
Боти можна розділяти по способу отримання оновлень (Update):
1️⃣ Long Polling
2️⃣ Webhook
Long Polling — бот періодично запитує сервер Телеграм, чи є нові оновлення. Цей варіант підходить для більшості ботів.
Webhook — бот отримує оновлення відразу, як тільки вони надходять, бо Телеграм відправляє їх на заданий Вами URL. Цей варіант для високонавантажених ботів.
На відміну від Long polling, для Webhook потрібен публічний IP або домен з SSL, щоб Телеграм міг надсилати запити безпосередньо на твій сервер.
#tg_bots
👍3
Forwarded from PythonFromYouTube
ByteByteGo
Top 3 Things You Should Know About Webhooks!
1 hour ago
https://www.youtube.com/watch?v=x_jjhcDrISk
Top 3 Things You Should Know About Webhooks!
1 hour ago
https://www.youtube.com/watch?v=x_jjhcDrISk
YouTube
Top 3 Things You Should Know About Webhooks!
Get a Free System Design PDF with 158 pages by subscribing to our weekly newsletter: https://bit.ly/bytebytegoytTopic
Animation tools: Adobe Illustrator and After Effects.
Checkout our bestselling System Design Interview books:
Volume 1: https://amzn.to/3Ou7gkd…
Animation tools: Adobe Illustrator and After Effects.
Checkout our bestselling System Design Interview books:
Volume 1: https://amzn.to/3Ou7gkd…
🤖 Телеграм боти. Update.
Оновлення (Update) - важливе поняття у телеграм ботах, важливо розуміти які вони бувають.
Повний список оновлень та їх опис можна знайти у оф.документації телеграму.
Для прикладу на скріншоті наведено три типи оновлень:
▪️ message - відбувається коли користувач відправляє текстове повідомлення.
▪️ edit_message - відбувається коли користувач його редагує
▪️ callback_query - відбувається коли користувач натискає на inline-кнопку.
Завжди є нюанси, наприклад натиснення на replay-кнопку теж рахується як message.
Фізично дані оновлення це json-контент який присилає нам сервер. Бібліотека aiogram3 перетворює json у об'єкти класів (вик. pydantic моделі).
#tg_bots
Оновлення (Update) - важливе поняття у телеграм ботах, важливо розуміти які вони бувають.
Повний список оновлень та їх опис можна знайти у оф.документації телеграму.
Для прикладу на скріншоті наведено три типи оновлень:
▪️ message - відбувається коли користувач відправляє текстове повідомлення.
▪️ edit_message - відбувається коли користувач його редагує
▪️ callback_query - відбувається коли користувач натискає на inline-кнопку.
Завжди є нюанси, наприклад натиснення на replay-кнопку теж рахується як message.
Фізично дані оновлення це json-контент який присилає нам сервер. Бібліотека aiogram3 перетворює json у об'єкти класів (вик. pydantic моделі).
#tg_bots
👍1🌚1
🤖 Телеграм боти. Long Polling
Long Polling ніщо інше як HTTP-запити на телеграм сервіс.
Нижче простий приклад отримання оновлень за допомогою requests.
Робимо запит і отримуємо оновлення у вигляді json.
Приклад виводу у коментарях.
#tg_bots
Long Polling ніщо інше як HTTP-запити на телеграм сервіс.
Нижче простий приклад отримання оновлень за допомогою requests.
Робимо запит і отримуємо оновлення у вигляді json.
import requests
TOKEN = 'Ваш токен від телеграм боту'
URL = f'https://api.telegram.org/bot{TOKEN}/getUpdates'
def get_updates(session: requests.Session, offset: int | None = None):
params = {'timeout': 30, 'offset': offset}
try:
r = session.get(URL, params=params, timeout=35)
r.raise_for_status()
data = r.json()
if not data.get('ok'):
raise RuntimeError("Telegram API response is not OK")
return data['result']
except requests.exceptions.Timeout:
return []
def long_polling():
offset = None
with requests.Session() as session:
while True:
if updates := get_updates(session, offset):
for update in updates:
print(update)
offset = update['update_id'] + 1
else:
print("No updates")
long_polling()
Приклад виводу у коментарях.
#tg_bots
👍1
Чи варто продовжувати писати власні пости?
Anonymous Poll
8%
Ні, взагалі немає сенсу
4%
Ні, занадто банально треба щось унікальніше і складніше.
88%
Так, продовжувати
▶️ Корисні речі, які варто знати про процес.
Коли ви запускаєте файл своєї програми, вона завантажується в оперативну пам’ять і починає виконуватися як процес.
Є кілька важливих аспектів процесу, які варто знати, щоб ефективніше використовувати їх у своїх проєктах:
1️⃣ Змінні оточення (Environment Variables) [1] [2]
2️⃣ Консольні аргументи (Command-line Arguments) [1] [2] [3]
3️⃣ Код завершення процесу (Exit Code) [1]
4️⃣ Потоки вводу/виводу
(Input/Output Streams, stdin/stdout/stderr) [1] [2]
Планую розглянути ці речі поступово детальніше.
Коли ви запускаєте файл своєї програми, вона завантажується в оперативну пам’ять і починає виконуватися як процес.
Є кілька важливих аспектів процесу, які варто знати, щоб ефективніше використовувати їх у своїх проєктах:
1️⃣ Змінні оточення (Environment Variables) [1] [2]
2️⃣ Консольні аргументи (Command-line Arguments) [1] [2] [3]
3️⃣ Код завершення процесу (Exit Code) [1]
4️⃣ Потоки вводу/виводу
(Input/Output Streams, stdin/stdout/stderr) [1] [2]
Планую розглянути ці речі поступово детальніше.
👍3
🟡 Змінні оточення (Environment Variables)
Змінні оточення — це іменовані пари ключ-значення, які операційна система передає програмам під час їх запуску.
Вони містять інформацію про середовище виконання, конфігурацію системи та користувача інше.
Є загальноприйняті системні змінні оточення, які діють у всій системі, а також ті,
що встановлюються іншими програмами або shell-скриптами під час запуску.
Для роботи зі змінними оточення у Python використовується словник os.environ.
Приклад використання системних змінних:
Цей код виводить розташування каталогу користувача в системі.
Як бачимо під різними системами різні назви змінних, крім того під Windows треба отримати дві зміних.
Аналогічним чином можна отримувати шлях до каталогу з тимчасовим файлами (TEMP/TMPDIR)
Відео по темі: Your .env File Is Lying to You
Змінні оточення — це іменовані пари ключ-значення, які операційна система передає програмам під час їх запуску.
Вони містять інформацію про середовище виконання, конфігурацію системи та користувача інше.
Є загальноприйняті системні змінні оточення, які діють у всій системі, а також ті,
що встановлюються іншими програмами або shell-скриптами під час запуску.
Для роботи зі змінними оточення у Python використовується словник os.environ.
Приклад використання системних змінних:
import os
import sys
def get_home_dir() -> str | None:
if sys.platform == "win32": # Windows
home_drive = os.environ.get("HOMEDRIVE", "")
home_path = os.environ.get("HOMEPATH", "")
if home_drive and home_path:
return os.path.join(home_drive, home_path)
else: # Linux подібні
return os.environ.get("HOME")
return None
print(get_home_dir())
Цей код виводить розташування каталогу користувача в системі.
Як бачимо під різними системами різні назви змінних, крім того під Windows треба отримати дві зміних.
Аналогічним чином можна отримувати шлях до каталогу з тимчасовим файлами (TEMP/TMPDIR)
Відео по темі: Your .env File Is Lying to You
🟢 Змінні оточення. Власні змінні.
Розглянемо приклад використання власної змінної.
Файл main.py
Якщо ми запустимо цей код стандартним способом отримуємо вивід None що логічно бо такої змінної немає.
Але якщо ми запустимо цей код у терміналі командою:
Під Windows
Або під Linux
Отримаємо очікувані "42"
👉 Таки чином ми можемо передавати у програму якісь налаштування:
▪️ виставляючи змінні глобально у системі
▪️ за допомогою терміналу і sh/bat - скриптів
▪️ запускаючи іншими програмами
P/S: У PyСharm є налаштування запуску куди можна додавати власні змінні оточення.
Розглянемо приклад використання власної змінної.
Файл main.py
import os
import sys
name = "USER_VAR"
value = os.environ.get(name)
print(value)
Якщо ми запустимо цей код стандартним способом отримуємо вивід None що логічно бо такої змінної немає.
Але якщо ми запустимо цей код у терміналі командою:
Під Windows
set USER_VAR="42" && python main.py
Або під Linux
export USER_VAR="42" && python main.py
Отримаємо очікувані "42"
👉 Таки чином ми можемо передавати у програму якісь налаштування:
▪️ виставляючи змінні глобально у системі
▪️ за допомогою терміналу і sh/bat - скриптів
▪️ запускаючи іншими програмами
P/S: У PyСharm є налаштування запуску куди можна додавати власні змінні оточення.
👍1
🔵 Dot env files
У минулому пості я перелічив три способи, як можна передавати змінні оточення у програму, але ці способи не дуже зручні саме під час розробки програмного забезпечення. У вас може бути багато проєктів, і незручно встановлювати все в системні змінні.
Писати командні скрипти можна, але потрібно створювати окремий скрипт для кожної операційної системи.
Тому під час розробки часто використовують
Цей звичайний текстовий файл який містить змінні оточення та їх значення розділені знаком рівності.
⚠️ Якщо ваш
Для роботи з такими файлами у python є стороння бібліотека
Файл
Файл
Що робить ця бібліотека?
1️⃣ Вона шукає у теці проєкту файл
2️⃣ Якщо файл є, вона його завантажує, парсить і додає змінні з файлу у словник
3️⃣ Якщо файлу немає,
У минулому пості я перелічив три способи, як можна передавати змінні оточення у програму, але ці способи не дуже зручні саме під час розробки програмного забезпечення. У вас може бути багато проєктів, і незручно встановлювати все в системні змінні.
Писати командні скрипти можна, але потрібно створювати окремий скрипт для кожної операційної системи.
Тому під час розробки часто використовують
.env файл.Цей звичайний текстовий файл який містить змінні оточення та їх значення розділені знаком рівності.
⚠️ Якщо ваш
.env файл містить або може містити в майбутньому секретні ключі, паролі тощо — його обов’язково треба додати у .gitignore, щоб не залити у GitHub репозиторій.Для роботи з такими файлами у python є стороння бібліотека
python-dotenv Файл
.envBOT_TOKEN="Ваш токен"
Файл
main.pyfrom dotenv import load_dotenv # pip install python-dotenv
import os
load_dotenv()
bot_token = os.environ.get("BOT_TOKEN")
print(bot_token)
Що робить ця бібліотека?
1️⃣ Вона шукає у теці проєкту файл
.env (іншу назву файлу можна вказати параметром).2️⃣ Якщо файл є, вона його завантажує, парсить і додає змінні з файлу у словник
os.environ.3️⃣ Якщо файлу немає,
os.environ залишається незмінним.👍1
У відео йдеться про різні цікаві можливості python-dotenv
https://www.youtube.com/watch?v=8dlQ_nDE7dQ
https://www.youtube.com/watch?v=8dlQ_nDE7dQ
YouTube
Load Environment Variables From .env Files in Python
Today we go a little bit deeper into the Python dotenv module, which allows us to load environment variables from .env files.
◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾
📚 Programming Books & Merch 📚
🐍 The Python Bible Book: https://www.neuralnine.com/books/
💻 The Algorithm Bible…
◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾◾
📚 Programming Books & Merch 📚
🐍 The Python Bible Book: https://www.neuralnine.com/books/
💻 The Algorithm Bible…
👏1
🤖 Приклад телеграм бота на aiogram3
Повернемось до теми Telegram ботів.
Будем розглядати приклад ехо-бота.
Файл
Файл
Для написання телеграм ботів по мінімум потрібні знання:
1️⃣ Асинхронності
2️⃣ ООП
3️⃣ Декораторів
4️⃣ Бази python, наприклад виключень та менеджерів контексту.
І це тільки для початку, бо для побудови більш менш нормального потрібна база даних, то треба ще знання SQL та ORM (SqlAlchemy)
Без цих основ немає сенсу братись за телеграм боти.
#tg_bots
Повернемось до теми Telegram ботів.
Будем розглядати приклад ехо-бота.
Файл
.envBOT_TOKEN=Ваш_токен
Файл
main.pyimport asyncio
import os
# pip install aiogram
from aiogram import Bot, Dispatcher, Router, html
from aiogram.filters import Command
from aiogram.types import Message
from aiogram.enums import ParseMode
from aiogram.fsm.storage.memory import MemoryStorage
# pip install python-dotenv
from dotenv import load_dotenv
router = Router()
async def startup(bot: Bot) -> None:
await bot.delete_webhook(drop_pending_updates=True)
print("Bot started.")
async def shutdown(bot: Bot) -> None:
print("Bot stopped.")
@router.message(Command("start"))
async def start_handler(message: Message):
await message.answer(
f"<i>Hello</i> {html.unparse(message.from_user.first_name)}!",
parse_mode=ParseMode.HTML
)
@router.message()
async def echo_handler(message: Message):
await message.answer(
f"Echo: {message.html_text}",
parse_mode=ParseMode.HTML
)
async def main():
load_dotenv()
token = os.environ.get("BOT_TOKEN")
assert token, "BOT_TOKEN is missing!"
async with Bot(token=token) as bot:
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
dp.startup.register(startup)
dp.shutdown.register(shutdown)
dp.include_router(router)
await dp.start_polling(bot)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("Stopped by user.")
Для написання телеграм ботів по мінімум потрібні знання:
1️⃣ Асинхронності
2️⃣ ООП
3️⃣ Декораторів
4️⃣ Бази python, наприклад виключень та менеджерів контексту.
І це тільки для початку, бо для побудови більш менш нормального потрібна база даних, то треба ще знання SQL та ORM (SqlAlchemy)
Без цих основ немає сенсу братись за телеграм боти.
#tg_bots
👏1
🟣 Опис роботи echo-бота. Основні класи.
✅ Токен бота беремо з змінних оточення або
✅ Чисто з естетичних причин ми перехоплюємо виключення KeyboardInterrupt.
Це виключення виникає при натисненні юзером Ctrl+C у терміналі і в таких випадках мабуть ми не хочемо бачити stack trace помилок.
✅ Для автоматичного закриття сесії бота використовуємо асинхронний контекстний менеджер.
✅ Класи Dispatcher, Router дозволяють реєструвати обробники оновлень(подій).
Загалом система диспетчеризації оновлень по обробникам може мати складну деревовидну структуру.
Dispatcher - це головний об'єкт який може включати в собі Router-и, водночас Router може включати в себе інші Router-и. Звучить складно, але загалом практичний сенс цього полягає у тому що ми групуємо обробники, по якомусь принципу у логічну одиницю -- Router, а Router-и додаємо у Dispatcher. Користь Router-ів у тому що ми можемо легко винести обробники оновлень у окремі файли - модулі. Крім того кожен роутер може мати свій Filter і/та Middleware, що дуже зручно (про це можливо пізніше)
Розглянемо приклад структури проєкту:
main.py
Логіка розділення:
▪️Очевидно, що адміністратори бота і/або чату можуть мати особливі права і їх дії треба обробляти окремо.
▪️Окремо також варто оброблювати повідомлення у особисте спілкування з ботом.
▪️ Окремо оброблювати події в каналах та групах.
⚠️ Це лише приклад, структура-розділення має залежати від суті бота.
Головне мати логічну вибудовану структуру, а не всі обробники у одному файлі.
✅ MemoryStorage - це клас сховища станів. Воно потрібне щоб тимчасово зберігати стан заповнення форми, а також дані полів які користувач вже заповнив перед тим як ці дані застосовувати(наприклад записати у БД)
#tg_bots
✅ Токен бота беремо з змінних оточення або
.env-файлу якщо він є.✅ Чисто з естетичних причин ми перехоплюємо виключення KeyboardInterrupt.
Це виключення виникає при натисненні юзером Ctrl+C у терміналі і в таких випадках мабуть ми не хочемо бачити stack trace помилок.
✅ Для автоматичного закриття сесії бота використовуємо асинхронний контекстний менеджер.
✅ Класи Dispatcher, Router дозволяють реєструвати обробники оновлень(подій).
Загалом система диспетчеризації оновлень по обробникам може мати складну деревовидну структуру.
Dispatcher - це головний об'єкт який може включати в собі Router-и, водночас Router може включати в себе інші Router-и. Звучить складно, але загалом практичний сенс цього полягає у тому що ми групуємо обробники, по якомусь принципу у логічну одиницю -- Router, а Router-и додаємо у Dispatcher. Користь Router-ів у тому що ми можемо легко винести обробники оновлень у окремі файли - модулі. Крім того кожен роутер може мати свій Filter і/та Middleware, що дуже зручно (про це можливо пізніше)
Розглянемо приклад структури проєкту:
project/
├── main.py (містить dp: Dispatcher)
├── keyboards.py
├── middleware.py
└── handlers/
├── __init__.py
├── admins.py (містить admin_router: Router)
├── private.py (містить private_router: Router)
├── сhannels.py (містить сhannels_router: Router)
└── group_users.py (містить group_router: Router)
main.py
from handles.admins import admin_router
from handles.private import private_router
# ...
dp = Dispatcher(storage=storage)
dp.include_router(admin_router)
dp.include_router(private_router)
# ...
dp.include_router(group_router)
Логіка розділення:
▪️Очевидно, що адміністратори бота і/або чату можуть мати особливі права і їх дії треба обробляти окремо.
▪️Окремо також варто оброблювати повідомлення у особисте спілкування з ботом.
▪️ Окремо оброблювати події в каналах та групах.
⚠️ Це лише приклад, структура-розділення має залежати від суті бота.
Головне мати логічну вибудовану структуру, а не всі обробники у одному файлі.
✅ MemoryStorage - це клас сховища станів. Воно потрібне щоб тимчасово зберігати стан заповнення форми, а також дані полів які користувач вже заповнив перед тим як ці дані застосовувати(наприклад записати у БД)
#tg_bots
👍1