ubuntuusers.de

Python: Code verfeinern, gibt es eine Alternative ?

Status: Gelöst | Ubuntu-Version: Ubuntu 18.04 (Bionic Beaver)
Antworten |

Pelikan666

Anmeldungsdatum:
22. September 2019

Beiträge: Zähle...

Hallo Community,

mit diesem Code übertrage ich die jeweilige Tabelle in eine CSV-File:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import requests as req
from bs4 import BeautifulSoup
import csv
import pandas as pd
urls = ["https://www.nationmaster.com/country-info/stats/Sports/Chess/GrandMasters-per-million",
        "https://www.nationmaster.com/country-info/stats/Agriculture/Agricultural-growth",
        "https://www.nationmaster.com/country-info/stats/Energy/Electric-power-consumption/KWh"]

for url in urls:
    r = req.get(url)
    soup = BeautifulSoup(r.content, 'html.parser')
    table = soup.find_all('table')[0]
    df = pd.read_html(str(table))[0]
    countries = df["COUNTRY"].tolist()
    users = df["AMOUNT"].tolist()
    with open("2.csv", 'a', newline='')as f:
        writer = csv.writer(f)
        for element in countries, users:
            writer.writerow(element)

Nun stellen sich mir folgende Fragen:

1.) Gibt es eine Alternative zu meinem Code, die auch mehrere Tabellen von mehreren Websiten übernimmt ?

Mit

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import csv
import pandas as pd

urls = ["https://www.nationmaster.com/country-info/stats/Sports/Chess/GrandMasters-per-million",
        "https://www.nationmaster.com/country-info/stats/Agriculture/Agricultural-growth",
        "https://www.nationmaster.com/country-info/stats/Energy/Electric-power-consumption/KWh"]

for url in urls:
    r = pd.read_html(url)
    with open("2.csv", 'a', newline='')as f:
        writer = csv.writer(f)
        for element in r:
            writer.writerow(element)

werden u.a. nur "AMOUNT", "COUNTRY" übernommen, aber nicht der Tabelleninhalt.

2.) Angenommen, es existiert neben "AMOUNT" und "COUNTRY", auch "A", "B", "C", allerdings nicht in jeder Tabelle. Bsp.:

1. url:"AMOUNT", "COUNTRY", "A", "B", "C"

2. url:"AMOUNT", "COUNTRY", "A", "C"

3. url:"AMOUNT", "COUNTRY", "B", "C"

Was muss an dem Code geändert werden, dass auch zusätzlich "A", "B", "C" übernommen wird. Ich hätte an eine if-Schleife Gedacht, die die Existenz von "A", "B", "C" prüft und wenn vorhanden, diese dann übernimmt.

3.) Wie wird "COUNTRY" alphabetisch sortiert und übernommen ?

LG

Axel-Erfurt

Anmeldungsdatum:
18. Mai 2016

Beiträge: 1347

Beispiel f. https://www.nationmaster.com/country-info/stats/Sports/Chess/GrandMasters-per-million

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import requests
from bs4 import BeautifulSoup
import os
from sys import platform

url_cntr = 'https://www.nationmaster.com/country-info/stats/Sports/Chess/GrandMasters-per-million'
t = requests.get(url_cntr)
html_content = t.content
html_soup = BeautifulSoup(html_content, 'html.parser')
sov_tables = html_soup.find('table')

df = pd.read_html(str(sov_tables))
df = df[0]
print(df)

with open('/tmp/table.csv', 'w') as f:
    df.to_csv(f, sep='\t', encoding='utf-8', index=False)

if platform == "linux" or platform == "linux2":
    os.system("xdg-open /tmp/table.csv")

Pelikan666

(Themenstarter)

Anmeldungsdatum:
22. September 2019

Beiträge: 19

Die Antwort beantwortet keinerlei meiner Probleme. Trotzdem Danke.

Pelikan666

(Themenstarter)

Anmeldungsdatum:
22. September 2019

Beiträge: 19

Verzeihung, es sollte heißen: Sie sind der Beste, die Antwort ist ideal !

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

@Axel-Erfurt: os.system ist veraltet, dass steht sogar wörtlich in der Python-Doku. Das subprocess Modul ist der Stand der Dinge. Gruß, noisefloor

Axel-Erfurt

Anmeldungsdatum:
18. Mai 2016

Beiträge: 1347

Wir wollen doch jetzt keine Korinthenkackerei anfangen, os.system funktioniert immer noch.

In den Ubuntu Quellen sind doch auch völlig veraltete Versionen, z.B. Pyqt5 wo dann eben manches nicht funktioniert.

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

os.system funktioniert immer noch

Darum geht es nicht. Du propagierst ein Vorgehen, was selbst in der offiziellen Python-Doku als explizit als veraltet bezeichnet wird. Bringt keinen weiter.

Eines der Kernproblem von Lernenden mit Python ist ja, dass es im Netz bergeweise veraltete und falsche Anleitungen gibt. Da brauchen wir hier nicht noch aktiv zu beitragen, dass der Zustand nicht besser wird.

Gruß, noisefloor

Pelikan666

(Themenstarter)

Anmeldungsdatum:
22. September 2019

Beiträge: 19

So, ich habe den Code geändert:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import requests
from bs4 import BeautifulSoup
import os
from sys import platform

with open('/tmp/table.csv', 'a') as f:
        for link in urls:
                page = requests.get(link)
                html = BeautifulSoup(page.content, 'html.parser')
                tables = html.find('table')
                df = pd.read_html(str(tables))
                df = df[0]
                df = df.sort_values(by=['COUNTRY'])
                df.to_csv(f, sep='\t', encoding='utf-8', index=False)
                print(df)

if platform == "linux" or platform == "linux2":
        os.system("xdg-open /tmp/table.csv")

Jetzt erhalte ich die Tabellen der jeweiligen Webseiten.

Mir ist es nicht möglich, wie in //pandas.pydata.org/pandas-docs/stable/user_guide/reshaping.html: und //pandas.pydata.org/pandas-docs/stable/reference/frame.html#combining-joining-merging: gezeigt, die Werte "AMOUNT" , "DATE" ,... der zweiten Tabelle, der ersten Tabelle zuzuordnen. Heißt konkret:

1
2
COUNTRY      AMOUNT          AMOUNT     DATE     DATE
Afghanistan  1.86 million    0.0        1993     2006

ODER

1
2
COUNTRY      AMOUNT           DATE   AMOUNT     DATE
Afghanistan  1.86 million     1993   0.0        2006

Hat jemand eine anfängerfreundliche Lösung für beide Wunschlösungen ?

LG

Pelikan666

(Themenstarter)

Anmeldungsdatum:
22. September 2019

Beiträge: 19

1
2
urls = ['https://www.nationmaster.com/country-info/stats/Sports/Chess/GrandMasters-per-million',
        'https://www.nationmaster.com/country-info/stats/Education/Children-out-of-school,-primary']

Axel-Erfurt

Anmeldungsdatum:
18. Mai 2016

Beiträge: 1347

Ich gehe davon aus das Du GRAPH nicht benötigst. Für deinen Spezialwunsch müsstest Du extra column anlegen.

Das ergibt eine Tabelle (1.Sortierung nach COUNTRY und 2.Sortierung nach DATE)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import pandas as pd
from subprocess import Popen
import os
csvFile = "/tmp/table.csv"
mlist = []

if os.path.isfile(csvFile):
    os.remove(csvFile) # alte datei löschen

urls = ['https://www.nationmaster.com/country-info/stats/Sports/Chess/GrandMasters-per-million',
        'https://www.nationmaster.com/country-info/stats/Education/Children-out-of-school,-primary']

for link in urls:
        df = pd.read_html(link, header=0, flavor='bs4')[0]
        df = df[['COUNTRY', 'AMOUNT', 'DATE']]
        df = df.sort_values(by=['COUNTRY'])
        for index, rows in df.iterrows(): 
            my_list =[rows.COUNTRY, rows.AMOUNT, rows.DATE] 
            mlist.append(my_list)

df2 = pd.DataFrame(mlist)     
df2.columns = ['COUNTRY', 'AMOUNT', 'DATE']
df2 = df2.sort_values(['COUNTRY', 'DATE'], ascending=[True, True])
print(df2)

with open(csvFile, 'a') as f:
    df2.to_csv(f, sep='\t', encoding='utf-8', index=False)
            
p = Popen(["xdg-open", csvFile])

Axel-Erfurt

Anmeldungsdatum:
18. Mai 2016

Beiträge: 1347

Hier noch eine Version mit zusätzlichen Spalten:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import pandas as pd
from subprocess import Popen
import os
from operator import itemgetter
csvFile = "/tmp/table.csv"
mlist = []

if os.path.isfile(csvFile):
    os.remove(csvFile) # alte datei löschen

urls = ['https://www.nationmaster.com/country-info/stats/Sports/Chess/GrandMasters-per-million',
        'https://www.nationmaster.com/country-info/stats/Education/Children-out-of-school,-primary']

for link in urls:
        df = pd.read_html(link, header=0, flavor='bs4')[0]
        df = df[['COUNTRY', 'AMOUNT', 'DATE']]
        df = df.sort_values(by=['COUNTRY'])
        for index, rows in df.iterrows(): 
            my_list =[rows.COUNTRY, rows.AMOUNT, rows.DATE] 
            mlist.append(my_list)


mlist2 = sorted(mlist, key=itemgetter(0))
mlist3 = []

for x in range(len(mlist2) - 1):
    if mlist2[x][0] == mlist2[x+1][0]:
        firstline = "%s\t%s\t%s" % (str(mlist2[x][0]), str(mlist2[x][1]), str(mlist2[x][2]))
        secondline = "%s\t%s" % (str(mlist2[x+1][1]), str(mlist2[x+1][2]))
        all = "%s\t%s" % (firstline, secondline)
        mlist3.append(all.split('\t'))


df2 = pd.DataFrame(mlist3)     
df2.columns = ['COUNTRY', 'AMOUNT', 'DATE', 'AMOUNT 2', 'DATE 2']
df2 = df2.sort_values(['COUNTRY'], ascending=[True])
print(df2)

with open(csvFile, 'a') as f:
    df2.to_csv(f, sep='\t', encoding='utf-8', index=False)
            
p = Popen(["xdg-open", csvFile])
         COUNTRY               AMOUNT  DATE      AMOUNT 2 DATE 2
0    Afghanistan                  0.0  2006  1.86 million   1993
1        Albania                0.315  2006         22232   2003
2        Algeria                  0.0  2006         25337   2012
3         Angola                  0.0  2006        512918   2011

Pelikan666

(Themenstarter)

Anmeldungsdatum:
22. September 2019

Beiträge: 19

Vielen Dank, wieder was gelernt. Deinen Code verstehe ich. Was ist, wenn sich jeden Tag die Spalten auf der Webseite ändern,ich nicht weiß, ob DATE, COUNTRY oder AMOUNT vorhanden ist und ich nicht jedes mal den Code ändern will, um die Tabelle zu erhalten ? Gibt es dafür auch eine anfängerfreundliche Lösung ? Sowas wie "df = df[['Alle Spalten die vorhanden sind']]"

Axel-Erfurt

Anmeldungsdatum:
18. Mai 2016

Beiträge: 1347

Mit

1
2
if os.path.isfile(csvFile):
    os.remove(csvFile) # alte datei löschen

wird ja die alte Tabelle gelöscht, mit dem Aufruf des Scripts erhältst Du also immer die neuesten Werte als Tabelle.

Antworten |