В данной статье я хотел бы сделать обзор на библиотеку, которая позволяет поместить значок приложения в трей, а также добавить к нему контекстное меню с выполнением различных операций при нажатии на них. А также, немного рассказать о новой библиотеке, которая позволяет выводить всплывающие сообщения в трее, как Windows 10, так и Windows 11. Использовать для этих целей мы будем небольшой скрипт на Python, в котором и будет показана работа библиотек.
Что потребуется?
Для работы скрипта потребуется установка довольно большого количества библиотек.
Это:
Для установки данных библиотек необходимо набрать в терминале следующую команду:
Так как в данном скрипте используются изображения, как для иконки скрипта в трее, так и для вывода во всплывающих сообщениях, необходимо будет скачать иконки в формате png и поместить их в папку pic.
У меня это выглядит вот так:
Значки могут быть, по сути любыми, а не только такими же, как у меня, главное - не забыть отобразить это в коде. Эти же иконки я прикреплю во вложение к статье.
На этом подготовительный этап можно завершить. После того, как будут установлены все библиотеки и загружены иконки, импортируем нужные для работы скрипта библиотеки:
Для того, чтобы внести небольшую ясность в то, что нам необходимо будет сделать, надо пояснить, что по клику на меню иконки в трее будет парситься запрос к Google, из которого нам необходимо будет забрать курс той или иной валюты. После чего вывести всплывающее сообщение. Давайте приступим к написанию кода.
Получение html-кода страницы
Создадим функцию get_text(url: str) -> (str, bool). На вход она получает ссылку на страницу, делает к ней запрос и если статус-код равен 200, возвращает html-код страницы. Если же код будет другим, вернется значение False.
Дополнительно укажем заголовки, в которых пропишем user-agent. Все же, парсить будем Google, а потому, нужно немного притвориться браузером.
Парсим стоимость валюты
Нас интересует стоимость той или иной валюты по отношению к рублю. В качестве подопытных валют были выбраны три: доллар, йена и юань.
Создадим функцию parse_course(url: str) -> (str, bool), которая на входе получает ссылку с запросом, а возвращает полученное значение в случае удачи или False, в случае, если значение получить не удалось.
Выполняем функцию get_text, в которую передаем полученную в функцию ссылку. В зависимости от ответа создаем объект BeautifulSoup, в который передаем полученный код страницы и указываем парсер, с помощью которого будем получать значения. Ищем значение валюты на странице, забираем его в переменную course и, если она не пуста возвращаем его из функции. Если же значение получено не было, или возникло исключение, возвращаем из функции False.
Вывод всплывающих сообщений
Создадим функцию notify_send(text: str, url='', icon=None), которая на входе получает текст сообщения, ссылку, по которой был выполнен запрос к странице с курсом валюты, а также словарь, в котором содержится путь к иконке и значение, которое указывает на необходимость переопределения логотипа приложения.
Проверяем не является ли значение icon – None. Такое может быть, если значение курса валют не было получено и вернулась ошибка. Если оно не None, создаем две кнопки, в качестве аргумента первой кнопки указываем ссылку на страницу, а у второй значение, которое закроет сообщение. Таким образом у нас должны быть две кнопки: Открыть в Google и Закрыть. Ну, а далее, выводим сообщение.
Если же значение icon равно None, выводим в сообщении только одну кнопку – Закрыть.
Выбор валюты, по которой было получено значение
Создадим функцию notify_choice(course: str, url: str, val: str), которая на входе получает текст с курсом валюты, ссылку по которой был выполнен запрос, значение val, указывающее, по какой из трех валют выполнялся запрос. В зависимости от этого формируем сообщение и отправляем для вывода на экран, в функцию notify_send.
Обработка нажатия на пункт меню иконки в трее
Создадим функцию click(icon: Icon, item: MenuItem), которая на входе получает значения, возвращаемые при нажатии на тот или иной пункт меню. Переводим полученное значение в текст, проверяем чему этот текст равен. В зависимости от этого запрашиваем значение нужной валюты в рублях и отправляем полученное значение в функцию notify_choice для формирования текста и вывода всплывающего сообщения.
Нужно обратить внимание, что остановка скрипта происходит при нажатии на пункт меню «Выход». В этом случае обрабатывается команда icon.stop(), которая и завершает работу скрипта.
Формирование меню и запуск скрипта
Создадим функцию main, в которой будем формировать меню для иконки скрипта в трее, а также для запуска скрипта на выполнение.
Загрузим иконку для приложения с помощью функции Pillow Image. Создадим переменную icon, в которую поместим объект Icon. В качестве параметров передадим название для созданного объекта, иконку, которая была загружена в переменную image, и начнем создавать меню. Как видно далее, доступно не только создание меню, но, для каждого пункта возможно создание подменю, чем мы и воспользуемся. Создадим два пункта меню у иконки: «Курс к рублю:» и «Выход». Для пункта «Курс к рублю:» создадим подменю, где разместим подменю для доллара, йены и юаня.
Затем выполним команду, которая свернет терминал в «Панель задач» и запустим скрипт на выполнение.
Давайте посмотрим, что у нас получилось. Как видим, иконка скрипта появилась в трее.
При щелчке по иконке правой кнопкой мыши будут доступны пункты меню, которое мы создали.
Теперь получим курс какой-нибудь валюты и посмотрим на всплывающее сообщение.
Данное сообщение имеет две кнопки. При клике на кнопку «Открыть в Google» будет запущен браузер, а при клике на кнопку «Закрыть» сообщение будет закрыто.
Теперь, если мы кликнем по пункту меню «Выход», скрипт завершит свою работу.
Единственной не особо приятной особенностью является то, что при работе библиотеки для отображения всплывающих сообщений в терминал выводятся значения кнопок сообщения.
А на этом, пожалуй, все.
Спасибо за внимание. Надеюсь, данное сообщение будет вам полезно
Что потребуется?
Для работы скрипта потребуется установка довольно большого количества библиотек.
Это:
- pystray – с помощью данной библиотеки мы будем реализовывать значок скрипта в трее;
- Pillow – данная библиотека потребуется для того, чтобы открыть изображение, которое будет служить иконкой для скрипта в трее;
- bs4 и lxml – с помощью данных библиотек мы будем парсить html-код страницы, который вернется к нам по запросу;
- requests – с помощью данной библиотеки мы будем получать html-код страницы по нужному нам адресу;
- pywin32 – данная библиотека потребуется для того, чтобы свернуть терминал со скриптом на панель задач;
- win11toast – с помощью данной библиотеки мы будем выводить всплывающие сообщения с интерактивными кнопками (win10toast в связке с python 3.11 работать не хочет, выбрасывает исключение).
Для установки данных библиотек необходимо набрать в терминале следующую команду:
pip install pystray Pillow requests bs4 lxml pywin32 win11toast
Так как в данном скрипте используются изображения, как для иконки скрипта в трее, так и для вывода во всплывающих сообщениях, необходимо будет скачать иконки в формате png и поместить их в папку pic.
У меня это выглядит вот так:
Значки могут быть, по сути любыми, а не только такими же, как у меня, главное - не забыть отобразить это в коде. Эти же иконки я прикреплю во вложение к статье.
На этом подготовительный этап можно завершить. После того, как будут установлены все библиотеки и загружены иконки, импортируем нужные для работы скрипта библиотеки:
Python:
from pathlib import Path
import win32con
import win32console
import win32gui
from PIL import Image
from bs4 import BeautifulSoup
from pystray import Icon, MenuItem, Menu
from requests import get
from win11toast import toast
Для того, чтобы внести небольшую ясность в то, что нам необходимо будет сделать, надо пояснить, что по клику на меню иконки в трее будет парситься запрос к Google, из которого нам необходимо будет забрать курс той или иной валюты. После чего вывести всплывающее сообщение. Давайте приступим к написанию кода.
Получение html-кода страницы
Создадим функцию get_text(url: str) -> (str, bool). На вход она получает ссылку на страницу, делает к ней запрос и если статус-код равен 200, возвращает html-код страницы. Если же код будет другим, вернется значение False.
Дополнительно укажем заголовки, в которых пропишем user-agent. Все же, парсить будем Google, а потому, нужно немного притвориться браузером.
Python:
def get_text(url: str) -> (str, bool):
"""
Получение кода страницы по заданной ссылке.
"""
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/110.0.0.0 Safari/537.36'
}
try:
res = get(url=url, headers=headers)
return res.text if res.status_code == 200 else False
except Exception:
return False
Парсим стоимость валюты
Нас интересует стоимость той или иной валюты по отношению к рублю. В качестве подопытных валют были выбраны три: доллар, йена и юань.
Создадим функцию parse_course(url: str) -> (str, bool), которая на входе получает ссылку с запросом, а возвращает полученное значение в случае удачи или False, в случае, если значение получить не удалось.
Выполняем функцию get_text, в которую передаем полученную в функцию ссылку. В зависимости от ответа создаем объект BeautifulSoup, в который передаем полученный код страницы и указываем парсер, с помощью которого будем получать значения. Ищем значение валюты на странице, забираем его в переменную course и, если она не пуста возвращаем его из функции. Если же значение получено не было, или возникло исключение, возвращаем из функции False.
Python:
def parse_course(url: str) -> (str, bool):
"""
Парсинг стоимости валюты по отношению к рублю.
"""
try:
if res := get_text(url):
soup = BeautifulSoup(res, 'lxml')
course = soup.find('div', class_='dDoNo ikb4Bb gsrt').find('span', class_='DFlfde SwHCTb').text.strip()
return course if course else False
else:
return False
except AttributeError:
return False
Вывод всплывающих сообщений
Создадим функцию notify_send(text: str, url='', icon=None), которая на входе получает текст сообщения, ссылку, по которой был выполнен запрос к странице с курсом валюты, а также словарь, в котором содержится путь к иконке и значение, которое указывает на необходимость переопределения логотипа приложения.
Проверяем не является ли значение icon – None. Такое может быть, если значение курса валют не было получено и вернулась ошибка. Если оно не None, создаем две кнопки, в качестве аргумента первой кнопки указываем ссылку на страницу, а у второй значение, которое закроет сообщение. Таким образом у нас должны быть две кнопки: Открыть в Google и Закрыть. Ну, а далее, выводим сообщение.
Если же значение icon равно None, выводим в сообщении только одну кнопку – Закрыть.
Python:
def notify_send(text: str, url='', icon=None):
"""
Вывод уведомления с активными кнопками.
"""
if icon:
buttons = [{'activationType': 'protocol', 'arguments': f'{url}', 'content': 'Открыть в Google'},
{'activationType': 'protocol', 'arguments': 'http:Dismiss', 'content': 'Закрыть'}]
toast("Курс к рублю", f'{text}', buttons=buttons, icon=icon)
else:
toast("Курс к рублю", f'{text}',
button={'activationType': 'protocol', 'arguments': 'http:Dismiss', 'content': 'Закрыть'}, icon=icon)
Выбор валюты, по которой было получено значение
Создадим функцию notify_choice(course: str, url: str, val: str), которая на входе получает текст с курсом валюты, ссылку по которой был выполнен запрос, значение val, указывающее, по какой из трех валют выполнялся запрос. В зависимости от этого формируем сообщение и отправляем для вывода на экран, в функцию notify_send.
Python:
def notify_choice(course: str, url: str, val: str):
"""
Выбор сообщения для определенной валюты, в зависимости от значения val.
"""
if val == "b":
icon = {
'src': f'{Path.cwd() / "pic" / "free-dollar.png"}',
'placement': 'appLogoOverride'
}
notify_send(f'Курс ₽1/$1 составляет: {course} руб.за доллар', url, icon)
elif val == "y":
icon = {
'src': f'{Path.cwd() / "pic" / "free-yen.png"}',
'placement': 'appLogoOverride'
}
notify_send(f'Курс ₽1/JP¥1 составляет: {course} руб.за йену', url, icon)
elif val == "u":
icon = {
'src': f'{Path.cwd() / "pic" / "free-yuan.png"}',
'placement': 'appLogoOverride'
}
notify_send(f'Курс ₽1/CN¥1 составляет: {course} руб.за юань', url, icon)
Обработка нажатия на пункт меню иконки в трее
Создадим функцию click(icon: Icon, item: MenuItem), которая на входе получает значения, возвращаемые при нажатии на тот или иной пункт меню. Переводим полученное значение в текст, проверяем чему этот текст равен. В зависимости от этого запрашиваем значение нужной валюты в рублях и отправляем полученное значение в функцию notify_choice для формирования текста и вывода всплывающего сообщения.
Python:
def click(icon: Icon, item: MenuItem):
"""
Обработка полученных значений меню. В зависимости от выбранного
пункта выполняется запрос данных по определенной валюте.
"""
if str(item) == 'доллара':
url = 'https://www.google.ru/search?q=курс+доллара'
if course := parse_course(url):
notify_choice(course, url, "b")
else:
notify_send("Данные по курсу не получены")
elif str(item) == 'йены':
url = 'https://www.google.ru/search?q=курс+йены'
if course := parse_course(url):
notify_choice(course, url, "y")
else:
notify_send("Данные по курсу не получены")
elif str(item) == 'юаня':
url = 'https://www.google.ru/search?q=курс+юаня'
if course := parse_course(url):
notify_choice(course, url, "u")
else:
notify_send("Данные по курсу не получены")
elif str(item) == 'Выход':
icon.stop()
Нужно обратить внимание, что остановка скрипта происходит при нажатии на пункт меню «Выход». В этом случае обрабатывается команда icon.stop(), которая и завершает работу скрипта.
Формирование меню и запуск скрипта
Создадим функцию main, в которой будем формировать меню для иконки скрипта в трее, а также для запуска скрипта на выполнение.
Загрузим иконку для приложения с помощью функции Pillow Image. Создадим переменную icon, в которую поместим объект Icon. В качестве параметров передадим название для созданного объекта, иконку, которая была загружена в переменную image, и начнем создавать меню. Как видно далее, доступно не только создание меню, но, для каждого пункта возможно создание подменю, чем мы и воспользуемся. Создадим два пункта меню у иконки: «Курс к рублю:» и «Выход». Для пункта «Курс к рублю:» создадим подменю, где разместим подменю для доллара, йены и юаня.
Затем выполним команду, которая свернет терминал в «Панель задач» и запустим скрипт на выполнение.
Python:
def main():
image = Image.open(Path.cwd() / "pic" / "cat.png")
icon = Icon('Cat Vampire', image, menu=Menu(
MenuItem('Курс к рублю:', Menu(
MenuItem('доллара', click),
MenuItem('йены', click),
MenuItem('юаня', click)
)),
MenuItem('Выход', click)
))
win32gui.ShowWindow(win32console.GetConsoleWindow(), win32con.SW_HIDE)
icon.run()
if __name__ == "__main__":
main()
Давайте посмотрим, что у нас получилось. Как видим, иконка скрипта появилась в трее.
При щелчке по иконке правой кнопкой мыши будут доступны пункты меню, которое мы создали.
Теперь получим курс какой-нибудь валюты и посмотрим на всплывающее сообщение.
Данное сообщение имеет две кнопки. При клике на кнопку «Открыть в Google» будет запущен браузер, а при клике на кнопку «Закрыть» сообщение будет закрыто.
Теперь, если мы кликнем по пункту меню «Выход», скрипт завершит свою работу.
Единственной не особо приятной особенностью является то, что при работе библиотеки для отображения всплывающих сообщений в терминал выводятся значения кнопок сообщения.
Python:
"""
pip install pystray Pillow requests bs4 lxml pywin32 win11toast
"""
from pathlib import Path
import win32con
import win32console
import win32gui
from PIL import Image
from bs4 import BeautifulSoup
from pystray import Icon, MenuItem, Menu
from requests import get
from win11toast import toast
def get_text(url: str) -> (str, bool):
"""
Получение кода страницы по заданной ссылке.
"""
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/110.0.0.0 Safari/537.36'
}
try:
res = get(url=url, headers=headers)
return res.text if res.status_code == 200 else False
except Exception:
return False
def parse_course(url: str) -> (str, bool):
"""
Парсинг стоимости валюты по отношению к рублю.
"""
try:
if res := get_text(url):
soup = BeautifulSoup(res, 'lxml')
course = soup.find('div', class_='dDoNo ikb4Bb gsrt').find('span', class_='DFlfde SwHCTb').text.strip()
return course if course else False
else:
return False
except AttributeError:
return False
def notify_send(text: str, url='', icon=None):
"""
Вывод уведомления с активными кнопками.
"""
if icon:
buttons = [{'activationType': 'protocol', 'arguments': f'{url}', 'content': 'Открыть в Google'},
{'activationType': 'protocol', 'arguments': 'http:Dismiss', 'content': 'Закрыть'}]
toast("Курс к рублю", f'{text}', buttons=buttons, icon=icon)
else:
toast("Курс к рублю", f'{text}',
button={'activationType': 'protocol', 'arguments': 'http:Dismiss', 'content': 'Закрыть'}, icon=icon)
def notify_choice(course: str, url: str, val: str):
"""
Выбор сообщения для определенной валюты, в зависимости от значения val.
"""
if val == "b":
icon = {
'src': f'{Path.cwd() / "pic" / "free-dollar.png"}',
'placement': 'appLogoOverride'
}
notify_send(f'Курс ₽1/$1 составляет: {course} руб.за доллар', url, icon)
elif val == "y":
icon = {
'src': f'{Path.cwd() / "pic" / "free-yen.png"}',
'placement': 'appLogoOverride'
}
notify_send(f'Курс ₽1/JP¥1 составляет: {course} руб.за йену', url, icon)
elif val == "u":
icon = {
'src': f'{Path.cwd() / "pic" / "free-yuan.png"}',
'placement': 'appLogoOverride'
}
notify_send(f'Курс ₽1/CN¥1 составляет: {course} руб.за юань', url, icon)
def click(icon: Icon, item: MenuItem):
"""
Обработка полученных значений меню. В зависимости от выбранного
пункта выполняется запрос данных по определенной валюте.
"""
if str(item) == 'доллара':
url = 'https://www.google.ru/search?q=курс+доллара'
if course := parse_course(url):
notify_choice(course, url, "b")
else:
notify_send("Данные по курсу не получены")
elif str(item) == 'йены':
url = 'https://www.google.ru/search?q=курс+йены'
if course := parse_course(url):
notify_choice(course, url, "y")
else:
notify_send("Данные по курсу не получены")
elif str(item) == 'юаня':
url = 'https://www.google.ru/search?q=курс+юаня'
if course := parse_course(url):
notify_choice(course, url, "u")
else:
notify_send("Данные по курсу не получены")
elif str(item) == 'Выход':
icon.stop()
def main():
image = Image.open(Path.cwd() / "pic" / "cat.png")
icon = Icon('Cat Vampire', image, menu=Menu(
MenuItem('Курс к рублю:', Menu(
MenuItem('доллара', click),
MenuItem('йены', click),
MenuItem('юаня', click)
)),
MenuItem('Выход', click)
))
win32gui.ShowWindow(win32console.GetConsoleWindow(), win32con.SW_HIDE)
icon.run()
if __name__ == "__main__":
main()
А на этом, пожалуй, все.
Спасибо за внимание. Надеюсь, данное сообщение будет вам полезно
Вложения
Последнее редактирование модератором: