[PYTHON] Wie erstelle ich einen Crawler?

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.

Inhalt dieses Artikels

Ü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.

Crawler-Entwicklungsverfahren

Bei der Montage eines Crawlers werden die folgenden Schritte grob ausgeführt, um zu untersuchen, zu entwerfen und zu implementieren.

  1. Untersuchen Sie die Linkstruktur der Site und die Leads auf jeder Seite
  2. Untersuchen Sie die HTML-Struktur der Seite, die Sie crawlen
  3. Montieren Sie den Crawler

Ich werde jedes im Detail erklären.

1. Untersuchen Sie die Linkstruktur der Site und die Leads auf jeder Seite

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.

Überprüfen Sie die Artikellistenseite

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. image.png

Sie können auch sehen, dass der Paging-Link zur nächsten Seite unten auf der Seite angezeigt wird. image.png

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. image.png

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.

Untersuchen Sie die Artikeldetailseite

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.

image.png

Um alle Artikel abzurufen, müssen Sie anscheinend nicht daran denken, von der Artikeldetailseite auf eine andere Seite zu wechseln.

Fassen Sie die Struktur der zu extrahierenden Daten zusammen

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.

  1. Rufen Sie die veröffentlichte Artikellistenseite auf, um die URL zu den Artikeldetails abzurufen
  2. Wenn ein Link zur nächsten Seite vorhanden ist, gehen Sie zur nächsten Seite und rufen Sie die URL zu den Artikeldetails wie in (1) ab.
  3. Rufen Sie die Artikeldetailseite auf, um Artikelinformationen zu erhalten

2. Untersuchen Sie die HTML-Struktur der Seite, die Sie crawlen

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.

Liste der veröffentlichten Artikel

Ich möchte Folgendes aus der Artikellistenseite extrahieren.

Rufen Sie die Link-URL der Artikeldetailseite ab

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.

image.png

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. image.png

Holen Sie sich die Link-URL zur nächsten Seite

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.

image.png

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.

image.png

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.

image.png

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. image.png

Artikeldetailseite

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.

image.png

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

3. Montieren Sie den Crawler

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.

Organisieren Sie, was zu tun ist

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

Vorsichtsmaßnahmen bei der Montage des Crawlers

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.

Solide Implementierung in Python

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.

Zusammenfassung

Ü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

Wie erstelle ich einen Crawler?
Wie erstelle ich einen Crawler?
Wie erstelle ich eine japanisch-englische Übersetzung?
Wie man einen lockeren Bot macht
Wie erstelle ich eine Docker-Datei?
[Blender] So erstellen Sie ein Blender-Plug-In
[Python] Wie man eine Klasse iterierbar macht
So erstellen Sie einen benutzerdefinierten Backtrader-Indikator
Wie erstelle ich eine Pelican Site Map?
Wie man ein Dialogsystem für Anfänger erstellt
So erstellen Sie ein Wörterbuch mit einer hierarchischen Struktur.
So erstellen Sie ein QGIS-Plug-In (Paketerzeugung)
Ich las "Wie man ein Hacking Lab macht"
So rufen Sie eine Funktion auf
Wie man ein Terminal hackt
Wie man ein Schießspiel mit toio macht (Teil 1)
So erstellen Sie ein Python-Paket mit VS Code
Grundlagen von PyTorch (2) - Wie erstelle ich ein neuronales Netzwerk?
So erstellen Sie mit Flask einen BOT für Cisco Webex-Teams
[Python] So erstellen Sie eine Liste von Zeichenfolgen Zeichen für Zeichen
So setzen Sie einen symbolischen Link
Wie erstelle ich ein Multiplayer-Online-Actionspiel mit Slack?
So erstellen Sie ein Conda-Paket
So erstellen Sie eine virtuelle Brücke
So erstellen Sie ein Hacking-Labor - Kali Linux (2020.1) VirtualBox 64-Bit-Edition -
Wie erstelle ich ein Python-Paket (geschrieben für Praktikanten)
[Blender] So erstellen Sie Blender-Skripte mehrsprachig
So erstellen Sie eine Konfigurationsdatei
So machen Sie einen String in Python zu einem Array oder ein Array zu einem String
So erstellen Sie einen Befehl zum Lesen der Einstellungsdatei mit Pyramide
So erstellen Sie eine Überwachungskamera (Überwachungskamera) mit Opencv und Python
[C-Sprache] So erstellen, vermeiden und erstellen Sie einen Zombie-Prozess
Spigot (Papier) Einführung in die Erstellung eines Plug-Ins für 2020 # 01 (Umgebungskonstruktion)
So erstellen Sie eine .dylib-Bibliothek aus einer .a-Bibliothek mit OSX (El Capitan)
So führen Sie einen Komponententest durch Teil 1 Entwurfsmuster zur Einführung
[Python] Wie erstelle ich eine Matrix aus sich wiederholenden Mustern (repmat / tile)
Wie man Selen so leicht wie möglich macht
So erstellen Sie einen Klon aus Github
So teilen und speichern Sie einen DataFrame
So erstellen Sie einen Git-Klonordner
Qiita (1) Wie schreibe ich einen Codenamen?
So fügen Sie ein Paket mit PyCharm hinzu
[Python] So konvertieren Sie eine zweidimensionale Liste in eine eindimensionale Liste
Machen wir einen Jupyter-Kernel
[Colab] So kopieren Sie einen riesigen Datensatz
[Python] So invertieren Sie eine Zeichenfolge
So installieren Sie ein Paket mithilfe eines Repositorys
[Ubuntu] So führen Sie ein Shell-Skript aus
Wie bekomme ich Stacktrace in Python?
[Cocos2d-x] So erstellen Sie eine Skriptbindung (Teil 2)
So machen Sie Multi-Boot-USB (Windows 10-kompatibel)
So erstellen Sie ein Repository aus Medien
Um eine Diktat-Eigenschaft schreibgeschützt zu machen
So wählen Sie eine Seaborn-Farbpalette aus
So testen Sie auf einer von Django authentifizierten Seite
[Cocos2d-x] So erstellen Sie eine Skriptbindung (Teil 1)
Verwendung des Jupyter-Notebooks [super basic]
Wie man Fabric installiert und wie man es benutzt
So führen Sie Maya Python-Skripte aus