1
\$\begingroup\$

The purpose of this was to practice web scraping, regex and GUI. I use a popular bitcoin website to scrape the names and prices of the top 16 cryptocurrencies. I then create a data frame and make a GUI to display the information based on the user's selection. I am looking for any and all input on how to improve this code.

import bs4
from urllib.request import urlopen as uReq
from bs4 import BeautifulSoup as soup
import pandas as pd

my_url = 'https://coinmarketcap.com/'
uClient = uReq(my_url)
page_html = uClient.read()
uClient.close()
page_soup = soup(page_html, "html.parser")

containers = page_soup.find("div", {"class": "container main-section"})
tabes = containers.find("table", {"id": "currencies"})
table_names= tabes.find("tbody")

btc = table_names.find_all("tr")

#Get the names and prices of the first 16 crypto coins
prices = []
names = []

for i in range(16):
    x = btc[i]

    #find the price
    x.find("a", {"class": "price"}).text
    current_price = x.find("a", {"class": "price"}).text.strip()
    prices.append(current_price)

    #find the name of the crypto
    name = x.find("td", {"class": "no-wrap currency-name"})
    q = name.text.strip()
    coin_name = " ".join(q.split("\n"))
    names.append(coin_name)

#Make a dataframe with the information we have gathered
df = pd.DataFrame({'Name': names,
                   'Price': prices,
                   })

#Use regular expressions to create a column with just the symbol
import re

symbols = []

for i in df['Name']:
    symbols.append(re.search(r"[A-Z]{3,5}\s\s", i).group().split()[0])

df['Symbol'] = symbols

#GUI
from tkinter import *

root = Tk()
root.title('BTC Price Check')
root.geometry('{}x{}'.format(950, 550))

frame = Frame(root,relief= GROOVE)
frame.pack(side = BOTTOM)

class CheckBox(Checkbutton):
    boxes = []  # Storage for all buttons
    def __init__(self, master=None, **options):
        Checkbutton.__init__(self, frame, options)
        self.boxes.append(self)
        self.var = IntVar() 
        self.configure(variable=self.var)

header = Label(height=1, width=100, text = "Welcome to BTC Price Check")
header.config(font=("Courier", 20))
header.pack(side = TOP, pady = 0)

text = Text(frame)
text.pack(padx = 20, pady = 0, side = RIGHT)

#fucntions for our buttons
def display_price():
    for c, box in enumerate(CheckBox.boxes):
        if box.var.get():
            text.insert(INSERT, "The price of " + names[c] + " is: " + prices[c])
            text.insert(INSERT, "\n")
    text.config(state=DISABLED)

def clearBox():
    text.config(state=NORMAL)
    text.delete("1.0", "end")

#Use the class we created to iterate through the 16 cryptos and create a checkbox for each             
a=0
while a<len(df['Name']):
   bouton=CheckBox(text = names[a],bg = 'yellow')
   a=a+1
   bouton.pack(fill = Y, pady = 2, side = TOP)

#Buttons
pricefind = Button(frame, text = 'Search',width= 20, command = display_price)
pricefind.pack()
clearprice = Button(frame, text = 'Clear', width= 20, command = clearBox)
clearprice.pack()

mainloop()
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Group your imports

You should put all of your imports at the top of the file instead of sprinkling them throughout the code. This is both a best practice and a recommendation from PEP8

Don't use wildcard imports

You import Tkinter with from tkinter import *, but the PEP8 guidelines (and best practices) say you should not. For me, the best way to import Tkinter is with import tkinter as tk because it avoids polluting the global namespace and gives you a short prefix for using Tkinter classes and objects. The prefix helps to make your code a bit more self-documenting.

Use more functions and classes

Most of your code exists in the global namespace. While that's fine for short programs, it becomes difficult to manage as the program grows. Its good to get in the habit of always using functions or classes for nearly all of your code.

For example, I recommend putting all of the GUI code into a class. That will make the code a bit easier to read, and gives you the flexibility of moving the code to a separate file.

clearBox should restore the state of the text widget

Your clearBox function resets the state of the text widget to be editable so that it can clear the contents, but it doesn't set it back. That means that after clicking the clear button, the user could be able to type anything they want in that window. It's somewhat harmless, but is a bit sloppy.

\$\endgroup\$

Your Answer

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

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