Как создать конвертер валют на Python

Конвертер валют — это приложение, позволяющее быстро переводить одну валюту в другую по курсу. Такие инструменты массово доступны в интернете, воспользоваться ими можно бесплатно. В этой статье мы разберем, как создать конвертер валют на Python.

Мы рассмотрим различные способы получения актуального курса обмена валют. Некоторые из них связаны с парсингом общедоступных веб-страниц, другие — с использованием официальных API (эти данные более надежны и пригодны для коммерческого использования).

Всего мы рассмотрим пять способов получения курса:

  1. Парсинг X-RATES
  2. Использование сервиса Xe
  3. Парсинг платформы Yahoo Finance
  4. Использование ExchangeRate API
  5. Использование Fixer API

Вы можете изучить все пять способов и выбрать тот, который вам понравится больше всего.

Для начала не забудьте установить необходимые библиотеки для всех методов, которые мы будем использовать. Запустите следующую команду:

$ pip install python-dateutil requests bs4 yahoo_fin

Итак, теперь мы готовы, давайте приступать!

Как написать программу для обмена валют в Python

Парсинг X-RATES

В этом разделе мы будем извлекать данные с сайта x-rates.com. Если вы перейдете на целевую веб-страницу, вы увидите большинство валют мира с курсом, определенным на текущий момент.

Давайте сначала очистим страницу. Сделать это можно следующим образом:

import requests
from bs4 import BeautifulSoup as bs
from dateutil.parser import parse
from pprint import pprint
python logo

Python задачи

Наш телеграм канал с тестами по Python, задачами с собеседований и разбором решений.

×

Следующая функция отвечает за выполнение запроса к странице и извлечение данных из таблиц:

def get_exchange_list_xrates(currency, amount=1):
    # make the request to x-rates.com to get current exchange rates for common currencies
    content = requests.get(f"https://www.x-rates.com/table/?from={currency}&amount={amount}").content
    # initialize beautifulsoup
    soup = bs(content, "html.parser")
    # get the last updated time
    price_datetime = parse(soup.find_all("span", attrs={"class": "ratesTimestamp"})[1].text)
    # get the exchange rates tables
    exchange_tables = soup.find_all("table")
    exchange_rates = {}
    for exchange_table in exchange_tables:
        for tr in exchange_table.find_all("tr"):
            # for each row in the table
            tds = tr.find_all("td")
            if tds:
                currency = tds[0].text
                # get the exchange rate
                exchange_rate = float(tds[1].text)
                exchange_rates[currency] = exchange_rate        
    return price_datetime, exchange_rates

Эта функция принимает исходную валюту и необходимую сумму в качестве параметров и возвращает соответствующие суммы в разных валютах мира вместе с датой и временем последнего обновления.

Время последнего обновления находится в теге span с классом rateTimestamp. Обратите внимание, что мы используем функцию parse() из модуля dateutil.parser для автоматического парсинга строки в объект Python DateTime.

Курсы валют размещены в двух таблицах. Мы извлекаем их с помощью метода find_all() из модуля BeautifulSoup, получаем название валюты и сумму по курсу в каждой строке таблиц и добавляем их в наш словарь exchange_rates, который выведем в конце.

Что ж, давайте воспользуемся этой функцией:

if __name__ == "__main__":
    import sys
    source_currency = sys.argv[1]
    amount = float(sys.argv[3])
    target_currency = "GBP"
    price_datetime, exchange_rates = get_exchange_list_xrates(source_currency, amount)
    print("Last updated:", price_datetime)
    pprint(exchange_rates)

Мы используем встроенный модуль sys, чтобы получать целевую валюту и сумму из командной строки. Давайте запустим следующую команду и попробуем перевести 1000 евро во все другие валюты:

$ python currency_converter_xrates.py EUR 1000

Результат будет таким:

Last updated: 2022-02-01 12:13:00+00:00
{'Argentine Peso': 118362.205708,     
 'Australian Dollar': 1586.232315,    
 'Bahraini Dinar': 423.780164,        
 'Botswana Pula': 13168.450636,       
 'Brazilian Real': 5954.781483,       
 'British Pound': 834.954104,
 'Bruneian Dollar': 1520.451015,      
 'Bulgarian Lev': 1955.83,
 'Canadian Dollar': 1430.54405,       
 'Chilean Peso': 898463.818465,       
 'Chinese Yuan Renminbi': 7171.445692,
 'Colombian Peso': 4447741.922165,    
 'Croatian Kuna': 7527.744707,        
 'Czech Koruna': 24313.797041,
 'Danish Krone': 7440.613895,
 'Emirati Dirham': 4139.182587,
 'Hong Kong Dollar': 8786.255952,
 'Hungarian Forint': 355958.035747,
 'Icelandic Krona': 143603.932438,
 'Indian Rupee': 84241.767127,
 'Indonesian Rupiah': 16187150.010697,
 'Iranian Rial': 47534006.535121,
 'Israeli Shekel': 3569.191411,
 'Japanese Yen': 129149.364679,
 'Kazakhstani Tenge': 489292.515538,
 'Kuwaiti Dinar': 340.959682,
 'Libyan Dinar': 5196.539901,
 'Malaysian Ringgit': 4717.485104,
 'Mauritian Rupee': 49212.933037,
 'Mexican Peso': 23130.471272,
 'Nepalese Rupee': 134850.008728,
 'New Zealand Dollar': 1703.649473,
 'Norwegian Krone': 9953.078431,
 'Omani Rial': 433.360301,
 'Pakistani Rupee': 198900.635421,
 'Philippine Peso': 57574.278782,
 'Polish Zloty': 4579.273862,
 'Qatari Riyal': 4102.552652,
 'Romanian New Leu': 4946.638369,
 'Russian Ruble': 86197.012666,
 'Saudi Arabian Riyal': 4226.530892,
 'Singapore Dollar': 1520.451015,
 'South African Rand': 17159.831129,
 'South Korean Won': 1355490.097163,
 'Sri Lankan Rupee': 228245.645722,
 'Swedish Krona': 10439.125427,
 'Swiss Franc': 1037.792217,
 'Taiwan New Dollar': 31334.286611,
 'Thai Baht': 37436.518169,
 'Trinidadian Dollar': 7636.35428,
 'Turkish Lira': 15078.75981,
 'US Dollar': 1127.074905,
 'Venezuelan Bolivar': 511082584.868731}

На момент написания данного руководства это около 1127,07 долларов США. Обратите внимание на дату и время последнего обновления. Обычно курс обновляется каждую минуту.

Использование сервиса Xe

А теперь давайте рассмотрим альтернативный вариант. 

Xe — это компания, предоставляющая инструменты и услуги по обмену иностранной валюты онлайн. Наиболее известна Xe своим онлайн-конвертером валют. В этом разделе мы воспользуемся такими библиотеками, как requests и  BeautifulSoup, чтобы сделать на их основе собственный конвертер валют.

Приступим!

Откройте новый файл Python и импортируйте все необходимые библиотеки:

import requests
from bs4 import BeautifulSoup as bs
import re
from dateutil.parser import parse

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

Выглядеть это будет следующим образом:

def convert_currency_xe(src, dst, amount):
    def get_digits(text):
        """Returns the digits and dots only from an input `text` as a float
        Args:
            text (str): Target text to parse
        """
        new_text = ""
        for c in text:
            if c.isdigit() or c == ".":
                new_text += c
        return float(new_text)
    
    url = f"https://www.xe.com/currencyconverter/convert/?Amount={amount}&From={src}&To={dst}"
    content = requests.get(url).content
    soup = bs(content, "html.parser")
    exchange_rate_html = soup.find_all("p")[2]
    # get the last updated datetime
    last_updated_datetime = parse(re.search(r"Last updated (.+)", exchange_rate_html.parent.parent.find_all("div")[-2].text).group()[12:])
    return last_updated_datetime, get_digits(exchange_rate_html.text)

На момент написания данного руководства обменный курс находился в третьем абзаце HTML-страницы. Это объясняет строчку soup.find_all("p")[2]. Не забывайте вносить правки, когда в HTML-страницу вносятся изменения.

В HTML DOM последняя дата и время обменного курса находятся во втором родителе абзаца exchange rate.

Поскольку обменный курс содержит строковые символы, мы создали функцию get_digits() для извлечения из заданной строки только цифр и точек.

Что ж, давайте воспользуемся нашей функцией:

if __name__ == "__main__":
    import sys
    source_currency = sys.argv[1]
    destination_currency = sys.argv[2]
    amount = float(sys.argv[3])
    last_updated_datetime, exchange_rate = convert_currency_xe(source_currency, destination_currency, amount)
    print("Last updated datetime:", last_updated_datetime)
    print(f"{amount} {source_currency} = {exchange_rate} {destination_currency}")

На этот раз нам нужно передать исходную и целевую валюты, а также сумму из командной строки. Мы также попытаемся конвертировать 1000 евро в доллары США с помощью команды в консоли:

$ python currency_converter_xe.py EUR USD 1000

Мы получим следующий результат:

Last updated datetime: 2022-02-01 13:04:00+00:00
1000.0 EUR = 1125.8987 USD

Замечательно! Xe обычно обновляется каждую минуту, так что мы получаем результат в режиме реального времени!

Парсинг платформы Yahoo Finance

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

Для начала давайте выполним импорт библиотек, которые нам понадобятся:

import yahoo_fin.stock_info as si
from datetime import datetime, timedelta

yahoo_fin отлично справляется с извлечением данных с веб-страницы Yahoo Finance. Мы используем метод get_data() из модуля stock_info и передаем ему символ исходной валюты.

Ниже приведена функция, которая использует данную функцию и возвращает сумму, переведенную из одной валюты в другую:

def convert_currency_yahoofin(src, dst, amount):
    # construct the currency pair symbol
    symbol = f"{src}{dst}=X"
    # extract minute data of the recent 2 days
    latest_data = si.get_data(symbol, interval="1m", start_date=datetime.now() - timedelta(days=2))
    # get the latest datetime
    last_updated_datetime = latest_data.index[-1].to_pydatetime()
    # get the latest price
    latest_price = latest_data.iloc[-1].close
    # return the latest datetime with the converted amount
    return last_updated_datetime, latest_price * amount

Мы передаем “1m” в качестве параметра interval в методе get_data() для извлечения данных на текущую минуту, а не текущий день (значение по умолчанию). Мы также извлекаем поминутные данные за предыдущие два дня, просто чтобы перестраховаться (с данными курса в выходные могут быть проблемы).

Существенным преимуществом этого метода является то, что вы можете получить исторические данные, просто изменив параметры start_date и end_date в данном методе. Более того, вы также можете изменить интервал: "1d" для ежедневного обновления, "1wk" для еженедельного и "1mo" для обновления курса один раз в месяц.

Теперь воспользуемся функцией, которая у нас получилась:

if __name__ == "__main__":
    import sys
    source_currency = sys.argv[1]
    destination_currency = sys.argv[2]
    amount = float(sys.argv[3])
    last_updated_datetime, exchange_rate = convert_currency_yahoofin(source_currency, destination_currency, amount)
    print("Last updated datetime:", last_updated_datetime)
    print(f"{amount} {source_currency} = {exchange_rate} {destination_currency}")

Запустим код из консоли следующей командой:

$ python currency_converter_yahoofin.py EUR USD 1000

Мы опять переводим 1000 евро в доллары США. И вот какой результат у нас получился:

Last updated datetime: 2022-02-01 13:26:34
1000.0 EUR = 1126.1261701583862 USD

Использование API ExchangeRate

Как упоминалось в самом начале данного руководства, если вы хотите создать более надежный конвертер валют, делать это лучше на базе API. Для данной цели существует несколько различных API. Мы выбрали два наиболее удобных и простых в использовании. Их мы и рассмотрим далее.

Начнем с ExchangeRate API. Он поддерживает 161 валюту и предлагает 1500 бесплатных запросов в месяц. Кроме того, также есть открытый API, который предлагает ежедневно обновляемые данные. Его-то мы и используем:

import requests
from dateutil.parser import parse 

def get_all_exchange_rates_erapi(src):
    url = f"https://open.er-api.com/v6/latest/{src}"
    # request the open ExchangeRate API and convert to Python dict using .json()
    data = requests.get(url).json()
    if data["result"] == "success":
        # request successful
        # get the last updated datetime
        last_updated_datetime = parse(data["time_last_update_utc"])
        # get the exchange rates
        exchange_rates = data["rates"]
    return last_updated_datetime, exchange_rates

Приведенная выше функция запрашивает открытый API и возвращает обменные курсы для всех валют с последней датой и временем.

Давайте используем эту функцию, чтобы написать свой конвертер валют:

def convert_currency_erapi(src, dst, amount):
    # get all the exchange rates
    last_updated_datetime, exchange_rates = get_all_exchange_rates_erapi(src)
    # convert by simply getting the target currency exchange rate and multiply by the amount
    return last_updated_datetime, exchange_rates[dst] * amount

Далее как обычно, напишем основной код:

if __name__ == "__main__":
    import sys
    source_currency = sys.argv[1]
    destination_currency = sys.argv[2]
    amount = float(sys.argv[3])
    last_updated_datetime, exchange_rate = convert_currency_erapi(source_currency, destination_currency, amount)
    print("Last updated datetime:", last_updated_datetime)
    print(f"{amount} {source_currency} = {exchange_rate} {destination_currency}")

И запустим из консоли нашу программу с помощью следующей команды:

$ python currency_converter_erapi.py EUR USD 1000

На выходе мы получим вот такой результат:

Last updated datetime: 2022-02-01 00:02:31+00:00
1000.0 EUR = 1120.0 USD

Курсы обновляются ежедневно. Стоит отметить, что открытый API не предлагает точный курс обмена. Но вы можете бесплатно зарегистрироваться и получить ключ API, чтобы извлекать точные обменные курсы.

Использование Fixer API

И последний способ получения курса валют — при помощи Fixer API. Это простой и легковесный API для конвертирования валют как в режиме реального времени, так и по состоянию на прошлые периоды.

Вы можете без проблем создать учетную запись и получить ключ API. После этого вы сможете использовать конечную точку /convert для конвертации сумм из одной валюты в другую. Однако, к сожалению, это не входит в бесплатный план и требует апгрейда вашей учетной записи.

Но ещё есть конечная точка /latest, которая отлично работает при бесплатном аккаунте. Она возвращает текущие курсы обмена для валюты вашего региона. В неё мы можем передать исходную и целевую валюты для конвертации и рассчитать обменный курс между ними. Данная функция может быть представлена следующим образом:

import requests
from datetime import datetime

API_KEY = "<YOUR_API_KEY_HERE>"

def convert_currency_fixerapi_free(src, dst, amount):
    """converts `amount` from the `src` currency to `dst` using the free account"""
    url = f"http://data.fixer.io/api/latest?access_key={API_KEY}&symbols={src},{dst}&format=1"
    data = requests.get(url).json()
    if data["success"]:
        # request successful
        rates = data["rates"]
        # since we have the rate for our currency to src and dst, we can get exchange rate between both
        # using below calculation
        exchange_rate = 1 / rates[src] * rates[dst]
        last_updated_datetime = datetime.fromtimestamp(data["timestamp"])
        return last_updated_datetime, exchange_rate * amount

Ниже приведена функция, которая использует конечную точку /convert (подходит для платного аккаунта):

def convert_currency_fixerapi(src, dst, amount):
    """converts `amount` from the `src` currency to `dst`, requires upgraded account"""
    url = f"https://data.fixer.io/api/convert?access_key={API_KEY}&from={src}&to={dst}&amount={amount}"
    data = requests.get(url).json()
    if data["success"]:
        # request successful
        # get the latest datetime
        last_updated_datetime = datetime.fromtimestamp(data["info"]["timestamp"])
        # get the result based on the latest price
        result = data["result"]
        return last_updated_datetime, result

Воспользуйтесь той из двух функций, которая вам больше подходит:

if __name__ == "__main__":
    import sys
    source_currency = sys.argv[1]
    destination_currency = sys.argv[2]
    amount = float(sys.argv[3])
    # free account
    last_updated_datetime, exchange_rate = convert_currency_fixerapi_free(source_currency, destination_currency, amount)
    # upgraded account, uncomment if you have one
    # last_updated_datetime, exchange_rate = convert_currency_fixerapi(source_currency, destination_currency, amount)
    print("Last updated datetime:", last_updated_datetime)
    print(f"{amount} {source_currency} = {exchange_rate} {destination_currency}")

Перед запуском скрипта обязательно замените API_KEY на ключ API, который вы получаете при регистрации учетной записи.

Запустим наш скрипт и получим следующий результат:

Last updated datetime: 2022-02-01 15:54:04
1000.0 EUR = 1126.494 USD

Если вы хотите узнать больше про Fixer API, то вы можете ознакомиться с документацией.

Заключение

Что ж, вот и всё! Сегодня мы разобрали, как написать конвертер валют на Python. При написании такой программы один из самых важных моментов — получение актуального курса валют. В этой статье мы рассмотрели пять способов получить курс. Если вам не подходит ни один из них, ничего страшного — вы можете выбрать любой другой!

Если вам необходимо, вы можете получить полный код для рассмотренных примеров здесь.

Надеемся, данная статья была вам полезна! Успехов в написании кода!

Перевод статьи «How to Make a Currency Converter in Python».