Web Scraping - Benutzernamen der Kommentatoren

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
TomBombadil
User
Beiträge: 14
Registriert: Sonntag 26. November 2017, 17:29

Hallöchen,

nachdem ich ein wenig über Web Scraping gelesen habe, dachte ich, spiele ich doch mal ein wenig rum und versuche nachzuverfolgen, wer an Diskussion X (im Python-Forum) teilgenommen hat.
Dafür habe ich nun folgenden "Protocode" geschrieben:

Code: Alles auswählen

import requests
import bs4


res = requests.get('https://www.python-forum.de/viewtopic.php?f=1&t=1689')
res.raise_for_status()
soup = bs4.BeautifulSoup(res.text, features="html.parser")


elems = soup.select('.username') # Suche nach der Klasse "username"
inaktive_benutzer = []
for x in range(len(elems)):
    variable = str(elems[x])
    if variable[:5] == "<span":
        inaktive_benutzer.append(variable[variable.find('>'):-7]) # Schneidet den Benutzernamen aus
    else:
        index = variable.find('>')
        print(variable[index+1:-4]) # Schneidet auch hier den Benutzernamen aus
if inaktive_benutzer: # Sollte es Einträge in der Liste "inaktive_benutzer" geben, werden diese angezeigt
    print("\n\nInaktive Benutzer:")
    for i in inaktive_benutzer:
        print(i)
Also ich lasse nun nach der Klasse "username" suchen, da dort auch der Benutzername vermerkt ist (was für ein Wunder :roll:), anschließend wird der Benutzername aus dem String entnommen und geprüft, ob der Benutzer noch aktiv ist (inaktive Benutzer fangen mit "<span" an)

Ich weiß, dass nur die erste Seite der Diskussion untersucht wird und Benutzer auch mehrfach vorkommen ...
Darum geht es mir im Moment aber auch nicht. Ich stelle mir die Frage, ob ich den Benutzernamen auch ohne diesen Aufwand ermitteln kann?
Zudem würde mich noch interessieren, warum der Typ von elems list ist, ich aber

Code: Alles auswählen

variable = str(elems[x])
extra in einen String umwandeln muss, damit variable nicht als

Code: Alles auswählen

<class 'bs4.element.Tag'>
behandelt wird ...
Danke für die hoffentlich schnellen Antworten und einen schönen Abend wünscht
TomBombadil
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@TomBombadil: Du willst elems[x] nicht in einen String umwandeln, weil Du mit dem Objekt arbeiten solltest.

`x` ist ein schlechter Name für einen Index, weil man bei x an eine Fließkommazahl denkt, bei `i`, `k`, `n` oder `m` kommt man viel leichter auf die Idee, dass es ein Index sein könnte. Aber eigentlich ist eine Schleife über den Index ein Anti-Pattern in Python, weil man direkt über die Elemente der Liste iterieren kann. Wie schon geschrieben, ist die Stringumwandlung eines Tag-Objekts ziemlich umständlich, weil dieses Objekt alle Information als Attribute hat, die Du brauchst.

`i` ist ein schlechter Name für einen Benutzer, `benutzer` wäre besser.

Code: Alles auswählen

elems = soup.select('.username') # Suche nach der Klasse "username"
inaktive_benutzer = []
for elem in elems:
    if elem.name == "span":
        inaktive_benutzer.append(elem.text)
    else:
        print(elem.text)

if inaktive_benutzer: # Sollte es Einträge in der Liste "inaktive_benutzer" geben, werden diese angezeigt
    print("\n\nInaktive Benutzer:")
    for benutzer in inaktive_benutzer:
        print(benutzer)    
oder kurz:

Code: Alles auswählen

inaktive_benutzer = [e.text for e in soup.select('span.username')]
besser wäre ohnehin:

Code: Alles auswählen

inaktive_benutzer = {e.text for e in soup.select('.postprofile span.username')}
aktive_benutzer = {e.text for e in soup.select('.postprofile a.username')}
TomBombadil
User
Beiträge: 14
Registriert: Sonntag 26. November 2017, 17:29

Hallo Sirius,

vielen Dank für die schnelle und hilfreiche Antwort.
*Knirsch* Ja, ich bin tatsächlich per Index über eine Liste drüber ... ich könnte intuitiv daran gedacht haben, dass ich über den Index das einzelne Zeichen der Strings aufrufen kann ... vermutlich habe ich aber einfach gar nicht gedacht.
Ebenso bei den Attributen, die das Objekt so zu bieten hat ..
An ein Set hatte ich auch schon gedacht, um die Benutzer nur einmal aufzuführen (ja, ich kenne diesen exotischen Datentyp :p), aber ich dachte - ja, tatsächlich -, ich fange erstmal mit dem Wesentliche an ...

Öhm ja, ich geh dann mal ins Bett. ;)


LG Tom

PS: Nun, nach dem obligatorischen "i" gehen mir immer die for-variablen aus. Daher fange ich danach (oder auch schon davor) immer mit anderen Variablen an. Vermutlich auch nur Übungssache. Ich versuche daran zu denken. :)
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TomBombadil: Das obligarorische `i` als Laufvariable ist ja nur für ganze Zahlen, und solche Schleifen sind in Python eher selten, also sollte *das* kein Problem sein. Für weitere ganze Zahlen als Laufvariablen und/oder Indexwerte, die in Python wie gesagt sowieso schon selten sind, bieten sich `j` und `k` an, wie man das aus der Mathematik gewohnt ist. Und so selten wie Indexwerte an sich schon sind: mehr als drei ``for``-Schleifen über ganze Zahlen/Indexwerte sollte man nicht verschachtelt haben. Also sehe ich da auch kein Problem Namen zu finden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten