Eine häufige Situation beim Web-Scraping ist, dass die Liste der Parsing-Ergebnisse sehr lang ist und gemischte Informationen enthält.
Vielleicht ist Ihnen beispielsweise aufgefallen, dass unsere vorherigen Bilder ein alt-Attribut enthalten können oder auch nicht.
Oder stellen Sie sich vor, wir würden alle Links aus dem Artikel extrahieren. Wir alle wissen, dass ein Wikipedia-Artikel SEHR VIELE Links enthält, und wir möchten vielleicht keine vollständige Liste davon. Das Ergebnis wird externe und interne Links, Referenzen und Zitate enthalten, daher müssen wir sie in mehrere Kategorien einteilen.
Um dieses Problem zu lösen, werden wir eine Lambda-Funktion verwenden. Im Grunde genommen nimmt die Lambda-Funktion jedes Element aus der Ergebnisliste als Parameter und wendet die von uns definierte Bedingung an, genau wie bei der Verwendung eines Filters.
Nehmen wir als praktisches Beispiel an, wir müssen alle internen Links extrahieren, auf die entsprechenden Artikel zugreifen und für jeden eine Zusammenfassung erstellen. Da einer der Anwendungsfälle von Python die künstliche Intelligenz ist, könnte dieses Beispiel eine hervorragende Anwendung zur Gewinnung von Trainingsdaten sein.
Zunächst müssen wir die NLTK-Bibliothek installieren, da die Erstellung einer Zusammenfassung die Verarbeitung menschlicher Sprache erfordert.
pip install -U nltk
Und natürlich müssen wir sie in unseren Code importieren:
import re
import nltk
import heapq
# need to download only for the first execution
# warning: the size of the dataset is big; hence it will take time
nltk.download()
Hinweis: Wenn Sie ein macOS-Benutzer sind, erhalten Sie möglicherweise die Fehlermeldung „SSL: certificate verify failed“. Die Ursache dafür könnte sein, dass Python 3.6 eine eingebettete Version von OpenSSL verwendet. Sie müssen lediglich den Ordner öffnen, in dem Sie Python installiert haben, und diese Datei ausführen:
/Your/Path/Here/Python 3.6/Install Certificates.command
Wie du siehst, haben wir auch die re-Bibliothek importiert, die für Operationen mit regulären Ausdrücken verwendet wird, sowie heapq, eine Implementierung einer Heap-Warteschlange.
Gut, wir haben alles, was wir brauchen, um mit dem Schreiben des Codes zu beginnen. Beginnen wir damit, die internen Links zu extrahieren. Wenn Sie zum Browser zurückkehren, werden Sie einige Dinge an den Elementen bemerken, die uns interessieren.
Das wären:
- Das href-Attribut hat einen Wert;
- Der Wert von „href“ beginnt mit „/wiki/“;
- Das übergeordnete Element des Links ist ein -Tag;
Diese Merkmale helfen uns dabei, die benötigten Links von allen anderen zu unterscheiden.
Da wir nun wissen, wie wir die Links finden, schauen wir uns an, wie wir sie extrahieren können.
count = 0
def can_do_summary(tag):
global count
if count > 10: return False
# Reject if parent is not a paragraph
if not tag.parent.name == 'p': return False
href = tag.get('href')
# Reject if href is not set
if href is None: return False
# Reject is href value does not start with /wiki/
if not href.startswith('/wiki/'): return False
compute_summary(href)
return True
def extract_links(soup):
soup.find_all(lambda tag: tag.name == 'a' and can_do_summary(tag))
def main():
URL = 'https://en.wikipedia.org/wiki/Beer'
page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
extract_links(soup)
main()
Okay, was ist hier also passiert? Wenn wir uns die Funktion `extract_links()` ansehen, erkennen wir, dass wir anstelle eines Tag-Namens eine Lambda-Funktion als Parameter an die Methode `.find_all()` übergeben haben. Das bedeutet, dass wir aus allen Tags des HTML-Dokuments nur diejenigen auswählen, die unserer Bedingung entsprechen.
Wie du sehen kannst, besteht die Bedingung für ein Tag darin, ein Link zu sein und von der oben definierten Funktion `can_do_summary()` akzeptiert zu werden. Dort lehnen wir alles ab, was nicht den zuvor beobachteten Merkmalen entspricht. Außerdem haben wir eine globale Variable verwendet, um die Anzahl der extrahierten Links auf 10 zu begrenzen. Wenn du alle benötigst, kannst du die Variable `count` gerne entfernen.
Am Ende rufen wir die Funktion `compute_summary()` für den neu gefundenen Link auf. Dort wird der Artikel zusammengefasst.
def compute_summary(href):
global count
full_link = 'https://en.wikipedia.org' + href
page = requests.get(full_link)
soup = BeautifulSoup(page.content, 'html.parser')
# Concatenate article paragraphs
paragraphs = soup.find_all('p')
article_text = ""
for p in paragraphs:
article_text += p.text
# Removing Square Bracket, extra spaces, special characters and digits
article_text = re.sub(r'\[[0-9]*\]', ' ', article_text)
article_text = re.sub(r'\s+', ' ', article_text)
formatted_article_text = re.sub('[^a-zA-Z]', ' ', article_text)
formatted_article_text = re.sub(r'\s+', ' ', formatted_article_text)
# Converting text to sentences
sentence_list = nltk.sent_tokenize(article_text)
# Find frequency of occurrence of each word
stopwords = nltk.corpus.stopwords.words('english')
word_frequencies = {}
for word in nltk.word_tokenize(formatted_article_text):
if word not in stopwords:
if word not in word_frequencies.keys():
word_frequencies[word] = 1
else:
word_frequencies[word] += 1
maximum_frequency = max(word_frequencies.values())
for word in word_frequencies.keys():
word_frequencies[word] = (word_frequencies[word] / maximum_frequency)
# Calculate the score of each sentence
sentence_scores = {}
for sent in sentence_list:
for word in nltk.word_tokenize(sent.lower()):
if word in word_frequencies.keys():
if len(sent.split(' ')) < 30:
if sent not in sentence_scores.keys():
sentence_scores[sent] = word_frequencies[word]
else:
sentence_scores[sent] += word_frequencies[word]
# Pick top 7 sentences with highest score
summary_sentences = heapq.nlargest(7, sentence_scores, key=sentence_scores.get)
summary = '\n'.join(summary_sentences)
count += 1
Kurz gesagt: Wir senden eine HTTP-Anfrage an die neu gefundene URL und wandeln das Ergebnis in ein BeautifulSoup-Objekt um, genau wie zu Beginn des Artikels.
Um eine Zusammenfassung zu erstellen, extrahieren wir alle Absätze aus dem Artikel und fügen sie aneinander. Danach entfernen wir alle Sonderzeichen, die die Berechnungen stören könnten.
Einfach ausgedrückt wird eine Zusammenfassung erstellt, indem die häufigsten Wörter ermittelt werden und jeder Satz eine Punktzahl erhält, die auf der Häufigkeit seiner Wörter basiert. Am Ende wählen wir die 7 Sätze mit der höchsten Punktzahl aus.
Dies ist nicht das Thema unseres Artikels, aber Sie können hier mehr darüber lesen, wenn Sie neugierig sind oder sich sogar für natürliche Sprachverarbeitung begeistern.