skip to Main Content

Following code should go on the website "https://www.destatis.de/DE/Themen/Gesellschaft-Umwelt/Bevoelkerung/Geburten/Tabellen/lebendgeborene-vorl.html" and get the data of that table there. The x axis data is in the column "Monate" and the y axis values are in "Geborene Kinder". I also put the xpath of the columns, where the data should be scrapped. But it doesn’t work.

import tkinter as tk
from tkinter import ttk
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
import json
import matplotlib.pyplot as plt
import os
from time import sleep as wait

options = Options()
options.binary_location = r'C:Program FilesMozilla Firefoxfirefox.exe'


class DataManager:
    def __init__(self):
        # Create the main window
        self.root = tk.Tk()
        self.root.title("Data Manager")

        # Create the grid layout
        self.mainframe = ttk.Frame(self.root, padding="3 3 12 12")
        self.mainframe.grid(column=0, row=0, sticky=(tk.N, tk.W, tk.E, tk.S))
        self.mainframe.columnconfigure(0, weight=1)
        self.mainframe.rowconfigure(0, weight=1)

        # Create the "Get Data" button
        self.get_data_button = ttk.Button(self.mainframe, text="Get Data", command=self.get_data)
        self.get_data_button.grid(column=1, row=1)

        # Create the "Load Data" button
        self.load_data_button = ttk.Button(self.mainframe, text="Load Data", command=self.load_data)
        self.load_data_button.grid(column=2, row=1)

        # Create the combo box for selecting plot type
        self.plot_type = tk.StringVar()
        self.plot_type_combo = ttk.Combobox(self.mainframe, textvariable=self.plot_type)
        self.plot_type_combo['values'] = ('Scatter', 'Line')
        self.plot_type_combo.grid(column=3, row=1)

        # Create the "Generate" button
        self.generate_button = ttk.Button(self.mainframe, text="Generate", command=self.generate_plot)
        self.generate_button.grid(column=4, row=1)

        # Create the "Quit" button
        self.quit_button = ttk.Button(self.mainframe, text="Quit", command=self.root.destroy)
        self.quit_button.grid(column=5, row=1)

    def get_data(self):
        """
        Scrapes data from the website and saves it as a json file
        """
        # Open the website using selenium webdriver
        driver = webdriver.Firefox(options=options)
        driver.get("https://www.destatis.de/DE/Themen/Gesellschaft-Umwelt/Bevoelkerung/Geburten/Tabellen/lebendgeborene-vorl.html")

        # wait 5 seconds
        wait(5)

        # Close "Hinweis zum Datenschutz"
        datenschutz = driver.find_element_by_xpath("/html/body/div[3]/div/div[1]/div/div/div/div/div[2]/div/p/button")
        datenschutz.click()

        # Wait 5 Seconds
        wait(5)

        # Scrape the data using xpath
        x_axis_data = driver.find_elements_by_xpath("/html/body/div[2]/div/div/main/div/div[3]/div/table/thead/tr/th[2]")
        y_axis_data = driver.find_elements_by_xpath("/html/body/div[2]/div/div/main/div/div[3]/div/table/thead/tr/th[3]")

        # Convert the data to lists
        x_axis_data = [x.text for x in x_axis_data]
        y_axis_data = [y.text for y in y_axis_data]

        # Create a dictionary with the data
        data = {"Month": x_axis_data, "Births": y_axis_data}

        # Create the data directory if it does not exist
        if not os.path.exists("data"):
            os.mkdir("data")

        # Save the data to a json file
        with open("data/scrapped_data.json", "w") as f:
            json.dump(data, f)

        # Close the webdriver
        driver.close()

    def load_data(self):
        """
        Loads the data from the json file and changes the column names
        """
        # Load the data from the json file
        with open("data/scrapped_data.json", "r") as f:
            data = json.load(f)

        # Change the column names
        data["Month"] = data.pop("Monate")
        data["Births"] = data.pop("Geborene Kinder")

        # Save the data to the class variable
        self.data = data

    def generate_plot(self):
        """
        Generates a plot based on the selected plot type and the loaded data
        """
        # Get the selected plot type
        plot_type = self.plot_type.get()

        # Check if data is loaded
        if not hasattr(self, "data"):
            print("Please load the data first")
            return

        # Check the plot type and generate the plot
        if plot_type == "Scatter":
            plt.scatter(self.data["Month"], self.data["Births"])
        elif plot_type == "Line":
            plt.plot(self.data["Month"], self.data["Births"])

        # Show the plot
        plt.show()


data_manager = DataManager()
tk.mainloop()

I tried to get the data with the Xpath, but it didn’t help. I expect, that the code can scrap the data off the columns, save it to a json file and then plot a graph.

2

Answers


  1. Chosen as BEST ANSWER

    I now changed the code and now it is working:

            for i in range(1, 11):
            if i == 1:
                x_path = f'/html/body/div[2]/div/div/main/div/div[3]/div/table/tbody/tr[{i}]/td[2]'
                y_path = f'/html/body/div[2]/div/div/main/div/div[3]/div/table/tbody/tr[{i}]/td[3]'
                x_axis.append(driver.find_element_by_xpath(x_path).text)
                y_axis.append(driver.find_element_by_xpath(y_path).text)
            else:
                x_path = f'/html/body/div[2]/div/div/main/div/div[3]/div/table/tbody/tr[{i}]/td[1]'
                y_path = f'/html/body/div[2]/div/div/main/div/div[3]/div/table/tbody/tr[{i}]/td[2]'
                x_axis.append(driver.find_element_by_xpath(x_path).text)
                y_axis.append(driver.find_element_by_xpath(y_path).text)
    

  2. Those xpaths for x_axis_data and y_axis_data select just the header titles of the two columns, that’s why you don’t get the row values.

    Looking at the html of the table, we notice that the cells containing the months have a unique class Vorspalte, so we can select them with the css selector td[class=Vorspalte]. The cells containing the values are simply the siblings of the month cells, so we can select them with td[class=Vorspalte]+td.

    x_axis_data = driver.find_elements(By.CSS_SELECTOR, 'td[class=Vorspalte]')
    y_axis_data = driver.find_elements(By.CSS_SELECTOR, 'td[class=Vorspalte]+td')
    

    And the output is

    >>> x_axis_data = [x.text for x in x_axis_data]
    >>> x_axis_data
    ['Januar',
     'Februar',
     'März',
     'April',
     'Mai',
     'Juni',
     'Juli',
     'August',
     'September',
     'Oktober']
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search