7
\$\begingroup\$
from bs4 import BeautifulSoup
import requests
import re
import datetime

metal_translation = {"Aluminium": "Aluminio", "Copper": "Cobre", "Zinc": "Zinc", "Nickel": "Níquel", "Lead": "Plomo", "Tin": "Estaño",
                     "Aluminium Alloy": "Aleación de Aluminio", "Cobalt": "Cobalto", "Gold*": "Oro*", "Silver*": "Plata*",
                     "Steel Scrap**": "Chatarra de Acero", "NASAAC": "NASAAC", "Steel Rebar**": "Varilla de Acero"}

def get_metal_values():
    names = []
    prices = []
    metals = requests.get('https://www.lme.com/').text
    soup = BeautifulSoup(metals, 'lxml')
    metal_table = soup.find("table", attrs={"class": "ring-times"})
    metal_table_names, metal_table_prices = metal_table.tbody.find_all("th"), metal_table.tbody.find_all("td")
    for name in metal_table_names:
        names.append(name.text.replace("LME ", ""))
    for price in metal_table_prices:
        prices.append(price.text.strip())
    return names, prices

def get_peso_conversion():
    peso = requests.get('https://themoneyconverter.com/USD/MXN').text
    soup1 = BeautifulSoup(peso, 'lxml')
    conversion = soup1.find("div", class_="cc-result").text
    rate = re.search("\d{2}\.\d{4}", conversion).group()
    return rate

def get_time():
    date = datetime.datetime.now()
    time = (f'{date.day}/{date.month}/{date.year} | {date.hour}:{date.minute}')
    return time

def convert_values():
    names, prices = get_metal_values()
    rate = get_peso_conversion()
    metal_data = dict(zip(names, prices))
    for k, v in metal_data.items():
        v = (float(v.replace(",", "")) * float(rate))
        v = ("%.2f" % v)
        k = metal_translation[k]
        print(f'{k}: {v} $')

def program_run():
    print("Metal Prices by ETHAN HETRICK")
    print("================================================")
    print(f'{get_time()} | 1 USD = {get_peso_conversion()} MXN\n')
    print("Precios de metales de London Metal Exchange: (Por tonelada métrica, *Por onza Troy)\n")
    convert_values()
    print("================================================")

program_run()
input("\nEscribe 'x' para terminar.\n")

EXAMPLE OUTPUT:

Metal Prices by ETHAN HETRICK
================================================
26/6/2020 | 18:28 | 1 USD = 23.0622 MXN

Precios de metales de London Metal Exchange: (Por tonelada métrica, *Por onza Troy)

Aluminio: 36484.40 $
Cobre: 138038.80 $
Zinc: 47438.95 $
Níquel: 293097.50 $
Plomo: 41004.59 $
Estaño: 391826.78 $
Aleación de Aluminio: 27997.51 $
NASAAC: 27444.02 $
Cobalto: 657272.70 $
Oro*: 40711.70 $
Plata*: 410.74 $
Chatarra de Acero: 6065.36 $
Varilla de Acero: 9720.72 $
================================================

Escribe 'x' para terminar.

My fiances father owns a metal recycling business in Mexico City, Mexico which requires him to do a lot of calculations when negotiating with clients. Since he was doing this by hand, I decided to automate this for him. I used London Metal Exchange, which is his preferred site to get the current prices, for the metal prices and also got the exchange rate for USD to MXN and applied that as well. I also needed to translate everything to spanish so I used a dictionary. This is my first time utilizing webscraping and the datetime module so any advice to make this program run more efficiently or make the code more concise is much appreciated!

\$\endgroup\$

1 Answer 1

9
\$\begingroup\$

Check for failure

metals = requests.get('https://www.lme.com/').text

should be

response = requests.get('https://www.lme.com/')
response.raise_for_status()
metals = response.text

String literals don't need parens

date = datetime.datetime.now()
time = (f'{date.day}/{date.month}/{date.year} | {date.hour}:{date.minute}')

would only need parens if it spans multiple lines.

Also, date shouldn't be called date for a couple of reasons:

  • it shadows datetime.date, and
  • it has a time, not just a date.

Finally: try using strftime rather than extracting the time's individual components to render a string.

No intermediate dict

metal_data = dict(zip(names, prices))
for k, v in metal_data.items():

The only reason you'd want to do this is if you're deeply concerned that there are duplicates, which this would remove. If there are no duplicates, then simply

for k, v in zip(names, prices):

Combine format strings

    v = ("%.2f" % v)
    k = metal_translation[k]
    print(f'{k}: {v} $')

can be

print(f'{metal_translation[k]}: {v:.2f}')
\$\endgroup\$
4
  • \$\begingroup\$ Thanks! I just updated the post ( : . @Reinderien \$\endgroup\$ Commented Jun 27, 2020 at 2:37
  • \$\begingroup\$ I have rolled this back. Rather than editing your existing post, if you are satisfied with the amount of feedback you've received, please make a new one. \$\endgroup\$
    – Reinderien
    Commented Jun 27, 2020 at 2:38
  • \$\begingroup\$ sure thing! I'll do that right away. \$\endgroup\$ Commented Jun 27, 2020 at 2:56
  • 2
    \$\begingroup\$ @Reinderien I saw this on the sidebar on another question and logged in to upvote. 3 years with Python and I had no clue you could format floats inside of formatted strings and use zip without dict. \$\endgroup\$
    – Malekai
    Commented Jun 27, 2020 at 10:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.