クロール対象のサイトへのリクエスト、レスポンスのパース処理を記述します どのようにサイトを辿って、ページの内容をどうパースするかのロジックが Spider に書かれます
クロール対象のデータから抽出したいデータ構造を記述するモデルのようなものです 目的に応じて自由な構造を定義できます Items は Spider で生成され Pipeline に渡されます
Spider より渡された Items に対する処理を記述します DB への保存、ファイル出力など目的に応じて自由に処理を記述できます
import logging logging.error("Some error")
scrapy startproject tutorial
robots.txt
を見つけるrobots.txt
からsitemap.xml
を見つけるsitemap.xml
から各コンテンツページに行くmetatag
を取得するmetatag
をクレンジングし、 itemsに変換するPythonファイルの実行または、CLIの実行どちらからでも実行できる。
scrapy crawl {SPIDER_NAME} # 実行 scrapy crawl {SPIDER_NAME} -o results/example.csv # 実行 & csv出力
from bs4 import BeautifulSoup class WebsiteSpider(scrapy.Spider): def parse(self, response): # BeautifulSoupを使う soup = BeautifulSoup(response.body, "lxml") ...
print(response.xpath("//meta").extract())
def parse(self, response): soup = BeautifulSoup(response.body, "lxml") # MetaTagの取得 # Normal description = soup.find("meta", { "name": "description" }) title = soup.find("title").string # タグの中身を取る url = response.url print("description: %s" % (description['content'])) print("title: %s" % (title)) print("url: %s" % (url)) # OGP og_description = soup.find("meta", { "property": "og:description" }) og_title = soup.find("meta", { "property": "og:title" }) og_url = soup.find("meta", { "property": "og:url" }) og_image_url = soup.find('meta', { 'property': 'og:image' }) print("og_description: %s" % (og_description['content'])) print("og_title: %s" % (og_title['content'])) print("og_url: %s" % (og_url['content'])) print("og_image_url: %s" % (og_image_url['content']))
ERROR: Spider error processing
どこかnullだったりで落ちている。
spider.pyarticle = ArticleItem() article['description'] = description article['title'] = title article['url'] = url article['image_url'] = og_image_url print("article: %s" % (article)) yield article
pipeline.pyclass ArticlePipeline(object): file = None def process_item(self, item, spider): print(item) return item
NOTE1: 定義したfield以外を代入すると、エラーになります。(当たり前)
NOTE2: ちなみに、クロールが長かった場合、途中で終了しても、出力設定をしていた場合、出力される。
import scrapy import firebase_admin from firebase_admin import credentials, firestore # import logging # Hack: 下記環境変数を設定しないとエラーになる import os os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './serviceAccount.json' # 値のバリデーションチェック class ValidationPipeline(object): print('ValidationPipeline: Activate') def process_item(self, item: scrapy.Item, spider: scrapy.Spider): if item['title'] is None or item['title'] == '': raise scrapy.exceptions.DropItem('Missing value: title') if item['url'] is None or item['url'] == '': raise scrapy.exceptions.DropItem('Missing value: url') return item class ArticlePipeline(object): file = None def __init__(self): cred = credentials.Certificate('./serviceAccount.json') firebase_admin.initialize_app(cred) def open_spider(self, spider: scrapy.Spider): print('ArticlePipeline.open_spider: Activate') def close_spider(self, spider: scrapy.Spider): print('ArticlePipeline.close_spider: Activate') def process_item(self, item: scrapy.Item, spider: scrapy.Spider): print(item['title']) db = firestore.Client() # NOTE: document() 指定なしだとランダムにIDが生成される doc_ref = db.collection(u'articles').document() doc_ref.set({ u'description': item['description'], u'image_url': item['image_url'], u'title': item['title'], u'url': item['url'], }) return item
None
: dictのkeyがない場合、終了''
: 空文字の場合、終了Pythonで、Noneは、nullと同じ使われた方をする
pipelines.pyclass ValidationPipeline(object): def process_item(self, item: scrapy.Item, spider: scrapy.Spider): if item['description'] is None: raise scrapy.exceptions.DropItem('Missing value: description') if item['title'] is None or item['title'] == '': raise scrapy.exceptions.DropItem('Missing value: title') if item['url'] is None or item['url'] == '': raise scrapy.exceptions.DropItem('Missing value: url') if item['image_url'] is None: raise scrapy.exceptions.DropItem('Missing value: image_url') return item
settings.pyITEM_PIPELINES = { 'crawler.pipelines.ValidationPipeline': 100, 'crawler.pipelines.ArticlePipeline': 300, }
設定する数字で、実行順番の制御を行っているよう。