[PYTHON] Benachrichtigen Sie den Chat über neue Artikel der Qiita-Organisation und verbessern Sie die Lerneffizienz der Organisation!

Wir fördern die Qiita-Artikelausgabeaktivitäten innerhalb des Unternehmens. Das ist G-awa. Die Output-Lernmethode weist eine gute Lerneffizienz auf und wird dringend empfohlen. Auf der anderen Seite ist es jedoch schwierig, alleine weiterzumachen. Daher ist es wichtig, dass Teams und Organisationen sich gegenseitig unterstützen. Es ist leicht, dein Herz zu brechen, wenn du allein bist.

→→→→

Ich habe den gestrigen Artikel gelesen, er war sehr hilfreich: thumbsup: Eine Umgebung, in der Sie sich gegenseitig ermutigen können, ist beispielsweise eine großartige Umgebung für Ingenieure, um zu wachsen. Wir möchten eine so wunderbare Umgebung schaffen, indem wir einen Kanal erstellen und betreiben, an dem Personen, die auf Qiita posten, teilnehmen (tatsächlich handelt es sich um einen öffentlichen Kanal, den alle Mitarbeiter anzeigen und veröffentlichen können).

Beim Aufbau und Betrieb der Qiita-Organisation stehen wir vor den folgenden Herausforderungen.

――Ich möchte nicht die tägliche Leistung aller verpassen

Also habe ich ein Tool erstellt, um den Chat über die Update-Informationen des Artikels zu informieren.

Über Werkzeuge

Es ist ein Tool, das neue Artikel abruft, die an die Qiita-Organisation gesendet wurden, und Rocket Chat benachrichtigt. Da die Qiita-API die Organisationsinformationen nicht abrufen konnte, wird sie durch Crawlen implementiert. Es läuft cron auf Lambda auf AWS.

Technologie-Stack Erläuterung
AWS Lambda Ausführungsumgebung
Serverless Framework Bereitstellen
Python beautiful soup Krabbeln
rocket chat api Poste eine Nachricht an Rocket Chat
CircleCI Prüfung

Klicken Sie hier für den Quellcode https://github.com/qiita-scraper/qiita-scraper-rocket-chat

Krabbeln

Verwenden Sie schöne Suppe zum Crawlen. Ich möchte auch das Buchungsdatum extrahieren, also mache ich eine kleine lästige Sache. Nein, Krabbeln ist hart.

image.png

def fetch_recent_user_articles(self, user):
    """
Erhalten Sie mehrere aktuelle Qiita-Artikel, die vom angegebenen Benutzer veröffentlicht wurden
    :param user:
    :return:
    """

    qiita_url = 'https://qiita.com/' + user
    response = request.urlopen(qiita_url)
    soup = BeautifulSoup(response, 'html.parser')
    response.close()

    created_ats = []
    created_dates = soup.find_all('div', class_='ItemLink__info')
    for created_date in created_dates:
        div = re.sub('<a.*?>|</a>', '', str(created_date))
        text = re.sub('<div.*?>|</div>', '', div).split()
        month = str(time.strptime(text[3], '%b').tm_mon)
        day = text[4][:-1]
        year = text[5]
        created_at = year + '/' + month + '/' + day
        created_ats.append(created_at)

    articles = []
    a_tags = soup.find_all('a', class_='u-link-no-underline')
    for index, a in enumerate(a_tags):
        href = a.get('href')
        url = 'https://qiita.com' + href
        title = a.string
        articles.append({'title': title, 'url': url, 'created_at': created_ats[index]})

    return articles

Poste im Rocket Chat

RocketChat veröffentlicht API-Spezifikationen. https://rocket.chat/docs/developer-guides/rest-api/

Verwenden Sie einfach urllib, die Standard-Python-Bibliothek. Der Artikel urllib.request ist ausreichend für Python-HTTP-Client war hilfreich. Wirklich Urllib ist genug.

Melden Sie sich an, um das authToken und die Benutzer-ID abzurufen. Es wird durch Schreiben in den http-Header authentifiziert und greift auf andere APIs zu.

def __login_rocket_chat(self, user, password):
    """
Melden Sie sich bei Rocket Chat an und authentifizieren Sie sich_Token und Benutzer_Holen Sie sich die ID.
    :param url:
    :return:
    """
    obj = {
        "user": user,
        "password": password
    }
    json_data = json.dumps(obj).encode("utf-8")
    headers = {"Content-Type": "application/json"}
    req_object = request.Request(self.url + '/api/v1/login', data=json_data, headers=headers, method='POST')
    with request.urlopen(req_object) as response:
        response_body = response.read().decode("utf-8")
        result_objs = json.loads(response_body.split('\n')[0])
        user_id = result_objs["data"]["userId"]
        auth_token = result_objs["data"]["authToken"]
        print(user_id, auth_token)
    return auth_token, user_id

Suchen Sie nach der ID des Chatrooms nach Namen.

def fetch_room_id(self, room_name):
    """
Rocket Chatraum_Holen Sie sich die ID.
    :param room_name:
    :return:
    """

    headers = {
        "Content-Type": "application/json",
        "X-Auth-Token": self.auth_token,
        "X-User-Id": self.user_id
    }
    params = {'roomName': room_name}
    url = '{}?{}'.format(self.url + '/api/v1/channels.info', parse.urlencode(params))
    req_object = request.Request(url, headers=headers, method="GET")
    with request.urlopen(req_object) as response:
        response_body = response.read().decode("utf-8")
        print(response_body)
        result_objs = json.loads(response_body.split('\n')[0])
        channel = result_objs.get('channel')
        return channel.get('_id')

Sende eine Nachricht. Sie können nicht senden, indem Sie den Benutzernamen und das Symbolbild vom RocketChat-Webbildschirm ersetzen, aber Sie können senden, indem Sie es von der API ersetzen. Es ist ein bisschen knifflig, nicht wahr?

def send_message_to_rocket_chat(self, msg, room_name):
    """
Senden Sie eine Nachricht an Rocket Chat
    :param msg:
    :param room_name
    :return:
    """
    headers = {
        "Content-Type": "application/json",
        "X-Auth-Token": self.auth_token,
        "X-User-Id": self.user_id
    }
    print(headers)
    body = {
        "message": {
            "rid": self.fetch_room_id(room_name),
            "msg": msg,
            "alias": 'Qiita Bot',
            "avatar": 'https://haskell.jp/antenna/image/logo/qiita.png'
        }
    }
    print(body)
    req_object = request.Request(self.url + '/api/v1/chat.sendMessage', data=json.dumps(body).encode("utf-8"), headers=headers, method="POST")
    with request.urlopen(req_object) as response:

So was.

image.png

Prüfung

Führen Sie den Test aus, indem Sie RocketChat und mongoDB im Docker starten und eine Anfrage an die eigentliche RocketChat-Anwendung senden. Es tut mir leid, Qiita, ich greife auf die reale Sache zu und teste sie.

Starten Sie RocketChat mit Docker-Compose. https://rocket.chat/docs/installation/docker-containers/docker-compose/

Es scheint, dass Sie den nervigen Assistentenbildschirm beim Starten von RocketChat überspringen können, indem Sie OVERWRITE_SETTING_Show_Setup_Wizard = complete als Umgebungsvariable angeben. Referenz: https://github.com/RocketChat/Rocket.Chat/issues/2233

docker-compose.yml


version: "2"

services:
  rocketchat:
    image: rocketchat/rocket.chat:latest
    command: >
      bash -c
        "for i in `seq 1 30`; do
          node main.js &&
          s=$$? && break || s=$$?;
          echo \"Tried $$i times. Waiting 5 secs...\";
          sleep 5;
        done; (exit $$s)"
    restart: unless-stopped
    volumes:
      - ./uploads:/app/uploads
    environment:
      - PORT=3000
      - ROOT_URL=http://localhost:3000
      - MONGO_URL=mongodb://mongo:27017/rocketchat
      - MONGO_OPLOG_URL=mongodb://mongo:27017/local
      - MAIL_URL=smtp://smtp.email
      - ADMIN_USERNAME=admin
      - ADMIN_PASS=supersecret
      - [email protected]
      # https://github.com/RocketChat/Rocket.Chat/issues/2233
      - OVERWRITE_SETTING_Show_Setup_Wizard=completed
    depends_on:
      - mongo
    ports:
      - 3000:3000
    labels:
      - "traefik.backend=rocketchat"
      - "traefik.frontend.rule=Host: your.domain.tld"

  mongo:
    image: mongo:4.0
    restart: unless-stopped
    volumes:
      - ./data/db:/data/db
    command: mongod --smallfiles --oplogSize 128 --replSet rs0 --storageEngine=mmapv1
    labels:
      - "traefik.enable=false"

  # this container's job is just run the command to initialize the replica set.
  # it will run the command and remove himself (it will not stay running)
  mongo-init-replica:
    image: mongo:4.0
    command: >
      bash -c
        "for i in `seq 1 30`; do
          mongo mongo/rocketchat --eval \"
            rs.initiate({
              _id: 'rs0',
              members: [ { _id: 0, host: 'localhost:27017' } ]})\" &&
          s=$$? && break || s=$$?;
          echo \"Tried $$i times. Waiting 5 secs...\";
          sleep 5;
        done; (exit $$s)"
    depends_on:
      - mongo

Führen Sie dann den Test mit RocketChat aus, das bei localhost: 3000 mit Pythons Unittest gestartet wurde. Es ist einfach.

import unittest
from rocket_chat.rocket_chat import RocketChat
import urllib
from qiita.qiita import Qiita
import freezegun
import json

class TestQiitaScraper(unittest.TestCase):
    def setUp(self):
        # rocket chat admin user set in docker-compoose.yml rocketchat service environment value.
        self.aurhorized_user = 'admin'
        self.aurhorized_password = 'supersecret'
        self.rocket_chat_url = 'http://localhost:3000'

    def test_login_success(self):
        rocket_chat = RocketChat(self.rocket_chat_url, self.aurhorized_user, self.aurhorized_password)
        self.assertNotEqual(len(rocket_chat.auth_token), 0)
        self.assertNotEqual(len(rocket_chat.user_id), 0)

    def test_login_failed(self):
        with self.assertRaises(urllib.error.HTTPError):
            unauthorized_user = 'mbvdr678ijhvbjiutrdvbhjutrdfyuijhgf'
            unauthorized_pass = 'gfr67865tghjgfr567uijhfrt67ujhgthhh'
            RocketChat(self.rocket_chat_url, unauthorized_user, unauthorized_pass)

Führen Sie Tests mit CircleCI durch

Geben Sie "machine" für "executer" anstelle von "imagae" an, um Docker-Compose in der Circleci-Ausführungsumgebung zu verwenden. * Die Cache-Einstellungen sind der Einfachheit halber ausgeschlossen.

.circleci/config.yml


version: 2
jobs:
  build:
    machine:
      image: circleci/classic:201808-01
    steps:
      - checkout
      - run:
          name: "Switch to Python v3.7"
          command: |
            pyenv versions
            pyenv global 3.7.0
      - run:
          name: docker-compose up
          command: sh dcup.sh
      - run:
          name: install dependencies and test
          command: |
            python3 -m venv venv
            . venv/bin/activate
            pip install -r requirements.txt
            pip install -r requirements-dev.txt
            python -m unittest test.py

Zusammenfassung

Ich bin vom Wesentlichen abgehoben (Förderung der Ausgabeaktivitäten der internen Organisation), aber ich habe gelernt, wie man kontinuierlich mit Crawlen und Docker-Compose testet. Es war. Ich hoffe, dass dies die Lerneffizienz der Organisation noch ein wenig verbessern wird.

Recommended Posts

Benachrichtigen Sie den Chat über neue Artikel der Qiita-Organisation und verbessern Sie die Lerneffizienz der Organisation!
Holen Sie sich Artikelbesuche und Likes mit Qiita API + Python
Ich habe die Methode des maschinellen Lernens und ihre Implementierungssprache anhand der Tag-Informationen von Qiita betrachtet
Ich habe den Chat von YouTube Live angezeigt und versucht zu spielen
[Qiita API] [Statistik • Maschinelles Lernen] Ich habe versucht, die bisher veröffentlichten Artikel zusammenzufassen und zu analysieren.
Ermitteln Sie die Anzahl der PVs von Qiita-Artikeln, die Sie mit API veröffentlicht haben
Benachrichtigen Sie den Inhalt der Aufgabe vor und nach der Ausführung der Aufgabe mit Fabric
Verbesserung der Wiederverwendbarkeit und Wartbarkeit von mit Luigi erstellten Workflows
Ich habe versucht, die Effizienz der täglichen Arbeit mit Python zu verbessern