Web scraping mit BeautifulSoup

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.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Hallo zusammen

Ich bin wieder einmal der Verzweiflung nahe. Ich versuche mit BeautifulSoup eine Yahoo News Site zu durchforschen. Mein Code sieht wie folgt aus:

Code: Alles auswählen

from bs4 import BeautifulSoup as soup  # HTML data structure
from urllib.request import urlopen as uReq  # Web client

# URl to web scrap from.
# we scrap "Daimler" from yahoo finance news
page_url = "https://finance.yahoo.com/quote/DAI.DE/?p=DAI.DE"

# opens the connection and downloads html page from url / loads it off and close it
uClient = uReq(page_url)
page_html = uClient.read()
uClient.close()

# parses html into a soup data structure to traverse html
page_soup = soup(page_html, "html.parser")

page_soup.h1

# Grabs each article

containers = page_soup.findAll("li",{"class":"js-stream-content Pos(r)"})

len(containers)

Wenn ich bei der letzten Zeile mit dem Befehl len(containers) die Länge prüfen möchte, gibt er mir als Resultat 3. Dies obwohl auf der Url https://finance.yahoo.com/quote/DAI.DE/?p=DAI.DE deutlich mehr Einträge vorhanden sind und ich meiner Meinung nach vorher mit

Code: Alles auswählen

 containers = page_soup.findAll("li",{"class":"js-stream-content Pos(r)"}) 
die richtige Stelle ausgesucht habe. Ich habe zahlreiche andere Befehle versucht aber nichts hat funktioniert. Beim manuellen Durchzälen bin ich auf 160 Einträge gekommen. Weshalb zeigt er mir den Wert nicht an?

Bin über jede Hilfe sehr dankbar!!!
ElektroBerry
User
Beiträge: 31
Registriert: Samstag 16. Mai 2020, 18:52

Du bekommst nur 3 Einträge, weil die restlichen mit einem Javascript auf der Webseite nachgeladen werden sobald du hinunter scrollst.

Die Daten von der Sitemap kann man einfacher crawlen.
https://finance.yahoo.com/sitemap/
Oder du suchst dir vielleicht eine andere Webseite.

Ansonsten funktioniert es die Webseite mit Selenium zu crawlen.
  • Dabei muss der Cookie-Button am Anfang bestätigt werden.
  • Außerdem muss die Webseite nach unten gescrollt werden.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Für Yahoo und andere Dienste sollte es fertige Bibliotheken geben, die das, was du da versuchst, für dich schon erledigen...
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Danke für die Antworten. Ich versuche das jetzt mit der Bibliothek Selenium zu lösen. Bin aber leider bereits wieder hängengeblieben.

Ich versuche mit Selenium die entsprechende Seite zu laden, komme aber bereits zu Beginn nicht wirklich weiter.

Folgendes habe ich erfasst:

Code: Alles auswählen

!pip install selenium

Import Selenium for web scraping

import selenium

Import webdriver, keys and time

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

Where does he find Chrome

PATH = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"

import socket

from socket import socket

driver = webdriver.Edge(PATH)

Bei mir kommt jeweils folgende Fehlermeldung:

Code: Alles auswählen


---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/selenium/webdriver/common/service.py in start(self)
     75                                             stderr=self.log_file,
---> 76                                             stdin=PIPE)
     77         except TypeError:

4 frames
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe': 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe'

During handling of the above exception, another exception occurred:

WebDriverException                        Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/selenium/webdriver/common/service.py in start(self)
     81                 raise WebDriverException(
     82                     "'%s' executable needs to be in PATH. %s" % (
---> 83                         os.path.basename(self.path), self.start_error_message)
     84                 )
     85             elif err.errno == errno.EACCES:

WebDriverException: Message: 'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe' executable needs to be in PATH. Please download from http://go.microsoft.com/fwlink/?LinkId=619687

zum heulen, ich komme einfach nicht vorwärts...
ElektroBerry
User
Beiträge: 31
Registriert: Samstag 16. Mai 2020, 18:52

Die Datei 'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe' konnte offensichtlich nicht gefunden werden.
Deine Importe sehen auch etwas merkwürdig aus.
"import for"?
"Where does he find Chrome"?

Ich selbst habe das mit Firefox unter Linux getestet:

Code: Alles auswählen

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from bs4 import BeautifulSoup
import time

URL = "https://finance.yahoo.com/quote/DAI.DE/?p=DAI.DE"


def scroll_to_bottom(driver):
    '''https://stackoverflow.com/a/58288921'''
    old_position = 0
    new_position = None
    while new_position != old_position:
        # Get old scroll position
        old_position = driver.execute_script(
                ("return (window.pageYOffset !== undefined) ?"
                 " window.pageYOffset : (document.documentElement ||"
                 " document.body.parentNode || document.body);"))
        # Sleep and Scroll
        time.sleep(3)  # Erhöhen wenn zuwenig Artikel gefunden werden. 210 Artikel ist das maximum.
        # 3 ist ein guter Wert, bei einer langsamen Internetverbindung.
        driver.execute_script((
                "var scrollingElement = (document.scrollingElement ||"
                " document.body);scrollingElement.scrollTop ="
                " scrollingElement.scrollHeight;"))
        # Get new position
        new_position = driver.execute_script(
                ("return (window.pageYOffset !== undefined) ?"
                 " window.pageYOffset : (document.documentElement ||"
                 " document.body.parentNode || document.body);"))


def get_url(url, press_button=None):
    opts = Options()
    opts.headless = False  # Wenn das Testen fertig ist, kann dieser Bool-Wert auf True gesetzt werden.
    browser = webdriver.Firefox(options=opts)
    browser.get(url)
    if press_button:
        browser.find_elements_by_xpath(press_button)[0].click()
    scroll_to_bottom(browser)
    html = BeautifulSoup(browser.page_source, "lxml")
    browser.close()
    return html


def main():
    soup = get_url(URL, press_button='//*[@id="consent-page"]/div/div/div/div[2]/div[2]/form/button')
    containers = soup.findAll("li",{"class":"js-stream-content Pos(r)"})
    if containers:
        print(f"Länge Containers: {len(containers)}")
        print(containers)
    else:
        print(soup.prettify())
    

if __name__ == '__main__':
    main()
Falls es mit Edge nicht funktioniert gibt es ja noch Chrome oder Firefox. Für beide gibt es einige Anleitungen, wie man es zusammen mit Selenium hinbekommt.
https://datarebellion.com/blog/quick-gu ... x-version/
https://datarebellion.com/blog/using-he ... in-python/
@pixewakb Fertige aktuelle Bibliotheken für die News scheint es nicht zu geben.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Wenn ich Deinen obigen Code verwende kommt bei mir die Meldung url is not defined.

Dabei wurde diese doch hier definiert:

Code: Alles auswählen

url = "https://finance.yahoo.com/quote/DAI.DE/?p=DAI.DE"
[\Code]

Er hat gegen die zweite Zeile in folgendem Code etwas einzuwenden:

[Code]
def main():
    soup = get_url(URL, press_button='//*[@id="consent-page"]/div/div/div/div[2]/div[2]/form/button')
    containers = soup.findAll("li",{"class":"js-stream-content Pos(r)"})
    if containers:
        print(f"Länge Containers: {len(containers)}")
        print(containers)
    else:
        print(soup.prettify())
    

if __name__ == '__main__':
    main()
[\Code]

und kommt mit folgender Fehlermeldung:

[Code]
NameError                                 Traceback (most recent call last)
<ipython-input-16-b67b09e5f161> in <module>()
     11 
     12 if __name__ == '__main__':
---> 13     main()

<ipython-input-16-b67b09e5f161> in main()
      1 
      2 def main():
----> 3     soup = get_url(URL, press_button='//*[@id="consent-page"]/div/div/div/div[2]/div[2]/form/button')
      4     containers = soup.findAll("li",{"class":"js-stream-content Pos(r)"})
      5     if containers:

NameError: name 'URL' is not defined
[\Code]
Benutzeravatar
__blackjack__
User
Beiträge: 13113
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bebbi: `url` ist ein anderer Name als `URL`.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

@ __blackjack__ Danke für den Hinweis!

Mein Dozent hat mir gesagt, dass ich weiterhin mit BeautifulSoup arbeiten soll. Selenium kennt er scheinbar nicht. Ich habe dies jetzt versucht und auch die Bibliothek PyQt5 geladen. Von PyQt5.QtWebKit müsste ich nun QWebPage installieren. Leider scheint es QWebPage im PyQt5 allerdings nicht zu geben sondern nur im PyQt4. Ich kann mir kaum vorstellen, dass die ältere Version mehr kann als die neue und gehe deshalb davon aus, dass die gewünschten Funktionen über einen anderen Befehl abgerufen werden können. Weiss hier jemand mehr?

Danke
Benutzeravatar
__blackjack__
User
Beiträge: 13113
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bebbi: Die Aussage Du müsstest weiterhin mit BeautifulSoup arbeiten weil Dein Dozent Selenium nicht kennt macht nicht so wirklich Sinn, denn auch Lösung mit Selenium benutzt ja weiterhin BeautifulSoup. Kennt Dein Dozent denn Qt?

Ich vermute Du suchst dann `QWebEnginePage`. Das wird aber alles sehr viel komplizierter als einfach Selenium zu verwenden, denn Du bastelst Dir da ja letztlich Selenium nach.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Ja, Qt scheint er zu kennen. Ich muss erlich sagen, dass ich zuwenig versiert bin um die Unterschiede zwischen Selenium und Qt zu kennen.....
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das eine ist ein Framework zum fernsteuern und Daten abgreifen von Browsern, das andere ein GUI-Framework, mit dem man zwar auch einen Browser bekommt - aber deswegen ist da nichts ferngesteuert, und auch nichts abgegriffen. Wie __blackjack__ schon sagte: du musst also alles selbst programmieren.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Das Ganze ist doch sehr verwirrend. Gemäss Euren Erklärungen würde ich lieber mit Selenium weiterfahren, welches mir aufgrund Eurer Kommentare einfacher erscheint.
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Joa. Das wuerde ich auch tun.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

So ich verfolge das Ganze nun definitiv mit Selenium weiter und habe versucht den Code von ElektroBerry in meine Colab einzubauen.

Ich schaffe es allerdings nicht (und das weder mit Chrome noch mit Edge) dass er den entsprechenden Driver findet. Ich habe die beiden Driver am gleichen Ort (C:\Program Files (x86)) abgelegt, schaffe es aber scheinbar nicht, dass er diese erkennt. Im Gegensatz zu ElektroBerry arbeite ich allerdings mit Windows...was ja aber auch möglich sein sollte oder?

Ich habe es dabei mit folgenden Varianten versucht.

Code: Alles auswählen


def get_url(url, press_button=None):
    opts = Options()
    opts.headless = False  # Wenn das Testen fertig ist, kann dieser Bool-Wert auf True gesetzt werden.
    browser = webdriver.Edge(executable_path='C:\Program Files (x86)\msedgedriver.exe')
    browser.get(url)
    if press_button:
        browser.find_elements_by_xpath(press_button)[0].click()
    scroll_to_bottom(browser)
    html = BeautifulSoup(browser.page_source, "lxml")
    browser.close()
    return html
def main():
    soup = get_url(url, press_button='//*[@id="consent-page"]/div/div/div/div[2]/div[2]/form/button')
    containers = soup.findAll("li",{"class":"js-stream-content Pos(r)"})
    if containers:
        print(f"Länge Containers: {len(containers)}")
        print(containers)
    else:
        print(soup.prettify())
    

if __name__ == '__main__':
    main()

[\Code]

Aber auch mit 

[Code]

def get_url(url, press_button=None):
    opts = Options()
    opts.headless = False  # Wenn das Testen fertig ist, kann dieser Bool-Wert auf True gesetzt werden.
    browser = webdriver.Edge(options=opts)
    browser.get(url)
    if press_button:
        browser.find_elements_by_xpath(press_button)[0].click()
    scroll_to_bottom(browser)
    html = BeautifulSoup(browser.page_source, "lxml")
    browser.close()
    return html
def main():
    soup = get_url(url, press_button='//*[@id="consent-page"]/div/div/div/div[2]/div[2]/form/button')
    containers = soup.findAll("li",{"class":"js-stream-content Pos(r)"})
    if containers:
        print(f"Länge Containers: {len(containers)}")
        print(containers)
    else:
        print(soup.prettify())
    

if __name__ == '__main__':
    main()

[\Code]

Zudem habe ich auch versucht den Pfadnamen jeweils mit .exe zu ergänzen, was auch erfolglos war. Etwas anderes fällt mir ehrlich gesagt nicht ein..
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Die entsprechenden Fehlermeldungen sind wie folgt:

Code: Alles auswählen


---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/selenium/webdriver/common/service.py in start(self)
     75                                             stderr=self.log_file,
---> 76                                             stdin=PIPE)
     77         except TypeError:

6 frames
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Program Files (x86)\\msedgedriver.exe': 'C:\\Program Files (x86)\\msedgedriver.exe'

During handling of the above exception, another exception occurred:

WebDriverException                        Traceback (most recent call last)
/usr/local/lib/python3.6/dist-packages/selenium/webdriver/common/service.py in start(self)
     81                 raise WebDriverException(
     82                     "'%s' executable needs to be in PATH. %s" % (
---> 83                         os.path.basename(self.path), self.start_error_message)
     84                 )
     85             elif err.errno == errno.EACCES:

WebDriverException: Message: 'C:\Program Files (x86)\msedgedriver.exe' executable needs to be in PATH. Please download from http://go.microsoft.com/fwlink/?LinkId=619687

[\Code]


respektive

[Code]

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-117-aff3ce62f2f7> in <module>()
     43 
     44 if __name__ == '__main__':
---> 45     main()
     46 

1 frames
<ipython-input-117-aff3ce62f2f7> in get_url(url, press_button)
     24     opts = Options()
     25     opts.headless = False  # Wenn das Testen fertig ist, kann dieser Bool-Wert auf True gesetzt werden.
---> 26     browser = webdriver.Edge(Options=opts)
     27     browser.get(url)
     28     if press_button:

TypeError: __init__() got an unexpected keyword argument 'Options'

[\Code]
Benutzeravatar
__blackjack__
User
Beiträge: 13113
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bebbi: Du schreibst was von Windows aber die Tracebacks sind eindeutig von einem Linux-System. Du kannst nicht in Notebooks die auf einem Server irgendwo im Internet laufen einfach so auf Pfade auf Deinem lokalen Rechner zugreifen. Und selbst wenn das ginge, könnte das Linux auf dem Server nix mit einer Windows-EXE anfangen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Danke für die Antwort, dass die Tracebacks auf Linux ausgerichtet sind, habe ich, auch wenn dies scheinbar offensichtlich ist nicht gemerkt. Das dies nicht funktioniert macht Sinn. Ich werde entsprechend schauen was ich dazu zu Windows finde. Das zweite ist für mich auch neu. Bedeutet dies, dass ich das Scraping nur mit meinem lokal installierten Python durchführen kann und die - eigentilch ganz angenehmen - Formate wie Colab oder Jupiter Notebook dazu nicht geeignet sind?
__deets__
User
Beiträge: 14543
Registriert: Mittwoch 14. Oktober 2015, 14:29

Colab läuft halt in der cloud. Und die ist weder Windows, noch hast du da üblicherweise grafische Oberflächen.

Jupyter kannst du auch lokal laufen lassen.
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

So, ich werde jetzt das Ganze mit Selenium und PyCharm weiterverfolgen. Ich hoffe ich kann die verlorene Zeit noch irgendwie aufholen.

Ich habe Selenium in PyCharm installierrt und auch die Sache mit dem Chrometreiber hinbekommen. Nun habe ich folgenden Code geschrieben:

Code: Alles auswählen


from selenium import webdriver
import pandas as pd

url = 'https://finance.yahoo.com/quote/DAI.DE?p=DAI.DE&.tsrc=fin-srch'

driver = webdriver.Chrome('C:/Users/Startklar/Desktop/CFDS/chromedriver.exe')
driver.get(url)

articles = driver.find_elements_by_class_name('cf')

for article in articles:
    source = article.find_element_by_xpath('.//*[@id="quoteNewsStream-0-Stream"]/ul/li[5]/div/div/div[1]/div/span[1]').text
    date = article.find_element_by_xpath('.//*[@id="quoteNewsStream-0-Stream"]/ul/li[5]/div/div/div[1]/div/span[2]').text
    print(source,date)

[\Code]

PyCharm gibt mir keine Fehlermeldung an, aber - trotz dem print Befehl - auch keine Ergebinsse.... Woran liegt das denn?
Bebbi
User
Beiträge: 144
Registriert: Dienstag 21. April 2020, 19:21

Ich habe jetzt untenstehenden Befehl hinzugefügt, mit welchem mir die gesamte Seite geladen werden sollte. Leider erhalte ich auch damit keine Resultate.

Code: Alles auswählen


driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

Antworten