Webscraping for-Schleife (mehrere Links)

Code-Stücke können hier veröffentlicht werden.
Antworten
sommares
User
Beiträge: 4
Registriert: Mittwoch 3. Februar 2021, 13:44

Mittwoch 3. Februar 2021, 14:08

Hallo zusammen,

ich bin gerade an einem Webscraping Projekt und versuche innerhalb von Links, die ich mir scrape, weitere Infos auszugeben.

Code: Alles auswählen

import requests
from bs4 import BeautifulSoup

# 1. Stepstone nach Junior Consultant Jobs durchsuchen 

url = 'https://www.stepstone.de/jobs/Junior-Consultant.html'
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:39.0)'}

res = requests.get(url, headers=headers)

soup = BeautifulSoup(res.text, 'html.parser')

angebote = soup.select('.job-element__url')

print(len(angebote))

# 2. Innerhalb der Berufe die Anforderungen scrapen

for angebot in angebote:
  print(angebot.get('href'))
  for angebot in angebote:
      print(angebot.get('at-section-text-profile-content'))
Ich lasse mir damit eine Liste von Links ausgeben lassen und versuche innerhalb von jedem Link das Element "at-section-text-profile-content" auszulesen, jedoch erhalte ich immer "none".

Es sollte so aussehen:
<Link/Beruf>
Anforderung 1...
Anforderung 2...


Ich bin um jede Hilfe dankbar!
Benutzeravatar
__blackjack__
User
Beiträge: 8430
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 3. Februar 2021, 16:52

@sommares: Du liest da Attrbut der <a>-Elemente aus und die haben so ein Attribut nicht. Die haben auch die Anforderungen nicht als Kindelemente. Da ist nur der Link drin. Den Text "at-section-text-profile-content" finde ich in der gesamten Seite nicht.
“For every complex problem, there is a solution that is simple, neat, and wrong.” — H. L. Mencken
sommares
User
Beiträge: 4
Registriert: Mittwoch 3. Februar 2021, 13:44

Mittwoch 3. Februar 2021, 17:24

__blackjack__ hat geschrieben:
Mittwoch 3. Februar 2021, 16:52
@sommares: Du liest da Attrbut der <a>-Elemente aus und die haben so ein Attribut nicht. Die haben auch die Anforderungen nicht als Kindelemente. Da ist nur der Link drin. Den Text "at-section-text-profile-content" finde ich in der gesamten Seite nicht.
danke für die Antwort.
ich habe beispielsweise mal den zweiten Link geöffnet der erscheint (https://www.stepstone.de/stellenangebot ... mb_m_0_0_0) und dort unter "Dein Profil" finde ich das Attribut "at-section-text-profile-content".

wie lese ich die div-attribute aus, damit es gefunden wird?
Benutzeravatar
__blackjack__
User
Beiträge: 8430
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 3. Februar 2021, 17:50

@sommares: Wenn die Daten auf einer anderen Webseite sind als das <a>-Element dann muss man sich die Webseite natürlich erst einmal holen. Also selber aktiv vom Server abfragen und parsen und dann *da* drin nach den Daten suchen.
“For every complex problem, there is a solution that is simple, neat, and wrong.” — H. L. Mencken
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Donnerstag 4. Februar 2021, 08:10

Hab das mal versucht umzusetzen, allerdings habe ich kaum Ahnung von HTML, daher denke ich dass meine Methode nicht wirklich robust ist. Da ich auf Klassen mit komischen Bezeichnungen zugreife wie z.B. "sc-jwKygS guXuLZ sc-cmTdod cgayqw". Ist das so üblich beim erstellen von Websiten oder wieso werden solche Bezeichnungen verwendet? Jedenfalls funktioniert das Script soweit. Würde mich aber trotzdem über Verbesserungsvorschläge oder Anmerkungen freuen, von jemandem der von dem ganzen Thema mehr Ahnung hat.

Code: Alles auswählen

from bs4 import BeautifulSoup
import requests

HEADERS = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"}

def make_soup(url):
    page = requests.get(url, headers=HEADERS)
    return BeautifulSoup(page.content, "html.parser")

def get_hrefs_from_soup(soup):
    results = soup.find_all('article',{'class':'job-element'})
    return [result.find('a',{'class':'job-element__url job-element__url--shortened-title'}).get('href') for result in results]

def main():
    soup = make_soup("https://www.stepstone.de/jobs/Junior-Consultant.html")
    hrefs_from_results = get_hrefs_from_soup(soup)
    for href in hrefs_from_results:
        soup_from_href =  make_soup(href)
        title = soup_from_href.find('h1',{'class':'listing__job-title at-header-company-jobTitle sc-jAaTju egCVVj'}).get_text().strip()
        company = soup_from_href.find('h1',{'class':'sc-jWBwVP yIdcv'}).get_text().strip()
        location = soup_from_href.find('li',{'class':'at-listing__list-icons_location js-map-offermetadata-link sc-iAyFgw hdLeLh'}).get_text().strip()
        requirements = soup_from_href.find_all('div',{'class':'sc-jwKygS guXuLZ sc-cmTdod cgayqw'})[2].get_text().strip()
        print(f"[Bezeichnung:]\n{title}\n")
        print(f"[Firma:]\n{company}\n")
        print(f"[Ort:]\n{location}\n")
        print(f"[Anforderungen:]\n{requirements}\n\n")


if __name__ == "__main__":
    main()
DasIch
User
Beiträge: 2608
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Donnerstag 4. Februar 2021, 19:43

Jankie hat geschrieben:
Donnerstag 4. Februar 2021, 08:10
Da ich auf Klassen mit komischen Bezeichnungen zugreife wie z.B. "sc-jwKygS guXuLZ sc-cmTdod cgayqw". Ist das so üblich beim erstellen von Websiten oder wieso werden solche Bezeichnungen verwendet?
Die sind höchstwahrscheinlich generiert. Das macht man um sicherzustellen dass die Namen global einzigartig sind oder um die Größe von Dateien zu minimieren.

Wie robust dein Scraper ist wenn du von solchen Namen abhängst, hängt davon ab wie die Namen generiert werden. Ich würde erwarten dass du schon ziemlich schnell merken wirst, wenn es nicht robust sein sollte.
Benutzeravatar
__blackjack__
User
Beiträge: 8430
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 4. Februar 2021, 19:58

Die Frage ist ob das überhaupt nötig ist, denn da scheinen ja auch semantische Klassen in Klartext vorhanden zu sein. Reichen die zur Identifizierung nicht aus? Am besten auch in Kombination mit etwas gezielterem statt immer die gesamte Seite nach allen Überschriften oder gar Listenelementen zu durchsuchen.
“For every complex problem, there is a solution that is simple, neat, and wrong.” — H. L. Mencken
sommares
User
Beiträge: 4
Registriert: Mittwoch 3. Februar 2021, 13:44

Donnerstag 4. Februar 2021, 20:57

Jankie hat geschrieben:
Donnerstag 4. Februar 2021, 08:10
Hab das mal versucht umzusetzen, allerdings habe ich kaum Ahnung von HTML, daher denke ich dass meine Methode nicht wirklich robust ist. Da ich auf Klassen mit komischen Bezeichnungen zugreife wie z.B. "sc-jwKygS guXuLZ sc-cmTdod cgayqw". Ist das so üblich beim erstellen von Websiten oder wieso werden solche Bezeichnungen verwendet? Jedenfalls funktioniert das Script soweit. Würde mich aber trotzdem über Verbesserungsvorschläge oder Anmerkungen freuen, von jemandem der von dem ganzen Thema mehr Ahnung hat.

Code: Alles auswählen

from bs4 import BeautifulSoup
import requests

HEADERS = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"}

def make_soup(url):
    page = requests.get(url, headers=HEADERS)
    return BeautifulSoup(page.content, "html.parser")

def get_hrefs_from_soup(soup):
    results = soup.find_all('article',{'class':'job-element'})
    return [result.find('a',{'class':'job-element__url job-element__url--shortened-title'}).get('href') for result in results]

def main():
    soup = make_soup("https://www.stepstone.de/jobs/Junior-Consultant.html")
    hrefs_from_results = get_hrefs_from_soup(soup)
    for href in hrefs_from_results:
        soup_from_href =  make_soup(href)
        title = soup_from_href.find('h1',{'class':'listing__job-title at-header-company-jobTitle sc-jAaTju egCVVj'}).get_text().strip()
        company = soup_from_href.find('h1',{'class':'sc-jWBwVP yIdcv'}).get_text().strip()
        location = soup_from_href.find('li',{'class':'at-listing__list-icons_location js-map-offermetadata-link sc-iAyFgw hdLeLh'}).get_text().strip()
        requirements = soup_from_href.find_all('div',{'class':'sc-jwKygS guXuLZ sc-cmTdod cgayqw'})[2].get_text().strip()
        print(f"[Bezeichnung:]\n{title}\n")
        print(f"[Firma:]\n{company}\n")
        print(f"[Ort:]\n{location}\n")
        print(f"[Anforderungen:]\n{requirements}\n\n")


if __name__ == "__main__":
    main()
vielen Dank für dein Skript!
Allerdings erhalte ich die Meldung "AttributeError: 'NoneType' object has no attribute 'get'". Ich habe mal bisschen rumprobiert, kriege den Fehler aber nicht weg...
hättest du noch eine Idee?
Benutzeravatar
sparrow
User
Beiträge: 2610
Registriert: Freitag 17. April 2009, 10:28

Donnerstag 4. Februar 2021, 21:53

Leider verrätst du nicht, wo die Ausnahme auftritt. Davon hängt ab, was du prüfen musst. Du musst damit rechnen, dass ein Element auf der Seite nicht gefunden wird. Entweder, weil sich die seltsamen Klassennamen geändert haben oder weil eine Fehlerseite angezeigt wird - zum Beispiel weil die Seite die da abrufst Gegenmaßnahmen ergreift. Die wenigsten Seiten mögen und erlauben das automatische Abgreifen ihrer Daten.
Antworten