Beautiful Soap : Verwendung von '.children' & '.descendants' / Formatierung des Quellcodes

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
YAPD
User
Beiträge: 120
Registriert: Dienstag 27. Juli 2021, 23:23
Wohnort: Frankfurt am Main

Hallo Zusammen,

ich habe ein Problem mit Beautiful Soap und hoffe, dass ihr mir vielleicht einen Tipp
geben könnt.

Die Basis meines Scripts ist der Quelltext dieser Website :

https://unicode.org/charts/index.html

Das einzige, was ich verändert habe, ist, dass ich den Inhalt des <style> Tags durch
"Dummy" ersetzt habe, also :

Code: Alles auswählen

<style>
# Dummy
</style>
Diesen Quelltext habe ich in einer HTML Datei gespeichert, damit ich beim Testen nicht
andauernd HTTP Request ausführe.

Die Problematik :

Zur Übung beschäftige ich mich hier nur mit dem Header, also :

Code: Alles auswählen

<head>
<meta charset="utf-8"/>

<link href="https://www.unicode.org/webscripts/standard_styles.css" type="text/css" rel="stylesheet">
<title>Code Charts</title>
<style>
# Dummy
</style>
</head>
Das Format des Quelltextes bereitet mir hier Probleme. Ich beziehe mich hier explizit
auf die Funktionen '.children' & '.descendants'. Ich habe folgende Code geschrieben :

Code: Alles auswählen

with open("index.html") as fh:
    bs = BeautifulSoup(fh, "html.parser")

    bs_elements = bs.contents  # Gesamter Source Code der Website
    bs_header = bs.head        # Gesamter Header des HTML Dokuments

    if not bs_header:
        print("The HTML Doc Has No Header !")
        exit(0)

    bs_title_tag = bs.title
    bs_title_text = bs.title.string

    print(f"title : {bs_title_text}")                  # Standard - Ausgabe des Titels
    print(f"title : {bs_title_tag}")                   # Ausgabe des Titels Inkl. Tags
    print(f"title : {bs_title_tag.contents}")          # Ausgabe des Titels als Liste"
    print()

    print(f"Header : \n")

    print(f"Numbers Of Childs      : {len( list(bs_header.children))}")
    print(f"Numbers Of Descendants : {len( list(bs_header.descendants))}")
    print()

    childs = bs_header.descendants

    for child in childs:
        print(child.name)
Wenn ich diesen so ausführe, erhalte ich :

Code: Alles auswählen

Numbers Of Childs       : 9
Numbers Of Descendants  : 11

None
meta
None
link
None
title
None
None
style
None
None


Anhand der Beschreibung habe ich es so interpretiert dass <head> nur ein child hat, und das ist head.
<title> , <metacharset> usw. sind ja Descendants. Deshalb kam mir die Zahl 9 bei den Childs sehr
hoch vor. Also habe ich meinen Code folgendermaßen angepasst :

Code: Alles auswählen

with open("index.html") as fh:
    bs = BeautifulSoup(fh, "html.parser")

    bs_elements = bs.contents  # Gesamter Source Code der Website
    bs_header = bs.head        # Gesamter Header des HTML Dokuments

    if not bs_header:
        print("The HTML Doc Has No Header !")
        exit(0)

    bs_title_tag = bs.title
    bs_title_text = bs.title.string

    print(f"title : { bs_title_text }")                  # Standard - Ausgabe des Titels
    print(f"title : { bs_title_tag }")                   # Ausgabe des Titels Inkl. Tags
    print(f"title : { bs_title_tag.contents }")          # Ausgabe des Titels als Liste"
    print()

    bs_header = bs_header.prettify().replace("\n", "")    # Ersetze Zeilenumbrüche
    header_raw = BeautifulSoup(bs_header, "html.parser")  # Erzeuge neues Beautiful Soap OBJ

    test = header_raw.find_all(string=" ")                # Ersetze leere Strings

    for t in test:
        t.replace_with("")

    print(f"Header : \n")

    print(f"Numbers Of Childs       : {len(list(header_raw.children))}")
    print(f"Numbers Of Descendants  : {len(list(header_raw.descendants))}")
    print()

    print(header_raw)

    childs = header_raw.descendants

    for child in childs:
        print(child.name)
Ergebnis :

Code: Alles auswählen

Numbers Of Childs       : 1
Numbers Of Descendants  : 11

head
None
meta
None
link
None
title
None
None
style
None
Das sieht schon besser aus, jetzt kommt eigentlich die Kernfrage :

Nach dem Entferne der Zeilenumbrüche und Leerzeichen liegt der
Quelltext in folgendem Format vor :

Code: Alles auswählen

 <head><meta charset="utf-8"/><link href="https://www.unicode.org/webscripts/standard_styles.css" rel="stylesheet" type="text/css"/><title>  Code Charts </title><style>  # Leer </style></head>
 
Wo kommt denn das None zwischen den einzelnen Tags her ?
Es stimmt ja auch mit der Anzahl der Decendants überein.
Ich kann es mir nur nicht erklären.

# 1 <head>
# 2 <meta charset>
# 3 <link>
# 4 <title>
# 5 Code Charts
# 6 </title>
# 7 <style>
# 8 # Leer
# 9 </style>
#10 </head>


Vielen Dank für Eure Hilfe !

VG
YAPD
Zuletzt geändert von YAPD am Dienstag 24. August 2021, 11:53, insgesamt 2-mal geändert.
-----
Yet Another Python Developer
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

Schau Dir einfach mal die Elemente an, die in bs_header.children bzw. .descendants drin sind, dann sollte sich die Frage ziemlich schnell beantworten.
Benutzeravatar
YAPD
User
Beiträge: 120
Registriert: Dienstag 27. Juli 2021, 23:23
Wohnort: Frankfurt am Main

Sirius3 hat geschrieben: Dienstag 24. August 2021, 11:47 Schau Dir einfach mal die Elemente an, die in bs_header.children bzw. .descendants drin sind, dann sollte sich die Frage ziemlich schnell beantworten.
Das hab ich seit gestern Abend und wenn ich nicht weiterkomme würde oder mich intensiv damit beschäftigt hätte,
hätte ich den Post nicht geschrieben, glaub mir. :)

VG
YAPD
-----
Yet Another Python Developer
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist meine Ausgabe:

Code: Alles auswählen

In [12]: [(type(d), d) for d in bs_header.head.descendants]
Out[12]: 
[(bs4.element.NavigableString, '\n'),
 (bs4.element.Tag, <meta charset="utf-8"/>),
 (bs4.element.NavigableString, '\n'),
 (bs4.element.Tag,
  <link href="https://www.unicode.org/webscripts/standard_styles.css" rel="stylesheet" type="text/css"/>),
 (bs4.element.NavigableString, '\n'),
 (bs4.element.Tag, <title>Code Charts</title>),
 (bs4.element.NavigableString, 'Code Charts'),
 (bs4.element.NavigableString, '\n'),
 (bs4.element.Tag, <style>
  # Dummy
  </style>),
 (bs4.element.NavigableString, '\n# Dummy\n'),
 (bs4.element.NavigableString, '\n')]
Damit sollte doch hoffentlich alles klar sein.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

YAPD hat geschrieben: Dienstag 24. August 2021, 11:35 Anhand der Beschreibung habe ich es so interpretiert dass <head> nur ein child hat, und das ist head.
<title> , <metacharset> usw. sind ja Descendants.
Ein Element kann nicht sein eigenes Kind sein. Es gibt natürlich verschachtelte Tags gleichen Namens (zb divs), aber so wie du das hier darstellst, ist das falsch.

Und auch Leerraum stellt Knoten dar. Nur weil du sie nicht siehst, sind sie aber trotzdem da. Sie könnten ja (wie Zeilenumbrüche in Texten) wichtig sein. Manche Parser Erlauben es, das festzulegen. Wenn der Benutzer weiß, dass der Leerraum irrelevant ist. KA ob BS das kann.
Antworten