Home > Software engineering >  How to display the entire list of currencies?
How to display the entire list of currencies?

Time:09-18

I need to output the exchange rate given by the ECB API. But the output shows an error

"TypeError: string indices must be integers"

How to fix this error?

import requests, config
from bs4 import BeautifulSoup

r = requests.get(config.ecb).text
soup = BeautifulSoup(r, "lxml")

course = soup.findAll("cube")
for i in course:
    for x in i("cube"):
        for y in x:
            print(y['currency'], y['rate'])

CodePudding user response:

You have too many for-loops

for i in course:
    print(i['currency'], i['rate'])

But this need also to search <cube> with attribute currency

course = soup.findAll("cube", currency=True)

course = soup.findAll("cube", {"currenc": True})

or you would have to check if item has attribute currency

for i in course:
    if 'currency' in i.attrs:
        print(i['currency'], i['rate'])

Full code:

import requests
from bs4 import BeautifulSoup

url = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml?c892a2e0fae19504ef05028330310886'

response = requests.get(url)
soup = BeautifulSoup(response.text, "lxml")

course = soup.find_all("cube", currency=True)

for i in course:
    #print(i)
    print(i['currency'], i['rate'])

CodePudding user response:

try this

r = requests.get('https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml?c892a2e0fae19504ef05028330310886').text
soup = BeautifulSoup(r, "lxml")
result = [{currency.get('currency'): currency.get('rate')} for currency in soup.find_all("cube", {'currency': True})]
print(result)

OUTPUT:

[{'USD': '0.9954'}, {'JPY': '142.53'}, {'BGN': '1.9558'}, {'CZK': '24.497'}, {'DKK': '7.4366'}, {'GBP': '0.87400'}, {'HUF': '403.98'}, {'PLN': '4.7143'}, {'RON': '4.9238'}, {'SEK': '10.7541'}, {'CHF': '0.9579'}, {'ISK': '138.30'}, {'NOK': '10.1985'}, {'HRK': '7.5235'}, {'TRY': '18.1923'}, {'AUD': '1.4894'}, {'BRL': '5.2279'}, {'CAD': '1.3226'}, {'CNY': '6.9787'}, {'HKD': '7.8133'}, {'IDR': '14904.67'}, {'ILS': '3.4267'}, {'INR': '79.3605'}, {'KRW': '1383.58'}, {'MXN': '20.0028'}, {'MYR': '4.5141'}, {'NZD': '1.6717'}, {'PHP': '57.111'}, {'SGD': '1.4025'}, {'THB': '36.800'}, {'ZAR': '17.6004'}]

CodePudding user response:

Just in addition to answer from @Sergey K, that is on point how it should be done, to show what is the main issue.

Main issue in your code is that, your selection is not that precise as it should be:

soup.findAll("cube")

This will also find_all() parent <cube> that do not have an attribute called currency or rate but much more decisive is that there are spaces in the markup in between nodes BeautifulSoup will turn those into NavigableString's.

Using the index to get the attribute values, wont work while you do it with a NavigableStringinstead of the next`.

You can see this if you print(y.name) only:

None
Cube
None
Cube
...

How to fix this error?

There are two approaches in my opinion

  1. Best is already shwon https://stackoverflow.com/a/73756178/14460824 by Sergey K who used very precise arguments to find_all() specific elements.
  2. While working with your code, is to implement an if-statement that checks, if the tag.name is equal to 'cube'. It is working fine, but I would recommend to use a more precise selection instead.

Example

import requests
from bs4 import BeautifulSoup

r = requests.get('https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml?c892a2e0fae19504ef05028330310886').text
soup = BeautifulSoup(r)

soup.findAll("cube")

course = soup.findAll("cube")
for i in course:
    for x in i("cube"):
        for y in x:
            if y.name == 'cube':
                print(y['currency'], y['rate'])

Output

USD 0.9954
JPY 142.53
BGN 1.9558
CZK 24.497
DKK 7.4366
GBP 0.87400
HUF 403.98
PLN 4.7143
...
  • Related