История курса рубля на PyQt5 + XML от ЦБ РФ

В данной статье мы создадим десктопное приложение используя PyQt5 и XML API от ЦБ РФ для получения курса валют. Интерфейс нашей программы будет достаточно простой. У нас будут несколько выпадающих списков для выбора дня, месяца и года. После выбора всех настроек, наше приложение сделает запрос к XML API от cbr.ru (Центральный Банк России) для получения курса доллара и евро на указанную дату.

Данный урок нацелен на улучшение знаний полученных после прочтения:

Скачать исходники: скрипт и изображения (33.4 кб)

Каркас приложения

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#!/usr/bin/python3

# -*- coding: utf-8 -*-

import sys

from PyQt5.QtWidgets import (QWidget, QLabel, QApplication, QComboBox, QPushButton)

from PyQt5.QtGui import QPixmap, QFont

class CBR_API(QWidget):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        self.setFixedSize(300, 400)

        self.setWindowTitle('История курса рубля')

        self.show()

if __name__ == '__main__':

    app = QApplication(sys.argv)

    money = CBR_API()

    sys.exit(app.exec_())

В данном примере у нас обычный каркас для PyQt5 приложения. Мы указали фиксированный размер для нашего окна. Настроили заголовок приложения.

Лого приложения

Мы быстро создали  лого для нашего приложения и загрузили её в PyQt5 с помощью QPixmap. Вот так выглядит метод initUI после добавления лого.

def initUI(self):

    # Загружаем лого нашей программы.

    logo_label = QLabel(self)

    logo_label.setPixmap(QPixmap("img/logo.png"))

    logo_label.move(0, 0)

    self.setFixedSize(300, 400)

    self.setWindowTitle('История курса рубля')

    self.show()

Запускаем наш скрипт.

История курса рубля на PyQt5 + XML от ЦБ РФ

После загрузки лого, нам понадобятся небольшие настройки для выбора дня, месяца и года. Тем самым, мы сформируем правильный запрос к API cbr.ru. Для создания выпадающих списков вы воспользуемся классом QComboBox из под-модуля PyQt5.QtWidgets.

Мы создадим 3 новых метода метода:

  • self.days() — создаем выпадающий список дней (1-30).
  • self.month() — создает выпадающий список номеров месяцев (1-12).
  • self.year() — создаем выпадающий список годов начиная с 2005.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

def days(self):

    """

    Выпадающий список дней.

    """

    # Создаем выпадающий список.

    self.days_combo = QComboBox(self)

    # Заголовок списка.

    day_label = QLabel("День", self)

    day_label.move(20, 170)

    for day in range(1, 31):

        # Наполняем список.

        self.days_combo.addItem('%d' % day)

    # Фиксируем список.

    self.days_combo.move(20, 200)

def month(self):

    """

    Выпадающий список месяцев.

    """

    # Создаем выпадающий список.

    self.month_combo = QComboBox(self)

    # Заголовок списка.

    month_label = QLabel("Месяц", self)

    month_label.move(80, 170)

    for month_num in range(1, 13):

        # Наполняем список.

        self.month_combo.addItem('%d' % month_num)

    # Фиксируем список.

    self.month_combo.move(80, 200)

def year(self):

    """

    Выпадающий список годов.

    """

    # Создаем выпадающий список.

    self.year_combo = QComboBox(self)

    # Заголовок списка.

    month_label = QLabel("Год", self)

    month_label.move(140, 170)

    for year_num in range(2005, 2018):

        # Наполняем список.

        self.year_combo.addItem('%d' % year_num)

    # Фиксируем список.

    self.year_combo.move(140, 200)

После создания методов внутри класса CBR_API мы должны вызвать методы в initUI. Мы создадим и кнопку «OK» после нажатия на которую выполнится запрос к API банка.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

def initUI(self):

    # Загружаем лого нашей программы.

    logo_label = QLabel(self)

    logo_label.setPixmap(QPixmap("img/logo.png"))

    logo_label.move(0, 0)

    # Загружаем выпадающие списки для дней, месяцев и годов.

    self.days()

    self.month()

    self.year()

    # Создаем кнопку "OK".

    ok_button = QPushButton('ОК', self)

    ok_button.resize(50, 25)

    ok_button.move(220, 200)

    # Каждый клик кнопки вызывает метод "makeRequest"

    ok_button.clicked.connect(self.makeRequest)

    self.setFixedSize(300, 400)

    self.setWindowTitle('История курса рубля')

    self.show()

def makeRequest(self):

    return True

Запускаем код и у нас должен появится вот такой результат.

История курса рубля на PyQt5 + XML от ЦБ РФ

Вывод курса валют

У нас слишком много места под выпадающими списками, нужно их заполнить иконками доллара и евро. Так-же, мы изменим шрифт текста для курса валют. Текст с курсом валют будет обновляться каждый раз как мы нажмем на кнопку «OK». Создаем метод load_result_image который загрузит иконки и выполнит позиционирование текста для каждой валюты.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

def load_result_image(self):

    # Настройки шрифта текста.

    font = QFont()

    font.setFamily("Arial")

    font.setPointSize(18)

    # Загружаем иконку доллара.

    dollar_label = QLabel(self)

    dollar_label.setPixmap(QPixmap("img/dollar.png"))

    dollar_label.move(60, 260)

    # Текст с выводом курса доллара.

    self.dollar_value = QLabel("0 руб.", self)

    self.dollar_value.setFont(font)

    self.dollar_value.move(130, 263)

    # Загружаем иконку евро.

    euro_label = QLabel(self)

    euro_label.setPixmap(QPixmap("img/euro.png"))

    euro_label.move(50, 320)

    # Текст с выводом курса евро.

    self.euro_value = QLabel("0 руб.", self)

    self.euro_value.setFont(font)

    self.euro_value.move(130, 320)

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Не забываем добавить вызов данного метода в initUI. После чего запускаем наш код.

История курса рубля на PyQt5 + XML от ЦБ РФ

Backend приложения

Интерфейс нашего приложения готов. Теперь, нужно доделать и backend часть, для этого придерживаемся данного сценария:

  1. Пользователь выбирает нужный день, месяц, год
  2. Нажимает на «ОК«
  3. Выполняется makeRequest который использует библиотеку Requests на примерах.
  4. Собираем данные из выпадающих списках
  5. Формируем запрос к XML API от cbr.ru
  6. Выполняем парсинг полученных XML данных
  7. Обновляем текст с курсом валют
  8. ???
  9. Profit!

Для начала создадим недостающие методы:

  • makeRequest — получает данные из выпадающих списков и отправляет их в getResult.
  • getResult — выполняет запрос к XML cbr.ru и обрабатывает полученные данные.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

def getResult(self, day, month, year):

    """

    Выполняет запрос к API Банка России.

    :param day: Выбранный день.

    :param month: Выбранный номер месяца.

    :param year: Выбранный код

    :return: dict

    """

    result = {

        'usd': 0,

        'eur': 0,

    }

    if int(day) < 10:

        day = '0%s' % day

    if int(month) < 10:

        month = '0%s' % month

    try:

        # Выполняем запрос к API.

        get_xml = requests.get(

            'http://www.cbr.ru/scripts/XML_daily.asp?date_req=%s/%s/%s' % (day, month, year)

        )

        # Парсинг XML используя ElementTree

        structure = ET.fromstring(get_xml.content)

    except:

        return result

    try:

        # Поиск курса доллара (USD ID: R01235)

        dollar = structure.find("./*[@ID='R01235']/Value")

        result['dollar'] = dollar.text.replace(',', '.')

    except:

        result['dollar'] = 'x'

    try:

        # Поиск курса евро (EUR ID: R01239)

        euro = structure.find("./*[@ID='R01239']/Value")

        result['euro'] = euro.text.replace(',', '.')

    except:

        result['euro'] = 'x'

    return result

def makeRequest(self):

    """

    После нажатия на "ОК" выполняется запрос к API с выбранными данными.

    """

    # Получаем текущие значения из выпадающих списках.

    day_value = self.days_combo.currentText()

    month_value = self.month_combo.currentText()

    year_value = self.year_combo.currentText()

    # Выполняем запрос к API с выбранными данными.

    result = self.getResult(day_value, month_value, year_value)

    # Заменяем текст для доллара.

    self.dollar_value.setText('%s руб.' % result['dollar'])

    self.dollar_value.adjustSize()

    # Заменяем текст для евро.

    self.euro_value.setText('%s руб.' % result['euro'])

    self.euro_value.adjustSize()

Структура XML ответа от cbr.ru

Скрипт выполняет запрос к URL:

http://www.cbr.ru/scripts/XML_daily.asp?date_req=ДД/ММ/ГГГ

Получаем такой ответ:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<ValCurs Date="22.04.2017" name="Foreign Currency Market">

    <Valute ID="R01235">

        <NumCode>840</NumCode>

        <CharCode>USD</CharCode>

        <Nominal>1</Nominal>

        <Name>Доллар США</Name>

        <Value>56,2307</Value>

    </Valute>

    <Valute ID="R01239">

        <NumCode>978</NumCode>

        <CharCode>EUR</CharCode>

        <Nominal>1</Nominal>

        <Name>Евро</Name>

        <Value>60,3187</Value>

    </Valute>

</ValCurs>

Мы получим более длинный список, но для экономии места показываем только для евро и доллара. Можете заметить, что каждая валюта имеет свой уникальный идентификационный номер.

  • ID Доллара: R01235
  • ID Евро: R01239

По данному идентификационному номеру мы и выполнили поиск нужной нам валюты используя библиотеку ElementTree и метод find.

# Выполняем запрос к API.

get_xml = requests.get(

    'http://www.cbr.ru/scripts/XML_daily.asp?date_req=%s/%s/%s' % (day, month, year)

)

# Парсинг XML используя ElementTree

structure = ET.fromstring(get_xml.content)

# Поиск курса доллара (USD ID: R01235)

dollar = structure.find("./*[@ID='R01235']/Value")

result['dollar'] = dollar.text.replace(',', '.')

# Поиск курса евро (EUR ID: R01239)

euro = structure.find("./*[@ID='R01239']/Value")

result['euro'] = euro.text.replace(',', '.')

После получения курса мы заменяем текст для каждой валюты.

# Заменяем текст для доллара.

self.dollar_value.setText('%s руб.' % result['dollar'])

self.dollar_value.adjustSize()

# Заменяем текст для евро.

self.euro_value.setText('%s руб.' % result['euro'])

self.euro_value.adjustSize()

Давайте узнаем какой сейчас курс рубля!

История курса рубля на PyQt5 + XML от ЦБ РФ

Благодарю за внимание!
Если есть вопросы — прошу в комментариях.

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: vasile.buldumac@ati.utm.md

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»