Nachdem ich Elastic Search studiert habe, habe ich mich gefragt, ob ich etwas mit ES anfangen kann. Deshalb habe ich mit Kinesis + Lambda einen ereignisgesteuerten Webcrawler geschrieben.
Der allgemeine Fluss ist wie folgt.
Da Sie die Berechtigung zur Verwendung von Kinesis und Elastic Search benötigen, Haben Sie jeweils ** Zugriffsschlüssel-ID ** und ** geheimen Zugriffsschlüssel **.
Darüber hinaus ist auch die ARN des Benutzers erforderlich. Denken Sie also daran (arn: aws: iam :: ********: user / ********).
Erstellen Sie zunächst einen Kinesis-Stream.
Erstellen Sie als Nächstes eine ES mit Amazon Elastic Search Service.
Create a new domain
Geben Sie einen geeigneten Domainnamen in den Elasticsearch-Domainnamen ein (vorläufig Webarchive).
Wählen Sie [5.1] für die Elasticsearch-Version. Drücken Sie [Weiter]
Setzen Sie den Instanztyp unter Cluster konfigurieren auf [t2.small]. Klicken Sie auf Weiter (zum Testen, also mit einer kleinen Instanz).
Wählen Sie in der Richtlinie Zugriff einrichten die Option Zugriff auf ein oder mehrere AWS-Konten oder IAM-Benutzer zulassen oder verweigern aus
Geben Sie die ARN des Benutzers, den Sie zulassen möchten, in die Konto-ID oder die ARN * ein
Erstellen Sie mit [Bestätigen und erstellen]
Nach einer Weile wird ES gestartet. Überprüfen Sie daher [Endpunkt] und denken Sie daran, wie es in Lambda verwendet wird.
Erstellen Sie Zuordnungsdaten, um URL, Titel und Artikelinhalt für die Artikelspeicherung zu speichern.
mapping.json
{
"mappings": {
"article": {
"properties" : {
"url" : {
"type": "string",
"index" : "not_analyzed"
},
"title" : {
"type": "string",
"index" : "analyzed"
},
"contents" : {
"type": "string",
"index" : "analyzed"
}
}
}
}
}
Erstellen Sie als Nächstes die obigen Zuordnungsdaten und ein Skript, um einen Index zu erstellen.
Installieren Sie die folgenden Pakete vorab lokal
$ pip install requests_aws4auth elasticsearch
es-mapping.py
# -*- coding: utf-8 -*-
import elasticsearch
from requests_aws4auth import AWS4Auth
import json
if __name__ == '__main__':
#Geben Sie den ES-Endpunkt an
host='search-***************.ap-northeast-1.es.amazonaws.com'
awsauth = AWS4Auth(
#AWS-Benutzerzugriffsschlüssel-ID und geheimer Zugriffsschlüssel
'ACCESS_KRY_ID',
'SECRET_ACCESS_KEY',
'ap-northeast-1', 'es')
es = elasticsearch.Elasticsearch(
hosts=[{'host': host, 'port': 443}],
http_auth=awsauth,
use_ssl=True,
verify_certs=True,
connection_class=elasticsearch.connection.RequestsHttpConnection
)
f = open('mapping.json', 'r')
mapping = json.load(f)
es.indices.create(index='website')
es.indices.put_mapping(index='website', doc_type='article', body=mapping['mappings'])
$ python es-mapping.py
Wenn Sie das Skript ausführen, sollte es in AWS ES indiziert sein.
Nachdem wir ElasticSearch erstellt haben, ist es Zeit, die Lambda-Funktion zu erstellen.
Erstellen Sie lokal eine Lambda-Funktion.
$ mkdir web_crawler
$ cd web_crawler
$ vim lambda_function.py
lambda_function.py
# -*- coding: utf-8 -*-
import os
import base64
from readability import Document
import html2text
import requests
import elasticsearch
from elasticsearch import helpers
from requests_aws4auth import AWS4Auth
def lambda_handler(event, context):
host = os.environ['ES_HOST']
#Verwenden Sie die IAM-Rolle, um sich beim ElasticSearch-Dienst zu authentifizieren
awsauth = AWS4Auth(
os.environ['ACCESS_ID'],
os.environ['SECRET_KEY'], 'ap-northeast-1', 'es')
es = elasticsearch.Elasticsearch(
hosts=[{'host': host, 'port': 443}],
http_auth=awsauth,
use_ssl=True,
verify_certs=True,
connection_class=elasticsearch.connection.RequestsHttpConnection
)
articles = []
#Holen Sie sich Events von Kinesis Stream
for record in event['Records']:
payload = base64.b64decode(record['kinesis']['data'])
try:
response = requests.get(payload)
if response.ok:
article = Document(response.content).summary()
titleText = html2text.html2text(Document(response.content).title())
contentsText = html2text.html2text(article)
res = es.search(index="website", body={"query": {"match": {"url": payload}}})
#Ist die URL bereits in ES registriert?
if res['hits']['total'] is 0:
doc = {
'url': payload,
'title': titleText.encode('utf-8'),
'contents': contentsText.encode('utf-8')
}
articles.append({'_index':'website', '_type':'scraper', '_source':doc})
except requests.exceptions.HTTPError as err:
print("HTTPError: " + err)
# Bulk Insert
helpers.bulk(es, articles)
Installieren Sie nach dem Erstellen der Lambda-Funktion die erforderlichen Bibliotheken in derselben Hierarchie
$ pip install readability-lxml html2text elasticsearch requests_aws4auth requests -t /path/to/web_crawler
Mit Reißverschluss aushärten
$ zip -r web_crawler.zip .
[Lambda-Funktion erstellen]
Wählen Sie [Leere Funktion]
Wählen Sie den zuvor unter [Triggereinstellungen] erstellten Kinesis-Stream aus.
[Stapelgröße] beträgt ungefähr 10
[Startposition] ist horizontale Trimmung
Überprüfen Sie die Triggeraktivierung
Geben Sie [Name] in [Funktionseinstellungen] ein (vorläufig WebCrawler hier).
Wählen Sie Python 2.7 für Runtime
Wählen Sie unter Codeeingabetyp die Option ZIP-Datei hochladen aus
Geben Sie die zuvor aus [Funktionspaket] erstellte Zip-Datei an.
Setzen Sie [Umgebungsvariablen] auf 3, um auf Elastic Search zuzugreifen.
Greifen Sie auf die Schlüssel-ID in ACCESS_ID zu
Geheimer Zugriffsschlüssel auf SECRET_KEY
Elastic Search-Endpunkt auf ES_HOST
[Handler] bleibt lambda_function.lambda_handler
Erstellen Sie die entsprechenden Rollen
Stellen Sie [Timeout] unter [Detaillierte Einstellungen] auf ca. 2 Minuten ein.
[Funktion erstellen]
Verwenden Sie als Nächstes Scrapy, um die URL von der Listenseite zu extrahieren und die Daten an den Kinesis-Stream zu senden.
Die Listenseite verwendet den Hot-Eintrag von Hatena Bookmark. RSS scheint einfacher zu sein, Daten zu erhalten, wenn Sie Scrapy verwenden, aber ich habe es gewagt, von der Webseite zu kratzen. Scrapy ist ein nützliches und leistungsstarkes Framework zum Erstellen erweiterter Webcrawler. Wenn Sie interessiert sind, können Sie es jederzeit berühren.
Installieren Sie zuerst Scrapy
$ pip install scrapy
$ scrapy startproject hotentry
$ vim hotentry/hotentry/spiders/hotentry.py
Geben sie den untenstehenden Code ein.
hotentry.py
# -*- coding: utf-8 -*-
import scrapy
from scrapy.conf import settings
import boto3
import json
kinesis = boto3.client(
'kinesis',
aws_access_key_id=settings['AWS_ACCESS_KEY_ID'],
aws_secret_access_key=settings['AWS_SECRET_ACCESS_KEY'],
region_name='ap-northeast-1')
class HotEntrySpider(scrapy.Spider):
name = "hotentry"
allowed_domains = ["b.hatena.ne.jp"]
start_urls = ['http://b.hatena.ne.jp/hotentry/general']
def parse(self, response):
for sel in response.css("li.hb-entry-unit-with-favorites"):
url = sel.css("a.entry-link::attr('href')").extract_first()
if url is None:
continue
kinesis.put_record(
StreamName = "scraping_url",
Data = sel.css("a.entry-link::attr('href')").extract_first(),
PartitionKey = "scraper"
)
$ vim hotentry/hotentry/settings.py
Fügen Sie der settings.py die Zugriffsschlüssel-ID und den geheimen Zugriffsschlüssel hinzu
AWS_ACCESS_KEY_ID = 'AKI******************'
AWS_SECRET_ACCESS_KEY = '************************************'
Sie können jetzt in den Kinesis-Stream einfügen. Versuchen wir, diesen Code auszuführen.
$ scrapy crawl hotenty
Sie sollten nun in der Lage sein, die Daten mit "Scrapy-> Kinesis-> AWS Lambda-> Elastic Search" zu füllen.
Ich konnte die URL mit Scrapy extrahieren und an Kinesis senden, aber da es sich um einen lokalen Stapel handelt, stellen Sie den Scrapy-Code für einen Cloud-Dienst namens Scrapinghub bereit.
Weitere Informationen zur Installation finden Sie im folgenden Artikel.
Es ist einfach, von der Benutzerregistrierung bis zur Bereitstellung, also werde ich es aufschlüsseln.
Anfangs habe ich SQS und DynamoDB verwendet und die Lambda-Funktion in mehrere Teile unterteilt, aber es wurde kompliziert und ich war frustriert, weil ich dem Fehler nicht folgen konnte. Immerhin ist einfach am besten. Ich möchte, dass mehr Lambda-Trigger mehr Dienste unterstützen.
** * Da dieser Code in einem Test geschrieben wurde, wird die Fehlerbehandlung usw. nicht streng durchgeführt. Wenn Sie mit diesem Code Nachteile haben, tun Sie dies bitte auf eigenes Risiko. ** **.
Recommended Posts