Besseres Web-Scraping in Python mit Selen, Beautiful Soup und Pandas

Web Scraping

Mit der Programmiersprache Python ist es möglich, Daten schnell und effizient aus dem Web zu "kratzen".

Web Scraping ist definiert als:

Ein Tool, mit dem die unstrukturierten Daten im Web in maschinenlesbare, strukturierte Daten umgewandelt werden können, die zur Analyse bereit sind. (Quelle)

Web Scraping ist ein wertvolles Werkzeug für die Fähigkeiten des Datenwissenschaftlers.

Was soll ich jetzt kratzen?

Öffentlich verfügbare Daten

Die KanView-Website unterstützt „Transparenz in der Regierung“. Das ist auch der Slogan der Seite. Die Website bietet Gehaltsdaten für den Bundesstaat Kansas. Und das ist großartig!

Wie bei vielen Regierungswebsites werden die Daten jedoch in Drilldown-Links und -Tabellen vergraben. Dies erfordert häufig eine „Best-Guess-Navigation“, um die spezifischen Daten zu finden, nach denen Sie suchen. Ich wollte die öffentlichen Daten, die für die Universitäten in Kansas bereitgestellt wurden, in einem Forschungsprojekt verwenden. Die Daten mit Python zu kratzen und als JSON zu speichern, war das, was ich tun musste, um loszulegen.

JavaScript-Links erhöhen die Komplexität

Web-Scraping mit Python erfordert häufig nur die Verwendung des Beautiful Soup-Moduls, um das Ziel zu erreichen. Beautiful Soup ist eine beliebte Python-Bibliothek, die das Web-Scraping durch Durchlaufen des DOM (Document Object Model) einfacher implementiert.

Die KanView-Website verwendet jedoch JavaScript-Links. Daher funktionieren Beispiele mit Python und Beautiful Soup ohne zusätzliche Ergänzungen nicht.

Selen zur Rettung

Das Selenium-Paket wird verwendet, um die Webbrowser-Interaktion von Python aus zu automatisieren. Mit Selenium ist das Programmieren eines Python-Skripts zur Automatisierung eines Webbrowsers möglich. Danach sind diese lästigen JavaScript-Links kein Problem mehr.

from selenium import webdriver from selenium.webdriver.common.keys import Keys from bs4 import BeautifulSoup import re import pandas as pd import os

Selenium startet jetzt eine Browsersitzung. Damit Selenium funktioniert, muss es auf den Browsertreiber zugreifen. Standardmäßig wird es im selben Verzeichnis wie das Python-Skript angezeigt. Hier finden Sie Links zu Chrome-, Firefox-, Edge- und Safari-Treibern. Der folgende Beispielcode verwendet Firefox:

#launch url url = "//kanview.ks.gov/PayRates/PayRates_Agency.aspx" # create a new Firefox session driver = webdriver.Firefox() driver.implicitly_wait(30) driver.get(url) python_button = driver.find_element_by_id('MainContent_uxLevel1_Agencies_uxAgencyBtn_33') #FHSU python_button.click() #click fhsu link

Das python_button.click()oben Gesagte weist Selenium an, auf den JavaScript-Link auf der Seite zu klicken. Nachdem Selenium die Seite mit den Jobtiteln erreicht hat, übergibt er die Seitenquelle an Beautiful Soup.

Übergang zur schönen Suppe

Schöne Suppe bleibt der beste Weg, um das DOM zu durchqueren und die Daten zu kratzen. Nachdem Sie eine leere Liste und eine Zählervariable definiert haben, müssen Sie Beautiful Soup bitten, alle Links auf der Seite abzurufen, die einem regulären Ausdruck entsprechen:

#Selenium hands the page source to Beautiful Soup soup_level1=BeautifulSoup(driver.page_source, 'lxml') datalist = [] #empty list x = 0 #counter for link in soup_level1.find_all('a', id=re.compile("^MainContent_uxLevel2_JobTitles_uxJobTitleBtn_")): ##code to execute in for loop goes here

Sie können dem obigen Beispiel entnehmen, dass Beautiful Soup einen JavaScript-Link für jede Berufsbezeichnung bei der staatlichen Behörde abruft. Jetzt klickt Selenium im Codeblock der for / in-Schleife auf jeden JavaScript-Link. Beautiful Soup ruft dann die Tabelle von jeder Seite ab.

#Beautiful Soup grabs all Job Title links for link in soup_level1.find_all('a', id=re.compile("^MainContent_uxLevel2_JobTitles_uxJobTitleBtn_")): #Selenium visits each Job Title page python_button = driver.find_element_by_id('MainContent_uxLevel2_JobTitles_uxJobTitleBtn_' + str(x)) python_button.click() #click link #Selenium hands of the source of the specific job page to Beautiful Soup soup_level2=BeautifulSoup(driver.page_source, 'lxml') #Beautiful Soup grabs the HTML table on the page table = soup_level2.find_all('table')[0] #Giving the HTML table to pandas to put in a dataframe object df = pd.read_html(str(table),header=0) #Store the dataframe in a list datalist.append(df[0]) #Ask Selenium to click the back button driver.execute_script("window.history.go(-1)") #increment the counter variable before starting the loop over x += 1

Pandas: Python-Datenanalysebibliothek

Schöne Suppe gibt die Ergebnisse an Pandas weiter. Pandas verwendet seine read_htmlFunktion, um die HTML-Tabellendaten in einen Datenrahmen einzulesen. Der Datenrahmen wird an die zuvor definierte leere Liste angehängt.

Bevor der Codeblock der Schleife abgeschlossen ist, muss Selenium im Browser auf die Schaltfläche "Zurück" klicken. Auf diese Weise steht der nächste Link in der Schleife zur Verfügung, um auf die Seite mit den Stellenangeboten zu klicken.

Wenn die for / in-Schleife abgeschlossen ist, hat Selenium jeden Jobtitel-Link besucht. Beautiful Soup hat die Tabelle von jeder Seite abgerufen. Pandas hat die Daten aus jeder Tabelle in einem Datenrahmen gespeichert. Jeder Datenrahmen ist ein Element in der Datenliste. Die einzelnen Tabellendatenrahmen müssen nun zu einem großen Datenrahmen zusammengeführt werden. Die Daten werden dann mit pandas.Dataframe.to_json in das JSON-Format konvertiert:

#loop has completed #end the Selenium browser session driver.quit() #combine all pandas dataframes in the list into one big dataframe result = pd.concat([pd.DataFrame(datalist[i]) for i in range(len(datalist))],ignore_index=True) #convert the pandas dataframe to JSON json_records = result.to_json(orient='records')

Jetzt erstellt Python die JSON-Datendatei. Es ist gebrauchsfertig!

#get current working directory path = os.getcwd() #open, write, and close the file f = open(path + "\\fhsu_payroll_data.json","w") #FHSU f.write(json_records) f.close()

Der automatisierte Prozess ist schnell

Der oben beschriebene automatisierte Web-Scraping-Prozess ist schnell abgeschlossen. Selen öffnet ein Browserfenster, das funktioniert. Auf diese Weise kann ich Ihnen ein Screenshot-Video zeigen, wie schnell der Vorgang ist. Sie sehen, wie schnell das Skript einem Link folgt, die Daten erfasst, zurückgeht und auf den nächsten Link klickt. Das Abrufen der Daten von Hunderten von Links ist eine Frage von einstelligen Minuten.

Der vollständige Python-Code

Hier ist der vollständige Python-Code. Ich habe einen Import für tabellarisch eingefügt. Es ist eine zusätzliche Codezeile erforderlich, die tabellarisch verwendet wird, um die Daten hübsch auf Ihrer Befehlszeilenschnittstelle auszudrucken:

from selenium import webdriver from selenium.webdriver.common.keys import Keys from bs4 import BeautifulSoup import re import pandas as pd from tabulate import tabulate import os #launch url url = "//kanview.ks.gov/PayRates/PayRates_Agency.aspx" # create a new Firefox session driver = webdriver.Firefox() driver.implicitly_wait(30) driver.get(url) #After opening the url above, Selenium clicks the specific agency link python_button = driver.find_element_by_id('MainContent_uxLevel1_Agencies_uxAgencyBtn_33') #FHSU python_button.click() #click fhsu link #Selenium hands the page source to Beautiful Soup soup_level1=BeautifulSoup(driver.page_source, 'lxml') datalist = [] #empty list x = 0 #counter #Beautiful Soup finds all Job Title links on the agency page and the loop begins for link in soup_level1.find_all('a', id=re.compile("^MainContent_uxLevel2_JobTitles_uxJobTitleBtn_")): #Selenium visits each Job Title page python_button = driver.find_element_by_id('MainContent_uxLevel2_JobTitles_uxJobTitleBtn_' + str(x)) python_button.click() #click link #Selenium hands of the source of the specific job page to Beautiful Soup soup_level2=BeautifulSoup(driver.page_source, 'lxml') #Beautiful Soup grabs the HTML table on the page table = soup_level2.find_all('table')[0] #Giving the HTML table to pandas to put in a dataframe object df = pd.read_html(str(table),header=0) #Store the dataframe in a list datalist.append(df[0]) #Ask Selenium to click the back button driver.execute_script("window.history.go(-1)") #increment the counter variable before starting the loop over x += 1 #end loop block #loop has completed #end the Selenium browser session driver.quit() #combine all pandas dataframes in the list into one big dataframe result = pd.concat([pd.DataFrame(datalist[i]) for i in range(len(datalist))],ignore_index=True) #convert the pandas dataframe to JSON json_records = result.to_json(orient='records') #pretty print to CLI with tabulate #converts to an ascii table print(tabulate(result, headers=["Employee Name","Job Title","Overtime Pay","Total Gross Pay"],tablefmt='psql')) #get current working directory path = os.getcwd() #open, write, and close the file f = open(path + "\\fhsu_payroll_data.json","w") #FHSU f.write(json_records) f.close()

Fazit

Web scraping with Python and Beautiful Soup is an excellent tool to have within your skillset. Use web scraping when the data you need to work with is available to the public, but not necessarily conveniently available. When JavaScript provides or “hides” content, browser automation with Selenium will insure your code “sees” what you (as a user) should see. And finally, when you are scraping tables full of data, pandas is the Python data analysis library that will handle it all.

Reference:

The following article was a helpful reference for this project:

//pythonprogramminglanguage.com/web-scraping-with-pandas-and-beautifulsoup/

Reach out to me any time on LinkedIn or Twitter. And if you liked this article, give it a few claps. I will sincerely appreciate it.

//www.linkedin.com/in/davidagray/

Dave Gray (@yesdavidgray) | Twitter

The latest Tweets from Dave Gray (@yesdavidgray). Instructor @FHSUInformatics * Developer * Musician * Entrepreneur *…

twitter.com