Scrapyチュートリアル¶
このチュートリアルでは、Scrapyがシステムに既にインストールされていると仮定します。 そうでない場合は、 インストール ガイド を参照してください。
ここでは quotes.toscrape.com という、有名な著者からの引用をリストするウェブサイトをスクレイピングします。
このチュートリアルでは以下の作業について説明します。
新しいScrapyプロジェクトの作成
スパイダー(spider) を作成してサイトをクロールし、データを抽出します。
コマンドラインを使用してスクレイピングされたデータをエクスポートする。
再帰的にリンクをたどるようにスパイダーを変更する。
スパイダー引数の使用
Scrapyは Python で書かれています。 この言語を初めて使用する場合は、Scrapyを最大限に活用するために、この言語がどのようなものかを理解することから始めてください。
すでに他の言語に精通しており、Pythonをすばやく学習したい場合は、 Python Tutorial (訳注:日本語版 https://docs.python.org/ja/3/tutorial/)が優れた文書です。
プログラミングが初めてで、Pythonを使い始めたい場合は、以下の書籍が役立ちます:
Automate the Boring Stuff With Python (邦訳: 退屈なことはPythonにやらせよう――ノンプログラマーにもできる自動化処理プログラミング Al Sweigart 著、相川 愛三 訳 2017年06月 発行 ISBN978-4-87311-778-2 オライリー・ジャパン)
How To Think Like a Computer Scientist (訳注:ThinkPythonの日本語版ページ http://www.cauldron.sakura.ne.jp/thinkpython/)
Learn Python 3 The Hard Way (邦訳:Learn Python 3 the Hard Way 書いて覚えるPython入門 堂阪 真司 訳 丸善出版 2019年01月 ISBN 978-4-621-30328-3)
また、 this list of Python resources for non-programmers (この非プログラマ向けのPythonリソースのリスト)と、 suggested resources in the learnpython-subreddit (learnpython-subredditの推奨リソース)を参照することもできます。
プロジェクトの作成¶
スクレイピングを開始する前に、新しいScrapyプロジェクトをセットアップする必要があります。 あなたのコードを保存して実行するディレクトリを入力してください:
scrapy startproject tutorial
これにより、以下の内容の tutorial
ディレクトリが作成されます:
tutorial/
scrapy.cfg # deploy configuration file
tutorial/ # project's Python module, you'll import your code from here
__init__.py
items.py # project items definition file
middlewares.py # project middlewares file
pipelines.py # project pipelines file
settings.py # project settings file
spiders/ # a directory where you'll later put your spiders
__init__.py
私たちの最初のスパイダー¶
スパイダーはユーザが定義するクラスであり、ScrapyはWebサイト(またはWebサイトのグループ)から情報をスクレイピングするために使用します。 Spider
をサブクラス化して最初のリクエストを作成し、オプションで、ページ内のリンクをたどる方法やダウンロードしたページ内容をパースしてデータを抽出する方法を定義する必要があります。
以下は、最初のスパイダーのコードです。 プロジェクトの tutorial/spiders
ディレクトリの下の quotes_spider.py
という名前のファイルに保存します:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
def start_requests(self):
urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
page = response.url.split("/")[-2]
filename = f'quotes-{page}.html'
with open(filename, 'wb') as f:
f.write(response.body)
self.log(f'Saved file {filename}')
ご覧のとおり、スパイダーは scrapy.Spider
をサブクラス化し、いくつかの属性とメソッドを定義しています:
name
は、スパイダーを識別します。 プロジェクト内で一意である必要があります。つまり、異なるスパイダーに同じ名前を設定することはできません。start_requests()
は、スパイダーがクロールを開始するリクエストの反復可能オブジェクト(iterable)を返す必要があります(リクエストのリストを返すか、ジェネレーター関数を作成できます)。これらの初期リクエストから後続のリクエストが連続して生成されます(訳注:iterableの意味はPythonドキュメント/用語集 https://docs.python.org/ja/3/glossary.html 参照)。parse()
は、行われたリクエストごとにダウンロードされたレスポンスを処理するために呼び出されるメソッドです。 リクエスト・パラメーターはTextResponse
のインスタンスで、ページ内容を保持し、さらにそれを処理するための便利なメソッドを持っています。parse()
メソッドは通常、レスポンスをパースし、スクレイプされたデータを辞書として抽出し、追跡する新しいURLを見つけて、それらから新しいリクエスト(Request
)を作成します。
私たちのスパイダーの実行方法¶
スパイダーを動作させるには、プロジェクトの最上位ディレクトリに移動して、以下を実行します:
scrapy crawl quotes
このコマンドは、追加したばかりの quotes
という名前のスパイダーを実行し、 quotes.toscrape.com
ドメインへのリクエストを送信します。以下のような出力が得られます:
... (omitted for brevity)
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Spider opened
2016-12-16 21:24:05 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:24:05 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (404) <GET http://quotes.toscrape.com/robots.txt> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-1.html
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-2.html
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Closing spider (finished)
...
次に、現在のディレクトリのファイルを確認します。 parse
メソッドが指示するように、それぞれのURLのコンテンツを持つ2つの新しいファイル quotes-1.html と quotes-2.html が作成されていることに気付くはずです。
注釈
なぜまだHTMLをパースしていないのかって?順番に説明するからもうちょい待ってくれ。
一体全体どういう仕組みなのか?¶
Scrapyは、スパイダーの start_requests
メソッドによって返される scrapy.Request
オブジェクトをスケジュールします。 それぞれのレスポンスを受信すると、 Response
オブジェクトをインスタンス化し、リクエストに関連付けられたコールバック・メソッド(この場合は parse
メソッド)を呼び出して、レスポンスを引数として渡します。
start_requestsメソッドへのショートカット¶
URLから start_requests()
オブジェクトを生成する start_requests()
メソッドを実装する代わりに、単にURLのリストで start_urls
を定義できます。 このリストはそれから start_requests()
のデフォルト実装で使用され、あなたのスパイダーの初期リクエストを作成します:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
def parse(self, response):
page = response.url.split("/")[-2]
filename = f'quotes-{page}.html'
with open(filename, 'wb') as f:
f.write(response.body)
parse()
メソッドは、Scrapyに明示的に指示していない場合でも、これらのURLの各リクエストを処理するために呼び出されます。 これは、 parse()
がScrapyのデフォルトのコールバック・メソッドであり、明示的にコールバックが割り当てられていないリクエストに対して呼び出されるためです。
データの抽出¶
Scrapyでデータを抽出する方法を学ぶ最良の方法は、 Scrapyシェル を使用してセレクターを試すことです。 以下のように実行します:
scrapy shell 'http://quotes.toscrape.com/page/1/'
注釈
コマンドラインからScrapyシェルを実行するときは、常にURLをクォーテーションで囲むことを忘れないでください。そうしないと、引数(つまり、 &
キャラクタ)を含むURLは機能しません。
Windowsでは代わりにダブルクォーテーションを使って下さい:
scrapy shell "http://quotes.toscrape.com/page/1/"
あなたは以下のようなものを見る事になるでしょう:
[ ... Scrapy log here ... ]
2016-09-19 12:09:27 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x7fa91d888c90>
[s] item {}
[s] request <GET http://quotes.toscrape.com/page/1/>
[s] response <200 http://quotes.toscrape.com/page/1/>
[s] settings <scrapy.settings.Settings object at 0x7fa91d888c10>
[s] spider <DefaultSpider 'default' at 0x7fa91c8af990>
[s] Useful shortcuts:
[s] shelp() Shell help (print this help)
[s] fetch(req_or_url) Fetch request (or URL) and update local objects
[s] view(response) View response in a browser
シェルを使用して、あなたはレスポンス・オブジェクトで CSS を使用して要素の選択を試す事ができます:
>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]
response.css('title')
を実行した結果は、 SelectorList
というリストのようなオブジェクトになり、これはXML/HTML要素をラップし、さらにクエリを実行して選択範囲を細かくしたり、データを抽出したりできるオブジェクトである Selector
のリストになっています。
上記のタイトルからテキストを抽出するには、以下のようにします:
>>> response.css('title::text').getall()
['Quotes to Scrape']
ここで注意すべき点が2つあります。1つは、CSSクエリに ::text
を追加したことです。これは、 <title>
要素内のテキスト要素のみを直接選択することを意味します。 ::text
を指定しない場合、そのタグを含む完全なタイトル要素を取得します:
>>> response.css('title').getall()
['<title>Quotes to Scrape</title>']
もう1つは、 .getall()
を呼び出した結果がリストであるということです。セレクターが複数の結果を返す可能性があり、そしてそれらの全てを抽出します。この場合のように、最初の結果だけが必要であることがわかったら、次の操作を実行できます:
>>> response.css('title::text').get()
'Quotes to Scrape'
代わりに以下のように書くこともできます:
>>> response.css('title::text')[0].get()
'Quotes to Scrape'
けれども、 SelectorList
インスタンスで .get()
を直接使用すると、 IndexError
を回避し、セレクターに一致する要素が見つからない場合 None
を返します。
ここに教訓があります。ほとんどのスクレイピングコードでは、ページ上で見つからないものに起因するエラーに対して回復力を持たせ、一部のスクレイピングに失敗した場合でも、少なくとも いくつかの データを取得できるようにします。
getall()
メソッドや get()
メソッドに加えて、 正規表現 (訳注: https://docs.python.org/ja/3/library/re.html ) により抽出する re()
メソッドも使用できます:
>>> response.css('title::text').re(r'Quotes.*')
['Quotes to Scrape']
>>> response.css('title::text').re(r'Q\w+')
['Quotes']
>>> response.css('title::text').re(r'(\w+) to (\w+)')
['Quotes', 'Scrape']
使用する適切なCSSセレクターを見つけるには、 view(response)
を使用してWebブラウザーのシェルからレスポンス・ページを開くと便利です。 ブラウザの開発ツールを使用してHTMLを調査し、セレクターを作成できます(Webブラウザの開発ツールを使ってスクレイピングする 参照)。
Selector Gadget という、多くのブラウザで動作する、選択された要素のCSSセレクターを視覚的にすばやく探せる素晴らしいツールもあります。
XPathの簡単な紹介¶
CSS に加えて、Scrapyセレクターは XPath 式の使用もサポートしています:
>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').get()
'Quotes to Scrape'
XPath式は非常に強力であり、Scrapyセレクターの基盤です。 実際、CSSセレクターは内部でXPathに変換されます。 シェル内のセレクター・オブジェクトのテキスト表現をよく読んでいれば、あなたはそれに気付く事ができるでしょう。
CSSセレクターほど一般的ではないかもしれませんが、XPath式は構造をナビゲートするだけでなく、内容を探すことができるため、より強力になります。 XPathを使用すると、「『Next Page』というテキストを含むリンクを選択」というような事ができます。これにより、XPathはスクレイピングのタスクに非常に適合します。CSSセレクターの構築方法を既に知っている場合でも、XPathを学ぶことをお勧めします。
ここではXPathについてはあまり取り上げませんが、 ScrapyセレクターでXPathを使用 に詳しく載っています。XPathの詳細については、 this tutorial to learn XPath through examples と this tutorial to learn "how to think in XPath" を私たちはお勧めします。
引用と著者の抽出¶
選択と抽出について少し理解できたので、Webページから引用を抽出するコードを作成して、スパイダーを完成させましょう。
http://quotes.toscrape.com の各引用は、次のようなHTML要素で表されます:
<div class="quote">
<span class="text">“The world as we have created it is a process of our
thinking. It cannot be changed without changing our thinking.”</span>
<span>
by <small class="author">Albert Einstein</small>
<a href="/author/Albert-Einstein">(about)</a>
</span>
<div class="tags">
Tags:
<a class="tag" href="/tag/change/page/1/">change</a>
<a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a>
<a class="tag" href="/tag/thinking/page/1/">thinking</a>
<a class="tag" href="/tag/world/page/1/">world</a>
</div>
</div>
Scrapyシェルで少しいじって、必要なデータを抽出する方法を見つけましょう:
$ scrapy shell 'http://quotes.toscrape.com'
引用HTML要素のセレクターのリストを取得します:
>>> response.css("div.quote")
[<Selector xpath="descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' quote ')]" data='<div class="quote" itemscope itemtype...'>,
<Selector xpath="descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' quote ')]" data='<div class="quote" itemscope itemtype...'>,
...]
上記のクエリによって返された各セレクターを使用すると、サブ要素に対してさらにクエリを実行できます。 最初のセレクターを変数に割り当てて、特定の引用でCSSセレクターを直接実行できるようにします:
>>> quote = response.css("div.quote")[0]
それでは、作成したばかりの quote
オブジェクトを使用して、その引用から text
と author
と tags
を抽出しましょう:
>>> text = quote.css("span.text::text").get()
>>> text
'“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
>>> author = quote.css("small.author::text").get()
>>> author
'Albert Einstein'
タグは文字列のリストになっているので、 .getall()
メソッドを使用してそれらすべてを取得できます:
>>> tags = quote.css("div.tags a.tag::text").getall()
>>> tags
['change', 'deep-thoughts', 'thinking', 'world']
各パーツを抽出する方法を考え出したので、すべての引用要素を反復処理して、それらをPython辞書にまとめることができます:
>>> for quote in response.css("div.quote"):
... text = quote.css("span.text::text").get()
... author = quote.css("small.author::text").get()
... tags = quote.css("div.tags a.tag::text").getall()
... print(dict(text=text, author=author, tags=tags))
{'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', 'author': 'Albert Einstein', 'tags': ['change', 'deep-thoughts', 'thinking', 'world']}
{'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', 'author': 'J.K. Rowling', 'tags': ['abilities', 'choices']}
...
私たちのスパイダーでデータを抽出する¶
私たちのスパイダーに戻ります。これまでは、特にデータを抽出せず、HTMLページ全体をローカルファイルに保存するだけでした。それでは、ここで、上記の抽出ロジックを私たちのスパイダーに組み込みましょう。
Scrapyスパイダーは通常、ページから抽出されたデータを含む多くのPython辞書を生成します。 これを行うには、以下に示すように、コールバックでPythonキーワード yield
を使用します:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
あなたがこのスパイダーを実行すると、抽出されたデータがlogとともに出力されます:
2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['life', 'love'], 'author': 'André Gide', 'text': '“It is better to be hated for what you are than to be loved for what you are not.”'}
2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['edison', 'failure', 'inspirational', 'paraphrased'], 'author': 'Thomas A. Edison', 'text': "“I have not failed. I've just found 10,000 ways that won't work.”"}
スクレイピングしたデータの格納¶
スクレイピングされたデータを保存する最も簡単な方法は、 フィード・エクスポート を以下のコマンドで使用することです:
scrapy crawl quotes -O quotes.json
それにより、スクレイピングされたすべてのアイテムを含み JSON でシリアライズされた quotes.json
ファイルを生成します。
-O
コマンドラインスイッチは既存のファイルを上書きします。 一方 -o
を使用すると、既存のファイルに新しいコンテンツを追加します。 ただし、JSONファイルに追加をすると、無効なJSONになります。ファイルに追加するときは、 JSON Lines など別のシリアル化形式の使用を検討してください:
scrapy crawl quotes -o quotes.jl
JSON Lines フォーマットは、ストリームに似ているため便利です。新しいレコードを簡単に追加できます。 2回実行する場合、JSONと違って壊れる事はありません。また、各レコードは個別の行であるため、メモリにすべてを収めなくても大きなファイルを処理できます。コマンドラインでそれを行うのに役立つ JQ などのツールがあります。
小さなプロジェクト(このチュートリアルのようなプロジェクト)では、これで十分です。 ただし、スクレイピングされたアイテムを使用してより複雑な操作を実行する場合は、 アイテム・パイプライン を記述できます。 アイテム・パイプラインのプレースホルダーファイルは、プロジェクトの作成時に tutorial/pipelines.py
に設定されています。 ただし、スクレイピングされたアイテムを保存するだけの場合は、アイテム・パイプラインを実装する必要はありません。
リンクを辿る¶
たとえば、http://quotes.toscrape.comの最初の2ページの内容を単にスクレイピングするのではなく、Webサイトのすべてのページの引用が必要な場合を考えます。
ページからデータを抽出する方法がわかったので、ページからリンクをたどる方法を見てみましょう。
まず、辿りたいページへのリンクを抽出します。 ページを調べると、以下のマークアップを含む、次のページへのリンクがあることがわかります:
<ul class="pager">
<li class="next">
<a href="/page/2/">Next <span aria-hidden="true">→</span></a>
</li>
</ul>
私たちはScrapyシェルでこれの抽出を試してみることができます:
>>> response.css('li.next a').get()
'<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'
これはアンカー要素を取得しますが、属性 href
が必要です。 そのために、Scrapyは、次のように属性の内容を選択できるCSS拡張機能をサポートしています:
>>> response.css('li.next a::attr(href)').get()
'/page/2/'
attrib
プロパティもあります(詳細については 要素属性の選択 参照):
>>> response.css('li.next a').attrib['href']
'/page/2/'
次のページへのリンクを再帰的にたどって、そこからデータを抽出するように修正した私たちのスパイダーを見てみましょう:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, callback=self.parse)
ここで、データを抽出した後、 parse()
メソッドは次のページへのリンクを探し、 urljoin()
メソッドを使用して完全な絶対URLを構築します(リンクは相対的な場合があります)、そして次のページへの新しいリクエストを生成し、次のページのデータ抽出を処理し、すべてのページをクロールし続けるために、コールバックとして登録します。
ここに表示されるのは、リンクをたどるScrapyのメカニズムです。コールバック・メソッドでリクエストを生成すると、Scrapyはそのリクエストの送信をスケジュールし、リクエストが終了したときに実行されるコールバック・メソッドを登録します。
これを使用して、定義したルールに従ってリンクをたどる複雑なクローラーを構築し、アクセスしているページに応じてさまざまな種類のデータを抽出できます。
この例では、次のページへのすべてのリンクをたどるループを作成します。ループが見つからなくなるまで、ブログやフォーラムやその他、ページ分けのあるサイトをクロールするのに便利です。
リクエストを作成するためのショートカット¶
Requestオブジェクトを作成するためのショートカットとして、 response.follow
を使用できます:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('span small::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
scrapy.Requestとは異なり、 response.follow
は相対URLに対応しています。つまり、urljoinを呼び出す必要はありません。 response.follow
はRequestインスタンスを返すだけであることに注意してください。 scrapy.Requestと同様、あなたはこのリクエストを作用(yield)させる必要があります。
文字列ではなく response.follow
にセレクターを渡すこともできます。 このセレクターは必要な属性を抽出する必要があります:
for href in response.css('ul.pager a::attr(href)'):
yield response.follow(href, callback=self.parse)
<a>
要素のためのショートカットがあります。 response.follow
はhref属性を自動的に使用します。 したがって、コードをさらに短くすることができます:
for a in response.css('ul.pager a'):
yield response.follow(a, callback=self.parse)
反復可能ファイルから複数のリクエストを作成するには、代わりに response.follow_all
を使用できます:
anchors = response.css('ul.pager a')
yield from response.follow_all(anchors, callback=self.parse)
更に短縮してみます:
yield from response.follow_all(css='ul.pager a', callback=self.parse)
さらなる例やパターン¶
コールバックと次のリンクを示す別のスパイダーを次に示します。今回は著者情報をスクレイピングするためのものです:
import scrapy
class AuthorSpider(scrapy.Spider):
name = 'author'
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
author_page_links = response.css('.author + a')
yield from response.follow_all(author_page_links, self.parse_author)
pagination_links = response.css('li.next a')
yield from response.follow_all(pagination_links, self.parse)
def parse_author(self, response):
def extract_with_css(query):
return response.css(query).get(default='').strip()
yield {
'name': extract_with_css('h3.author-title::text'),
'birthdate': extract_with_css('.author-born-date::text'),
'bio': extract_with_css('.author-description::text'),
}
このスパイダーはメインページから始まり、各ページの parse_author
コールバックを呼び出す作成者ページへのすべてのリンクと、以前解説したように parse
コールバックのページ分けリンクをたどります。
ここでは、コードを短くするための位置引数として、コールバックを response.follow_all
に渡しますが、 Request
でも機能します。
parse_author
コールバックは、CSSクエリからデータを抽出してクリーンアップするヘルパー関数を定義し、著者データを含むPython辞書を生成します。
このスパイダーが示すもう1つの興味深い点は、同じ著者からの引用が多数ある場合でも、同じ著者ページに何度もアクセスすることを心配する必要がないことです。 デフォルトでは、ScrapyはすでにアクセスしたURLへの重複したリクエストを除外し、プログラミングのミスによるサーバーへの過剰なアクセスの問題を回避します。 これは設定 DUPEFILTER_CLASS
で設定できます。
今や、あなたはScrapyでリンクとコールバックをたどるメカニズムを使う方法を十分に理解できたと思います。
リンクをたどるメカニズムを活用するさらに別のスパイダーの例として、クローラーを作成するために使用できる小さなルールエンジンを実装する汎用スパイダーの CrawlSpider
クラスを確認してください。
また、一般的なパターンは、 コールバックに追加のデータを渡す手口 を使用して、複数のページからのデータでアイテムを構築することです。
スパイダー引数の使用¶
あなたはスパイダーの実行時に -a
オプションを使用して、スパイダーにコマンドライン引数を提供できます:
scrapy crawl quotes -O quotes-humor.json -a tag=humor
これらの引数はSpiderの __init__
メソッドに渡され、デフォルトでspider属性になります。
この例では、 tag
引数に指定された値は self.tag
を介して利用できます。 これを使用して、スパイダーに特定のタグを持つ引用のみを読み込み(fetch)させ、引数に基づいてURLを構築できます:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
def start_requests(self):
url = 'http://quotes.toscrape.com/'
tag = getattr(self, 'tag', None)
if tag is not None:
url = url + 'tag/' + tag
yield scrapy.Request(url, self.parse)
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
yield response.follow(next_page, self.parse)
あなたがこのスパイダーに tag=humor
引数を渡すと、 http://quotes.toscrape.com/tag/humor
などの humor
タグのURLのみにアクセスすることに気付くでしょう。
スパイダー引数の取扱について更に学ぶ をご覧ください。
さぁてお次は?¶
このチュートリアルでは、Scrapyの基本のみを説明しましたが、ここには記載されていない他の多くの機能があります。 最も重要なものの簡単な概要については、 Scrapyを3行で説明シル の章の 他に何かある? 節を確認してください。
基本の概念 節では続けて、コマンドラインツール、スパイダー、セレクター、およびスクレイプデータのモデリングのようにチュートリアルで扱っていないその他のことについて詳しく知ることができます。 サンプルプロジェクトで遊びたい場合は、 例 節を確認してください。