LAPRAS Output Relay Tag 1 Artikel!
Hallo! Dies ist @Chanmoro, ein LAPRAS-Crawler-Ingenieur! Dieses Mal werden LAPRAS-Mitglieder unter dem Titel LAPRAS Output Relay bis Ende März täglich Artikel ausgeben! Studiensitzungen und Konferenzen wurden aufgrund des jüngsten Koronaschocks abgesagt, aber ich hoffe, dass dieses LAPRAS-Ausgangsrelais die Eingangs- und Ausgangsmotivation von Ingenieuren unterstützt.
Übrigens arbeite ich normalerweise als Crawler-Entwickler, aber ich möchte diesen Artikel über den Entwicklungsfluss bei der Entwicklung eines neuen Crawlers schreiben.
Hier werden als Beispiel die Informationen des Artikels in LAPRAS NOTE, dem von LAPRAS betriebenen Medium des Unternehmens, erfasst und in eine Datei im JSON-Format ausgegeben. Ich möchte ein Beispiel für die Implementierung eines Crawlers vorstellen.
Bei der Montage eines Crawlers werden die folgenden Schritte grob ausgeführt, um zu untersuchen, zu entwerfen und zu implementieren.
Ich werde jedes im Detail erklären.
Wenn Sie einen kurzen Blick auf die Seite LAPRAS NOTE werfen, wird auf der oberen Seite eine Liste mit Artikeln angezeigt, die Sie vom Link zum Artikel in der Liste zur Seite jedes Artikels führt.
Sie können sehen, dass es ungefähr aus zwei Arten von Seiten besteht.
--Artikellistenseite --Artikel-Detailseite
Schauen wir uns die Erstellung dieser Seiten genauer an.
Auf der Artikellistenseite können Sie sehen, dass der Artikeltitel, die Kategorie, das Veröffentlichungsdatum, die Digest-Informationen des Textes und die Links zur Detailseite jedes Artikels wie folgt veröffentlicht werden.
Sie können auch sehen, dass der Paging-Link zur nächsten Seite unten auf der Seite angezeigt wird.
Wenn Sie zur zweiten Seite gehen, die momentan die letzte Seite ist, können Sie sehen, dass der Link zur nächsten Seite hier nicht angezeigt wird.
Wenn also ein Link zur nächsten Seite vorhanden ist, wechseln Sie zur nächsten Seite. Wenn kein Link vorhanden ist, scheint es sich um die letzte Seite zu handeln.
Schauen wir uns als nächstes den Inhalt der Artikeldetailseite an. Auf dieser Seite können Sie den Titel des Artikels, das Veröffentlichungsdatum, die Kategorie und den Artikelkörper anzeigen.
Um alle Artikel abzurufen, müssen Sie anscheinend nicht daran denken, von der Artikeldetailseite auf eine andere Seite zu wechseln.
Bei der zuvor erwähnten Site-Umfrage habe ich festgestellt, dass es wahrscheinlich ist, dass diese Daten extrahiert werden können.
--Artikel --Titel
Außerdem habe ich festgestellt, dass Sie, um die obigen Daten für alle Artikel von LAPRAS NOTE zu extrahieren, der Site gemäß dem folgenden Ablauf folgen sollten.
Als Nächstes untersuchen wir, wie die Zieldaten extrahiert werden, indem wir uns die HTML-Struktur der zu crawlenden Seite ansehen. Hier verwenden wir die Entwicklertools des Webbrowsers.
Ich möchte Folgendes aus der Artikellistenseite extrahieren.
Suchen Sie zunächst das Element, das einem Artikel entspricht, um den Link zur Artikeldetailseite zu finden.
Bei Betrachtung der HTML-Struktur der Seite stellte ich fest, dass das "div" -Element mit der Klasse "post-item" dem Umfang eines Artikels entspricht. Wenn Sie sich die Elemente im entsprechenden "div.post-item" ansehen, können Sie auch sehen, dass die URL der Artikeldetailseite im "a" -Tag direkt unter dem "h2" -Tag festgelegt ist.
Der CSS-Pfad, um dieses Tag anzugeben, das Sie erhalten möchten, lautet "div.post-item h2> a".
Die aktuelle Erwartung ist, dass Sie auf der ersten Seite der Artikelliste ** 10 Elemente erhalten sollten, die diesem CSS-Pfad entsprechen **, aber ich würde gerne sehen, ob ich irrelevante URLs erhalten kann. Sie können beispielsweise den folgenden JavaScript-Code über Ihre Browserkonsole ausführen, um festzustellen, wie viele CSS-Selektoren übereinstimmen.
document.querySelectorAll("#main div.post-item h2 > a").length
Wenn Sie Folgendes über die Browserkonsole ausführen, während die erste Seite der Artikellistenseite angezeigt wird, erhalten Sie das Ergebnis "10", sodass Sie bestätigen können, dass der obige CSS-Pfad in Ordnung zu sein scheint.
Suchen Sie dann nach der Link-URL zur nächsten Seite der Artikellistenseite.
Wenn Sie sich die Elemente von nav.navagation.pagination
ansehen, können Sie sehen, dass dies der Bereich ist, in dem die Links zu jeder Seite und die Links zur nächsten Seite angezeigt werden.
Sie können sehen, dass das "a" -Tag mit den Klassen "next" und "page-numbers" in diesem Element auf die Link-URL zur nächsten Seite gesetzt ist.
Der CSS-Pfad, um dies zu erhalten, wäre "nav.navigation.pagination a.next.page-numbers". Lassen Sie uns die Anzahl der Fälle überprüfen, die tatsächlich über die Konsole des Browsers abgerufen werden können.
document.querySelectorAll("nav.navigation.pagination a.next.page-numbers").length
Als ich es ausgeführt habe, habe ich das Ergebnis "1" erhalten, daher scheint es in Ordnung zu sein, die Ziel-Link-URL abzurufen.
Sie können auch sehen, dass das Element des Links zur nächsten Seite nicht auf der zweiten Seite angezeigt wird, die die letzte Seite ist.
Für alle Fälle habe ich über die Konsole nach dem Element des Links zur nächsten Seite gesucht und das Ergebnis "0" erhalten.
Ich möchte Folgendes aus der Artikeldetailseite extrahieren.
--Titel
Schauen Sie sich wie zuvor die HTML-Struktur an, um den CSS-Pfad zum gewünschten Element zu finden.
Das Verfahren ist das gleiche wie zuvor, daher werde ich es weglassen, aber ich habe festgestellt, dass ich die Daten aus den folgenden Elementen extrahieren sollte.
--Titel
- h1
article header div.entry-meta
--Kategoriearticle header div.entry-meta a
article div.entry-content
Die Logik für das Crawlen ist aus den bisher untersuchten Inhalten fast klar, daher werden wir sie in Code implementieren. Es spielt keine Rolle, welche Sprache Sie in den meisten Fällen verwenden, aber hier möchte ich eine Beispielimplementierung in Python schreiben.
Zunächst werde ich aufzählen, was fest zu tun ist.
# TODO: https://note.lapras.com/Zugreifen
# TODO:Rufen Sie die Artikeldetail-URL aus dem Antwort-HTML ab
# TODO:Holen Sie sich, wenn es einen Link auf der nächsten Seite gibt
# TODO:Rufen Sie die Artikeldetailseite auf
# TODO:Artikelinformationen aus Antwort-HTML abrufen
# TODO: URL
# TODO:Titel
# TODO:Veröffentlichungsdatum
# TODO:Kategorie
# TODO:Artikel Text
#Speichern Sie die abgerufenen Daten in einer Datei im JSON-Format
Passen Sie vorsichtshalber zum Zeitpunkt der Implementierung das Zugriffsintervall an, indem Sie den Ruhezustand entsprechend einfügen, um den Crawling-Zieldienst nicht zu überlasten. In den meisten Fällen ist es als Leitfaden besser, sie innerhalb von höchstens 1 Anforderung pro Sekunde zu halten. Es ist jedoch ein Problem, wenn der entsprechende Dienst durch Crawlen heruntergefahren wird, also vom Crawl-Ziel Überprüfen Sie immer, ob die Antwort ein Fehler ist.
Für Python schreibe ich oft Crawler, indem ich Anfragen und Beautiful Soup kombiniere. Informationen zur Verwendung der Bibliothek finden Sie auch unter Schöne Suppe in 10 Minuten.
Es gibt Frameworks, die Crawler wie [Scrapy] implementieren (https://qiita.com/Chanmoro/items/f4df85eb73b18d902739), aber um zunächst ein vollständiges Bild des Crawlers zu erhalten, ohne das Framework zu verwenden. Es wird empfohlen, es zu versuchen.
Wenn Sie den Prozess, den Sie schreiben möchten, in festem Code ausdrücken, ohne tief über das Design nachzudenken, sieht es so aus.
import json
import time
import requests
from bs4 import BeautifulSoup
def parse_article_list_page(html):
"""
Analysieren Sie die Artikellistenseite und extrahieren Sie Daten
:param html:
:return:
"""
soup = BeautifulSoup(html, 'html.parser')
next_page_link = soup.select_one("nav.navigation.pagination a.next.page-numbers")
return {
"article_url_list": [a["href"] for a in soup.select("#main div.post-item h2 > a")],
"next_page_link": next_page_link["href"] if next_page_link else None
}
def crawl_article_list_page(start_url):
"""
Durchsuchen Sie die Artikellistenseite, um alle Artikeldetail-URLs abzurufen
:return:
"""
print(f"Accessing to {start_url}...")
# https://note.lapras.com/Zugreifen
response = requests.get(start_url)
response.raise_for_status()
time.sleep(10)
#Rufen Sie die Artikeldetail-URL aus dem Antwort-HTML ab
page_data = parse_article_list_page(response.text)
article_url_list = page_data["article_url_list"]
#Holen Sie sich, wenn es einen Link auf der nächsten Seite gibt
while page_data["next_page_link"]:
print(f'Accessing to {page_data["next_page_link"]}...')
response = requests.get(page_data["next_page_link"])
time.sleep(10)
page_data = parse_article_list_page(response.text)
article_url_list += page_data["article_url_list"]
return article_url_list
def parse_article_detail(html):
"""
Analysieren Sie die Artikeldetailseite, um Daten zu extrahieren
:param html:
:return:
"""
soup = BeautifulSoup(html, 'html.parser')
return {
"title": soup.select_one("h1").get_text(),
"publish_date": soup.select_one("article header div.entry-meta").find(text=True, recursive=False).replace("|", ""),
"category": soup.select_one("article header div.entry-meta a").get_text(),
"content": soup.select_one("article div.entry-content").get_text(strip=True)
}
def crawl_article_detail_page(url):
"""
Durchsuchen Sie die Artikeldetailseite, um die Artikeldaten abzurufen
:param url:
:return:
"""
#Greifen Sie auf Artikeldetails zu
print(f"Accessing to {url}...")
response = requests.get(url)
response.raise_for_status()
time.sleep(10)
#Artikelinformationen aus Antwort-HTML abrufen
return parse_article_detail(response.text)
def crawl_lapras_note_articles(start_url):
"""
Crawlen Sie LAPRAS HINWEIS, um alle Artikeldaten abzurufen
:return:
"""
article_url_list = crawl_article_list_page(start_url)
article_list = []
for article_url in article_url_list:
article_data = crawl_article_detail_page(article_url)
article_list.append(article_data)
return article_list
def collect_lapras_note_articles():
"""
Holen Sie sich alle Daten des LAPRAS NOTE-Artikels und speichern Sie sie in einer Datei
:return:
"""
print("Start crawl LAPRAS NOTE.")
article_list = crawl_lapras_note_articles("https://note.lapras.com/")
output_json_path = "./articles.json"
with open(output_json_path, mode="w") as f:
print(f"Start output to file. path: {output_json_path}")
json.dump(article_list, f)
print("Done output.")
print("Done crawl LAPRAS NOTE.")
if __name__ == '__main__':
collect_lapras_note_articles()
Der implementierte Code wird in diesem Repository veröffentlicht. https://github.com/Chanmoro/lapras-note-crawler
Es herrscht eine Atmosphäre wie bei einem Einwegkabel, aber für die Basic Edition möchte ich die Erklärung einmal beenden.
Übrigens, diesmal "So erstellen Sie einen Crawler - Basis Edition" mit dem Thema der Crawler-Implementierung von LAPRAS NOTE, einer Reihe von Abläufen bei der Entwicklung eines Crawlers Ich habe die Grundlagen vorgestellt.
Wenn ich einen Crawler entwickle, folge ich dem hier vorgestellten Verfahren. Der im Implementierungsbeispiel angegebene Code fehlt häufig noch, wenn er als Crawler betrachtet wird, der über einen langen Zeitraum beibehalten wird. Es reicht jedoch aus, einen Datensatz gleichzeitig zu erfassen, anstatt die Daten kontinuierlich zu aktualisieren. Ich denke, dass ein solcher Code für die einfache Verwendung ausreicht. Wenn Sie einen Crawler für Recherchen haben, der ausreicht, um einige Male ausgeführt zu werden, können Sie ihn problemlos mit nur einem Shell-Skript implementieren, ohne Python zu verwenden.
In meiner eigentlichen Arbeit verbringe ich viel mehr Zeit mit der Entwicklung der Datenmodellierung, dem Crawling-Flow-Design, der Behandlung von Fehlern usw., um die Daten bei kontinuierlichen Crawls intakt zu halten. Ich habe vor, einige Artikel während der LAPRAS-Ausgabe-Relay-Periode zu schreiben, aber in meinem nächsten Artikel, "Wie erstelle ich einen Crawler-Advanced", basierend auf dem Inhalt dieses Artikels, Langzeitwartung Worauf sollten wir beim Entwerfen eines Crawlers achten, der weiterläuft? Ich möchte das vorstellen, also freuen Sie sich bitte darauf!
Der LAPRAS-Ausgangsrelais-Tag von morgen wird von @nasum geschrieben! Bitte freuen Sie sich auch darauf!
Recommended Posts