Unlock the secrets of your code with our AI-powered Code Explainer. Take a look!
A currency converter is an app or tool that allows you to quickly convert from one currency to another. We can easily find such tools for free on the Internet. This tutorial will make a real-time currency converter using several methods utilizing web scraping techniques and APIs.
This tutorial will cover six different ways to get the most recent foreign exchange rates, some of them parse the rates from public web pages such as X-RATES and Xe, and others use official APIs for more commercial and reliable use, such as Fixer API, Currency Conversion API, and ExchangeRate API, feel free to use any one of these.
Feel free to jump into the method you want to use:
To get started, we have to install the required libraries for all the methods below:
$ pip install python-dateutil requests bs4 yahoo_fin
In this section, we will extract the data from the x-rates.com website. If you go to the target web page, you'll see most of the currencies along with the most recent date and time. Let's scrape the page:
import requests
from bs4 import BeautifulSoup as bs
from dateutil.parser import parse
from pprint import pprint
The following function is responsible for making a request to that page and extracting the data from the tables:
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
The above function takes the currency and the amount as parameters and returns the exchange rates of most currencies along with the date and time of the last update.
The time of the last update is in a span
tag that has the class of ratesTimestamp
. Notice we use the parse()
function from dateutil.parser
module to automatically parse the string into a Python DateTime object.
The exchange rates are located in two tables. We extract them using the find_all()
method from the BeautifulSoup object and get the currency name and the exchange rate in each row in the tables, and add them to our exchange_rates
dictionary that we will return. Let's use this function:
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)
Excellent, we use the built-in sys
module to get the target currency and the amount from the command line. Let's run this:
$ python currency_converter_xrates.py EUR 1000
The above run is trying to convert 1000 Euros to all other currencies. Here is the output:
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}
That's about 1127.07 in USD at the time of writing this tutorial. Notice the last updated date and time; it usually updates every minute.
Xe is an online foreign exchange tools and services company. It is best known for its online currency converter. In this section, we use requests and BeautifulSoup libraries to make a currency converter based on it.
Open up a new Python file and import the necessary libraries:
import requests
from bs4 import BeautifulSoup as bs
import re
from dateutil.parser import parse
Now let's make a function that accepts the source currency, target currency, and the amount we want to convert, and then returns the converted amount along with the exchange rate date and time:
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)
At the time of writing this tutorial, the exchange rate is located in the third paragraph on the HTML page. This explains the soup.find_all("p")[2]
. Make sure to change the extraction whenever a change is made to the HTML page. Hopefully, I'll keep an eye out whenever a change is made.
The latest date and time of the exchange rate is located at the second parent of the exchange rate paragraph in the HTML DOM.
Since the exchange rate contains string characters, I made the get_digits(
) function to extract only the digits and dots from a given string, which is helpful in our case.
Let's use the function now:
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}")
This time, we get the source and target currencies as well as the amount from the command-lines, trying to convert 1000 EUR to USD:
$ python currency_converter_xe.py EUR USD 1000
Output:
Last updated datetime: 2022-02-01 13:04:00+00:00
1000.0 EUR = 1125.8987 USD
That's great! Xe usually updates every minute too, so it's real-time!
Yahoo Finance provides financial news, currency data, stock quotes, press releases, and financial reports. This section uses the yahoo_fin
library in Python to make a currency exchanger based on Yahoo Finance data.
Importing the libraries:
import yahoo_fin.stock_info as si
from datetime import datetime, timedelta
yahoo_fin
does an excellent job of extracting the data from the Yahoo Finance web page, and it is still maintained now; we use the get_data()
method from the stock_info
module and pass the currency symbol to it.
Below is the function that uses this function and returns the converted amount from one currency to another:
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
We pass "1m"
to the interval
parameter in the get_data()
method to extract minute data instead of daily data (default). We also get minute data of the previous two days, as it may cause issues on the weekends, just to be cautious.
The significant advantage of this method is you can get historical data by simply changing start_date
and end_date
parameters on this method. You can also change the interval
to be "1d"
for daily, "1wk"
for weekly, and "1mo"
for monthly.
Let's use the function now:
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}")
Running the code:
$ python currency_converter_yahoofin.py EUR USD 1000
Output:
Last updated datetime: 2022-02-01 13:26:34
1000.0 EUR = 1126.1261701583862 USD
As mentioned at the beginning of this tutorial, if you want a more reliable way to make a currency converter, you have to choose an API for that. There are several APIs for this purpose. However, we have picked two APIs that seem convenient and easy to get started.
ExchangeRate API supports 161 currencies and offers a free monthly 1,500 requests if you want to try it out, and there is an open API as well that offers daily updated data, and that's what we are going to use:
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
The above function requests the open API and returns the exchange rates for all the currencies with the latest date and time. Let's use this function to make a currency converter function:
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
As usual, let's make the main code:
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}")
Running it:
$ python currency_converter_erapi.py EUR USD 1000
Output:
Last updated datetime: 2022-02-01 00:02:31+00:00
1000.0 EUR = 1120.0 USD
The rates update daily, and it does not offer the exact exchange number as it's an open API; you can freely sign up for an API key to get precise exchange rates.
One of the promising alternatives is Fixer API. It is a simple and lightweight API for real-time and historical foreign exchange rates. You can easily create an account and get the API key.
After you've done that, you can use the /convert
endpoint to convert from one currency to another. However, that's not included in the free plan and requires upgrading your account.
There is the /latest
endpoint that does not require an upgrade and works in a free account just fine. It returns the exchange rates for the currency of your region. We can pass the source and target currencies we want to convert and calculate the exchange rate between both. Here's the function:
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
Below is the function that uses the /convert
endpoint in case you have an upgraded account:
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
Let's use either function:
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}")
Before running the script, make sure to replace API_KEY
with the API key you get when registering for an account.
Running the script:
Last updated datetime: 2022-02-01 15:54:04
1000.0 EUR = 1126.494 USD
You can check the documentation of Fixer API here.
Currency Conversion API helps you with current and historical foreign exchange rates. In this section, we're going to use the currencyapi.com API with Python.
To get started, you have to create an account. You can easily log in with your Gmail with a click of a button, or manually sign up with your email:
After signing up, you're immediately redirected to the dashboard:
You can see the API key hidden in my image, make sure to copy it, and let's get started with the code. Open up a new file named currency_converter_currencyapi.py
and add the following:
import requests
import urllib.parse as p
API_KEY = "<YOUR_API_KEY>"
base_url = "https://api.currencyapi.com/v3/"
We're going to see two of the core endpoints of this API, which are the /latest
to get the latest currency rates, and /historical
to see the historical exchange rates. The response data format is the same, therefore, let's make a common function to handle both:
# utility function that both functions will use
def get_currencyapi_data(endpoint, date=None, base_currency="USD", print_all=True):
"""Get the list of currency codes from the API"""
# construct the url
url = p.urljoin(base_url,
f"{endpoint}?apikey={API_KEY}{'' if endpoint == 'latest' else f'&date={date}'}&base_currency={base_currency}")
# make the request
res = requests.get(url)
# get the json data
data = res.json()
# print all the currency codes and their values
if print_all:
for currency_code, currency_name in data.get("data").items():
print(f"{currency_code}: {currency_name.get('value')}")
if endpoint == "latest":
# get the last updated date
last_updated = data.get("meta").get("last_updated_at")
print(f"Last updated: {last_updated}")
return data
This function takes the endpoint
(either latest
or historical
), the date
(in case of historical
), the base currency (default is "USD"
), and whether to print all the rates available, the default is True
.
We're using the requests
library to make the API call, retrieving the JSON data using the .json()
method, printing all the rates if print_all
is True
, and printing the last updated date in case it's the latest
endpoint.
Let's make the two functions for the /latest
and /historical
endpoints:
def get_latest_rates(base_currency="USD", print_all=True):
"""Get the latest rates from the API"""
return get_currencyapi_data(endpoint="latest", base_currency=base_currency, print_all=print_all)
def get_historical_rates(base_currency="USD", print_all=True, date="2023-01-01"):
"""Get the historical rates from the Currency API
`date` must be in the format of YYYY-MM-DD"""
return get_currencyapi_data(endpoint="historical", base_currency=base_currency, date=date, print_all=print_all)
Amazing. Let's use these functions:
if __name__ == "__main__":
latest_rates = get_latest_rates()
print(f"\n{'-'*50}\n")
# get the historical rates for the date 2021-01-01
historical_rates = get_historical_rates(date="2021-01-01", print_all=False)
# get EUR rate, for example
eur_rate = historical_rates.get("data").get("EUR").get("value")
print(f"EUR rate on 2021-01-01: {eur_rate}")
First, we're getting the latest rates using our get_latest_rates()
function, and printing them.
Second, we get the historical rates but pass False
to print_all
, and then as an example, we get the EUR rate ("USD"
is the base currency) of the 2021-01-01
date. Here's the output of the entire code:
ADA: 2.57927
AED: 3.672219
AFN: 86.155058
ALL: 101.250181
AMD: 388.059705
ANG: 1.79865
AOA: 510.500992
...
<SNIPPED>
...
XOF: 594.500673
XPF: 109.225174
XRP: 2.136364
YER: 250.300428
ZAR: 18.401632
ZMK: 9001.2
ZMW: 17.739516
ZWL: 321.999592
Last updated: 2023-05-01T23:59:59Z
--------------------------------------------------
EUR rate on 2021-01-01: 0.82132
The output is snipped as it's too long, a total of 177 global currencies. Please check the CurrencyAPI documentation for more info.
There is an alternative to using raw API calls using their Python wrapper here.
There are many ways to make a currency converter, and we have covered six of them. If one method does not work for you, you can choose another one!
You can get the complete code for all the files here.
Learn also: Webhooks in Python with Flask.
Happy coding ♥
Why juggle between languages when you can convert? Check out our Code Converter. Try it out today!
View Full Code Fix My Code
Got a coding query or need some guidance before you comment? Check out this Python Code Assistant for expert advice and handy tips. It's like having a coding tutor right in your fingertips!