import numpy as np
import pandas as pd
import datetime
from bs4 import BeautifulSoup
import urllib.request
import re
Webscraping mit Python
Der Index der anatomischen, therapeutischen und chemischen Strukturen (ATC) wird von der WHO resp. dem norwegischen Institut für Public Health verwaltet und veröffentlicht. Die jährlich aktualisierten Daten sind im öffentlich verfügbaren ATC-Index auf der Website einsehbar. Der manuelle Websiteaufruf ist für gewisse Usecases nicht sinnvoll. Hier wird eine Möglichkeit gezeigt, wie das Webscraping resp. Parsen der ATC-Codes und deren Beschreibung mit Python umgesetzt werden kann. Der Output ist eine csv-Datei mit den drei pipegetrennten Spalten atc_name, atc_code, level
.
Zunächst werden die relevanten Packages geladen. Mit BeautifulSoup
kann das retournierte HTML-Skript bearbeitet werden.
Wenn man den ATC-Index-Wesite betrachtet und die Seite analysiert, erkennt man schnell die URL-Struktur. Dem Endpunkt wird im ersten Parameter code
der gesuchte ATC-Code übergeben. Mit einem zweiten Parameter kann man die ausführliche Beschreibung anzeigen lassen, die hier nicht benötigt wird und auf no
gesetzt ist.
= "https://atcddd.fhi.no/atc_ddd_index"
endpoint = "/?code="
para1 = "&showdescription=no" para2
Die Hilfsfunktion extract_value
dient später dazu, die ATC-Codes und deren Schreibung aus eine Liste (vom DOM-Elementen) zu extrahieren.
def extract_value(s):
return s.split('=')[1].split('&')[0]
Der Hauptfunktion parseATC
wird ein ATC-Code-Parameter übergeben Diese Funktion wird auf ein iterierbares Dataframe angewandt und somit später der komplette Index durchforstet. Im ersten Teil dieser Funktion wird die Request-URL zusammengesetzt, abgefragt und die “html-Suppe” gekocht. Der DOM des ATC-Index ist so aufgebaut, dass die ATC-Codes und die Beschreibung aus A-Elementen herausgelesen werden können, in denen der Begriff code
vorkommt. Die extrahierten Inhalte werden in einem lokalen Dataframe zwischengespeichert und dort das Level (String-Länge) des ATC-Codes ermittelt.
def parseATC(atc_as_para):
# Parse HTML content
= endpoint + para1 + atc_as_para + para2
url = urllib.request.urlopen(url).read()
html_content = BeautifulSoup(html_content, "html.parser")
soup
# Find all "a" elements in DOM with "code" inside
= soup.find_all(href=re.compile("code"))
codes
# Extract the data
= [a.text for a in codes]
atc_names = [str(a.attrs) for a in codes]
href_string
# Create local data frame
= {"atc_name": atc_names, "href": href_string}
data = pd.DataFrame(data)
df_data
# Extract atc code from href and delete href column
'atc_code'] = df_data['href'].apply(lambda x: extract_value(x))
df_data[del df_data['href']
= df_data[df_data['atc_name']!='Show text from Guidelines']
df_data
# calculate atc-level (length of atc code)
'level'] = df_data['atc_code'].apply(lambda x: len(x))
df_data[print(datetime.datetime.now()) # just showing script is running
return df_data
Zwei initiale Dataframes werden erstellt. Über df
wird später iteriert und in df_combined
werden alle Ergebnisse gespeichert.
= df = pd.DataFrame()
df_combined = df = parseATC("") df_combined
Nun folgt die zentrale Abfrage aller Daten. Die Levels 1, 3, 4 und 5 werden itrerativ abgefragt und die parseATC-Funktion nach und nach auf alle Codes und Subcodes angewendet. Diese doppelte Loop dauert rund 5 Minuten, wobei der innere Loop hier am wichtigsten ist.
= np.array([1,3,4,5])
level_iterator
for li in level_iterator:
print("level: "+str(li))
= df_combined[df_combined.level==li]
df
for row in df.itertuples():
= parseATC(row.atc_code) # global data frame
df_data = pd.concat([df_combined, df_data], ignore_index=True)
df_combined
# drop duplicates
= df_combined.drop_duplicates() df_combined
Zu Guter letzt werden die Daten sortiert nach dem ATC-Code und die finale Liste als atc_list.csv
exporiert.
= df_combined.sort_values('atc_code')
df_combined 'atc_list.csv', index=False, sep='|') df_combined.to_csv(
Bei diesem Thema sollte man jedoch die Lizenzbestimmungen beachten. Der rechtliche Aspekt wurde hier nicht geklärt, sondern nur die technsiche Machbarkeit dargestellt.
Hier findet man weitere Infos zu BeautifulSoup.