[PYTHON] Ich habe ein Tool erstellt, um neue Artikel zu erhalten

Ich habe ein Tool erstellt, um den Titel und die URL eines neuen Blogposts durch Scraping mit Python abzurufen. Es ist github-> https://github.com/cerven12/blog_post_getter

Warum hast du es geschafft?

Als mein Freund mit dem Bloggen begann (neu gestartet?), Wollte ich versuchen, mein Gedächtnis zu verbessern und meine Schreibfähigkeiten durch das Posten von Blogs zu verbessern. Ich dachte, dass es aktiver wäre, von zwei Menschen angeregt zu werden, die miteinander konkurrieren und zusammenarbeiten, anstatt es alleine zu tun, also habe ich es als Teil davon gemacht.

Was für ein Werkzeug ist das?

Holen Sie sich den Titel und die URL des neu veröffentlichten Artikels. (Ich möchte es regelmäßig ausführen und über die LINE-API usw. benachrichtigen.)

Verwenden Sie die txt-Datei, die die URL der vorhandenen Beitragsliste enthält, und vergleichen Sie sie mit der URL der neuesten Beitragsliste. Ich versuche, Änderungen im Titel oder Inhalt nicht zu erkennen. (Weil es schwierig ist, eine Benachrichtigung mit der Aufschrift "Neu!" Zu erhalten, indem Sie einfach den Titel bearbeiten!) Die Ausnahme ist jedoch, wenn sich die URL beim Bearbeiten eines Artikels ändert (Gibt es ...?).

Ich weiß nichts über andere Websites, weil ich es so gemacht habe, dass es mit Qiita verwendet werden kann. Ich denke, dass es auf Seiten verwendet werden kann, auf denen HTML das folgende Format hat

<!--Das a-Tag enthält eine Klasse. Der Titel wird als Element des a-Tags geschrieben-->
<a class='articles'  href='#'>Title</a>

Verwendbare Seite

Qiita-Benutzerseite: https://qiita.com/takuto_neko_like Hatena Blog-Benutzerseite: http://atc.hateblo.jp/about

Nutzungsbedingungen

  1. Auf einer Seite wird eine Liste mit Artikeln angezeigt
  2. Im Tag "" jedes Artikels wird ein gemeinsamer Selektor festgelegt.
  3. Der Titel muss als Element des a-Tags geschrieben werden
  4. Erstellen Sie im Voraus eine leere TXT-Datei

Ganzer Code


import requests, bs4


def new_post_getter(url, selecter, txt):
    '''
Artikeltitel und URL bs4_Element abrufen
1. Argument:URL der Seite mit der Beitragsliste
Zweites Argument:Von jedem Beitrag<a>Am am Kopf angebrachten Auswahlkopf.Mit
3. Argument:TXT-Pfad für die Aufnahme
    '''
    res = requests.get(url)
    posts = bs4.BeautifulSoup(res.text, 'html.parser').select(selecter)

    now_posts_url = [] #1 Liste der URLs der erfassten Artikelliste,Wird verwendet, um neue Beiträge durch Vergleich mit vorherigen Beitragsdaten zu identifizieren
    now_posts_url_title_set = [] #Liste der URLs und Titel der erworbenen Artikelliste,
    for post in posts:
        #URL extrahieren
        index_first = int(str(post).find('href=')) + 6
        index_end = int(str(post).find('">'))
        url = (str(post)[index_first : index_end])
        #Titel extrahieren
        index_first = int(str(post).find('">')) + 2
        index_end = int(str(post).find('</a'))
        title = (str(post)[index_first : index_end].replace('\u3000', ' ')) #Leerer Ersatz

        now_posts_url.append(url)
        now_posts_url_title_set.append(f"{url}>>>{title}")

    old_post_text = open(txt)
    old_post = old_post_text.read().split(',') #Von der Textdatei zum Listentyp
    # differences :Beiträge, die gepostet wurden, aber nicht auf dem Listenbildschirm angezeigt werden+Neuer Beitrag
    differences = list(set(now_posts_url) - set(old_post))
    old_post_text.close()

    #Überschreibe txt für die Aufnahme aller_Beiträge sind vergangene Beiträge+Neuer Beitrag
    all_posts = ",".join(old_post + differences)
    f = open(txt, mode='w')
    f.writelines(all_posts)
    f.close()

    new_post_info = []
    for new in now_posts_url_title_set:
        for incremental in differences:
            if incremental in new:
                new_post_info.append(new.split(">>>"))
    return new_post_info

Wie benutzt man

Seite der Artikelliste, Auswahl, die an ein Tag jedes Artikels angehängt ist, Geben Sie den Pfad der txt-Datei an, in der der Buchungsstatus gespeichert wird als Argument

★ Versuchen Sie es mit

Versuchen Sie es mit


url = 'https://qiita.com/takuto_neko_like'
selecter = '.u-link-no-underline'
file = 'neko.txt'

my_posts = new_post_getter(url, selecter, file)
print(my_posts)

Mit den oben genannten ...

Ergebnis



[['/takuto_neko_like/items/93b3751984e5e3fd3670', '[Fisch] Über die Sache, dass die Bewegung von Fischen zu langsam war ~ git Ärger ~'], ['/takuto_neko_like/items/14e92797fa2b23a64adb', '[Python] Was wird durch Mehrfachvererbung geerbt?']]

Sie können eine doppelte Liste von URLs und Titeln erhalten. [[URL, Titel], [URL, Titel], [URL, Titel], .......]

Durch Drehen der Doppelliste mit einer for-Anweisung und Formatieren der Zeichenfolge ...


for url, title in my_posts:
    print(f'{title} : {url}')

Gut lesbare Ausgabe ↓

Ausgabe



[Fisch] Über die Sache, dass die Bewegung von Fischen zu langsam war ~ git Ärger ~: /takuto_neko_like/items/93b3751984e5e3fd3670
[Python] Was wird durch Mehrfachvererbung geerbt?: /takuto_neko_like/items/14e92797fa2b23a64adb

Apropos

Der Inhalt von neko.txt ist wie folgt.

/takuto_neko_like/items/93b3751984e5e3fd3670,/takuto_neko_like/items/14e92797fa2b23a64adb,/takuto_neko_like/items/bb8d0957347636b5bf4f,/takuto_neko_like/items/62aeb4271614f6f0347f,/takuto_neko_like/items/c9c80ff453d0c4fad239,/takuto_neko_like/items/aed9dd5619d8457d4894,/takuto_neko_like/items/6cf9bade3d9515a724c0

Enthält eine Liste von URLs. Versuchen Sie, den ersten und den letzten zu löschen ...

/takuto_neko_like/items/14e92797fa2b23a64adb,/takuto_neko_like/items/bb8d0957347636b5bf4f,/takuto_neko_like/items/62aeb4271614f6f0347f,/takuto_neko_like/items/c9c80ff453d0c4fad239,/takuto_neko_like/items/aed9dd5619d8457d4894

Wenn du rennst ...


my_posts = new_post_getter(url, selecter, file)
print(my_posts)

Ergebnis ↓

[['/takuto_neko_like/items/c5791f267e0964e09d03', 'Es wurde ein Tool erstellt, mit dem neue Artikel dazu gebracht werden können, hart mit Freunden an Blog-Posts zu arbeiten'], ['/takuto_neko_like/items/93b3751984e5e3fd3670', '[Fisch] Über die Sache, dass die Bewegung von Fischen zu langsam war ~ git Ärger ~'], ['/takuto_neko_like/items/6cf9bade3d9515a724c0', '【Python】@Was sind Klassenmethoden und Dekorateure?']]

Holen Sie sich nur den gelöschten Betrag! ☺

Wie hast du es gemacht?

Unten finden Sie eine Beschreibung des Codes.

Code-Fluss

  1. Rufen Sie die <a> Tags aller angezeigten Artikel von der Artikellistenseite ab
  2. Extrahieren Sie die URL aus den erhaltenen "" -Tags. Außerdem werden eine Reihe von URLs und Titeln separat extrahiert.
  3. Verwenden Sie die vorhandene Beitragsliste (txt), 2. Vergleichen Sie mit der URL in. Extrahieren Sie den Unterschied.
  4. Überschreiben Sie txt mit der URL des neuen Beitrags und dem vorhandenen Beitragsdatensatz in einem
  5. Extrahieren Sie nur die Elemente, die der Differenz zu URL und Titelsatz in 2 entsprechen. Machen Sie es zu einem doppelten Listentyp für eine einfache Formgebung

Jeder Code

1. Rufen Sie das << `Tag aller angezeigten Artikel von der Artikellistenseite ab

1.Holen Sie sich das a-Tag aller angezeigten Artikel von der Artikellistenseite



import requests, bs4


def new_post_getter(url, selecter, txt):
    '''
Artikeltitel und URL bs4_Element abrufen
1. Argument:URL der Seite mit der Beitragsliste
Zweites Argument:Von jedem Beitrag<a>Am am Kopf angebrachten Auswahlkopf.Mit
3. Argument:TXT-Pfad für die Aufnahme
    '''
    res = requests.get(url)
    posts = bs4.BeautifulSoup(res.text, 'html.parser').select(selecter)

Wir werden hier zwei Bibliotheken von Drittanbietern verwenden.

  1. request Eine Bibliothek, die WebAPI verwenden kann. Dieses Mal verwenden wir die GET-Methode, um das Antwortobjekt abzurufen. Das Anforderungsobjekt enthält verschiedene Informationen, kann jedoch mithilfe von ".text" in eine Zeichenfolge umgewandelt werden. Beautiful Soup in 2. verwendet den als Antwort zurückgegebenen HTML-Text.
  2. BeautifulSoup Sie können den abgerufenen HTML-Text syntaktisch interpretieren, dann Attribute mit verschiedenen Methoden abrufen, mehrere Elemente mithilfe von Selektoren abrufen und vieles mehr. Dieses Mal interpretiere ich die Textantwort als HTML und verwende dann die Methode ".select", um einen bestimmten Selektor anzugeben. Dadurch erhalten Sie mehrere Elemente für diesen Selektor.

Die Daten, die tatsächlich von dem oben genannten "★ Try using" erfasst wurden, sind der nächste weiße Rahmenteil

スクリーンショット 2020-03-08 0.07.31.png

2. Extrahieren Sie die URL aus den erhaltenen "" -Tags. Außerdem werden eine Reihe von URLs und Titeln separat extrahiert.

2.Holen Sie sich den Titel und die URL aus den erhaltenen Tags. Außerdem werden eine Reihe von URLs und Titeln separat extrahiert.



    now_posts_url = [] #1 Liste der URLs der erfassten Artikelliste,Wird verwendet, um neue Beiträge durch Vergleich mit vorherigen Beitragsdaten zu identifizieren
    now_posts_url_title_set = [] #Liste der URLs und Titel der erworbenen Artikelliste,
    for post in posts:
        #URL extrahieren
        index_first = int(str(post).find('href=')) + 6
        index_end = int(str(post).find('">'))
        url = (str(post)[index_first : index_end])
        #Titel extrahieren
        index_first = int(str(post).find('">')) + 2
        index_end = int(str(post).find('</a'))
        title = (str(post)[index_first : index_end].replace('\u3000', ' ')) #Leerer Ersatz

        now_posts_url.append(url)
        now_posts_url_title_set.append(f"{url}>>>{title}")

Drehen Sie die erfassten <a> Tag-Elemente mit einer for-Anweisung. Durch Angabe einer Zeichenfolge mit ".find ()" können Sie den Index der Startposition dieser Zeichenfolge ermitteln, sodass Sie den URL-Teil und den Titelteil erhalten, indem Sie die Zeichenfolge mit diesem Wert aufteilen.

スクリーンショット 2020-03-08 0.17.53.png

now_posts_url sind die Daten, die verwendet werden, um mit den bisher veröffentlichten Daten zu vergleichen und die Differenz zu extrahieren (ausgenommen Artikel, die aufgrund der Seitennation usw. vom Listenbildschirm verschwunden sind). Dieses Mal erkennen wir Neuankömmlinge anhand einer URL, die sich auch bei Aktualisierung des Artikels nicht ändert. Um den Titel und die URL später auszugeben, speichern Sie jetzt den Satz "URL + Titel". Ich will. Verwenden Sie daher "now_posts_url", um die Differenz zu ermitteln, und extrahieren Sie später nur die Daten, die die Differenz-URL enthalten, aus "now_posts_url_title_set".

3. Verwenden Sie die vorhandene Beitragsliste (txt), 2. Vergleichen Sie mit der URL in. Extrahieren Sie den Unterschied.

3.Liste der vorhandenen Beiträge(txt)Verwenden von, 2. Vergleichen Sie mit der URL in. Extrahieren Sie den Unterschied.


    old_post_text = open(txt)
    old_post = old_post_text.read().split(',') #Von der Textdatei zum Listentyp
    # differences :Beiträge, die gepostet wurden, aber nicht auf dem Listenbildschirm angezeigt werden+Neuer Beitrag
    differences = list(set(now_posts_url) - set(old_post))
    old_post_text.close()

Ich möchte mit der txt-Datei vergleichen, in der die bisherigen Post-Datensätze gespeichert sind, und den Unterschied aus der zuletzt neu erworbenen Post-Liste extrahieren. Es ist ein Unterschied. Im Ben-Diagramm ist es wie folgt A ist eine Liste vergangener Beiträge B ist die neueste Beitragsliste Und der schattierte Bereich ist der Unterschied, der ein völlig neuer Beitrag ist.

IMG_7686.jpg

Set-Operationen können einfach ausgeführt werden, indem das Berechnungsziel auf ein Set-Typ-Objekt gesetzt wird. Dieses Mal wird die in der txt-Datei aufgezeichnete Zeichenkette vom Listentyp ([URL1, URL2, URL3]) mit split () in den Listentyp konvertiert. Die Differenz wird beim Konvertieren in den festgelegten Typ zusammen mit der neuesten Beitragsliste in 2 berechnet.

4. Überschreiben Sie txt, indem Sie die URL des neuen Beitrags und den vorhandenen Beitragsdatensatz kombinieren.

Überschreiben Sie txt mit der URL des neuen Beitrags und dem vorhandenen Beitragsdatensatz in einem


    #Überschreibe txt für die Aufnahme aller_Beiträge sind vergangene Beiträge+Neuer Beitrag
    all_posts = ",".join(old_post + differences)
    f = open(txt, mode='w')
    f.writelines(all_posts)
    f.close()

Die txt-Datei sollte auch mit den neuesten Informationen aktualisiert werden, damit sie beim nächsten Mal verwendet werden kann. Überschreiben Sie die txt-Datei, indem Sie den Unterschied (neuer Beitrag) zu den vorherigen Beiträgen hinzufügen.

Aus dem in 5.2. Erhaltenen Satz von URL und Titel werden nur die Elemente extrahiert, die der Differenz entsprechen. Machen Sie es zu einem doppelten Listentyp für eine einfache Formgebung

Formatieren Sie den neuen Titel und die neue URL des Beitrags


    new_post_info = []
    for new in now_posts_url_title_set:
        for incremental in differences:
            if incremental in new:
                new_post_info.append(new.split(">>>"))
    return new_post_info

Aus den Daten der Zeichenfolge "URL >>> Titel", die im Voraus in 2. erhalten wurden, werden nur die Daten erhalten, die die URL (Zeichenfolge) enthalten, die der Differenz entspricht.

IMG_7687 2.jpg

Da es sich um eine Zeichenfolge handelt, ist es in Ordnung, wenn dasselbe Zeichen mit dem Operator "in" in der Zeichenfolge enthalten ist. Dadurch konnte ich die URL und den Titel des neuen Artikels abrufen.

von jetzt an

Ich möchte von LINE benachrichtigt werden

~~ Ich möchte regelmäßig Chats mit Freunden benachrichtigen können. später. ~~

Nachtrag 2020/03/09

Ich habe Line Notify verwendet.


def send_line_notify(posts, token):
    '''
    # new_post_Nehmen Sie den Rückgabewert von Getter als Argument
    '''
    notice_url = "https://notify-api.line.me/api/notify"
    headers = {"Authorization" : "Bearer "+ token}
    for url, title in posts:
        if 'http' not in url:
            url = 'https://qiita.com/' + url
        message = f'{title}:{url}'
        payload = {'message': message}
        r = requests.post(notice_url, headers=headers, params=payload,)

Auf diese Weise verwenden



token = '########'
neko_post = new_post_getter(neko_url, neko_selecter, neko_txt)
send_line_notify(neko_post, token)

Wenn Sie den Rückgabewert und das Token der Funktion "new_post_getter" als Argumente angeben, wird es an "LINE Notify" gesendet. Ich habe auf [hier] verwiesen (https://qiita.com/moriita/items/5b199ac6b14ceaa4f7c9).

Ich möchte es regelmäßig ausführen

Ich möchte jede Minute mit ~~ Python überall laufen. später. ~~

2020/03/09 Kopieren Sie jede Datei an eine beliebige Stelle nach Python und erstellen Sie .sh wie folgt

In der Lage sein, die virtuelle Umgebung zu cronen



source /home/<Konto>/blog_post_notice/venv/bin/activate
python3 /home/<Konto>/blog_post_notice/send.py ## 

Wenn ich dann versuche, .sh auszuführen, bevor ich cron einrichte ...

Error



requests.exceptions.ProxyError: HTTPSConnectionPool(host='qiita.com', port=443): Max retries exceeded with url: /takuto_neko_like (Caused by ProxyError('Canno
t connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden')))

Nach einer Untersuchung scheint Python überall nur auf externe Websites zugreifen zu können, die Whitelist entsprechen, um den unbefugten Zugriff auf kostenlose Konten zu verhindern. Also habe ich Python überall aufgegeben ...

Ich habe versucht, in Heroku zu implementieren. Da Sie jedoch keine Dateien in Heroku speichern können, können Sie die txt-Datei nicht in demselben Verzeichnis überschreiben wie bei der Verarbeitung in Python wie diesmal. Ich habe versucht, die Datei zu aktualisieren, indem ich die Google Drive- und Dropbox-APIs von Python aus manipuliert habe. Es scheint, dass ich den Dateinamen und die Metadaten abrufen und eine neue Datei hinzufügen kann, aber ich wusste nicht, wie ich den Inhalt der Datei abrufen kann.

Daher werde ich dieses Mal cron auf meinem PC einrichten und es regelmäßig ausführen.

Als crontab -e ...

Versuchen Sie es vorerst jede Minute


0 * * * * sh /Users/Nutzername/dir1/post_notice/notice.sh

Recommended Posts

Ich habe ein Tool erstellt, um neue Artikel zu erhalten
Ich habe ein Tool erstellt, um eine Wortwolke aus Wikipedia zu erstellen
[Titan Craft] Ich habe ein Werkzeug gemacht, um einen Riesen nach Minecraft zu rufen
Ich habe einen neuen AWS S3-Eimer hergestellt
Ich habe ein automatisches Stempelwerkzeug für den Browser erstellt.
Ich habe ein Tool erstellt, um die Antwortlinks von OpenAI Gym auf einmal zu erhalten
〇✕ Ich habe ein Spiel gemacht
Ich habe ein nützliches Tool für Digital Ocean erstellt
Ich habe ein Tool zum automatischen Durchsuchen mehrerer Websites mit Selenium (Python) erstellt.
Ich habe ein CLI-Tool erstellt, um Bilder in jedem Verzeichnis in PDF zu konvertieren
Ich habe ein Router-Konfigurationssammlungstool Config Collecor erstellt
Ich habe ein Tool erstellt, um Jupyter py mit VS Code in ipynb zu konvertieren
Ich habe ein Tool erstellt, um die Ausführungszeit von cron zu schätzen (+ PyPI-Debüt)
Ich habe gerade ein Tool erstellt, mit dem Daten mithilfe der GUI-Operation einfach als Diagramm angezeigt werden können
Ich habe ein Tool zum Generieren von Markdown aus der exportierten Scrapbox-JSON-Datei erstellt
Ich habe ein Tool zum automatischen Sichern der Metadaten der Salesforce-Organisation erstellt
Ich habe eine Bibliothek erstellt, um japanische Sätze schön zu brechen
Ich habe ein Reinigungstool für Google Container Registry erstellt
Ich habe ein Skript erstellt, um ein Snippet in README.md einzufügen
Ich habe ein Python-Modul erstellt, um Kommentare zu übersetzen
Ich habe einen Code erstellt, um illustration2vec in ein Keras-Modell zu konvertieren
Ich habe einen Befehl zum Markieren des Tabellenclips gegeben
Ich habe eine Python-Bibliothek erstellt, die einen rollierenden Rang hat
Ich habe ein Tool zur Erzeugung sich wiederholender Textdaten "rpttxt" erstellt.
Ich habe einen Python-Text gemacht
Ich habe einen Zwietrachtbot gemacht
Ich habe ein Paket erstellt, um Zeitreihen mit Python zu filtern
Ich habe eine Schachtel gemacht, um mich auszuruhen, bevor Pepper müde wird
[Python] Ich möchte einen gemeinsamen Satz zwischen numpy erhalten
Ich habe einen Befehl zum Generieren eines Kommentars für eine Tabelle in Django eingegeben
Ich habe eine Funktion erstellt, um das Modell von DCGAN zu überprüfen
Ich habe versucht, mit Hy ・ Define a class zu beginnen
Ich habe ein Skript geschrieben, um eine beliebte Seite in Japan zu bekommen
Ich habe Sie dazu gebracht, Befehle über einen WEB-Browser auszuführen
Ich habe ein Drehbuch gemacht, um bei meinem Koshien Hallo zu sagen
Erstellt einen Toolsver, der Betriebssystem, Python, Module und Toolversionen an Markdown ausspuckt
Ich habe ein Tool erstellt, mit dem das Erstellen und Installieren eines öffentlichen Schlüssels etwas einfacher ist.
Ich habe eine Klasse erstellt, um das Analyseergebnis von MeCab in ndarray mit Python zu erhalten
Ich habe ein Tool erstellt, um automatisch ein einfaches ER-Diagramm aus der Anweisung CREATE TABLE zu generieren
Erstellt ein Tool, mit dem Sie bequem Parameter für Modelle des maschinellen Lernens festlegen können
Ich habe eine C ++ - Lernseite erstellt
Ich bekomme einen UnicodeDecodeError mit mecab-python3
Ich habe einen Line-Bot mit Python gemacht!
Ich habe einen Wikipedia Gacha Bot gemacht
Ich erhalte einen KeyError in pyclustering.xmeans
Ich habe mit Python eine Lotterie gemacht.
Ich habe ein CUI-basiertes Übersetzungsskript erstellt
Tool zum Konvertieren der Juniper-Konfiguration
Ich habe mit Python einen Daemon erstellt
[5.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ich habe versucht, ein Programm zu erstellen, um die Fehlersuche von Saiseriya zu lösen (Hinweis)
Ich habe eine Bibliothek erstellt, die Konfigurationsdateien mit Python einfach lesen kann
Ich habe versucht, mit Pandas eine Pferderenn-Datenbank zu erstellen
[2nd] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
Ein Memorandum beim automatischen Erwerb mit Selen
Ich habe mit Razpai einen Webserver erstellt, um Anime zu schauen
[3.] Ich habe versucht, mit Python ein bestimmtes Authenticator-ähnliches Tool zu erstellen
[Python] Ein Memo, das ich versucht habe, mit Asyncio zu beginnen
Ich habe ein Skript geschrieben, mit dem Sie mit hoher Geschwindigkeit mit AtCoder beginnen können!
Erstelltes WebSocket Client / Server-CLI-Tool (wie WebSocket Version Netcat)
Ich habe versucht, mit Boto3 eine Liste der AMI-Namen zu erhalten