よくある例

このセクションでは、Scrapyを使用する際によくある例について説明します。 これらはいくつもトピックに渡るものであり、他の特定のトピックにはあまり該当しません。

スクリプトからScrapyを実行する

あなたは scrapy crawl を介してScrapyを実行する一般的な方法の代わりに、 API を使用してスクリプトからScrapyを実行できます。

ScrapyはTwisted非同期ネットワークライブラリの上に構築されているため、Twistedリアクター内で実行する必要があることに注意してください。

あなたがスパイダーを実行するために使用できる最初のユーティリティは scrapy.crawler.CrawlerProcess です。 このクラスは、Twistedリアクターを開始し、ロギングを構成し、シャットダウン・ハンドラーを設定します。 このクラスは、すべてのScrapyコマンドで使用されるクラスです。

単一のスパイダーを実行する方法を示す例を以下に示します。

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider(scrapy.Spider):
    # Your spider definition
    ...

process = CrawlerProcess(settings={
    "FEEDS": {
        "items.json": {"format": "json"},
    },
})

process.crawl(MySpider)
process.start() # the script will block here until the crawling is finished

CrawlerProcessの辞書内の設定を定義します。 CrawlerProcess の文書を確認して、使用方法の詳細を把握してください。

あなたがScrapyプロジェクト内にいる場合は、プロジェクト内にこれらのコンポーネントをインポートするために使用できる追加のヘルパーがいくつかあります。名前を CrawlerProcess に渡してスパイダーを自動的にインポートし、 get_project_settings を使用してプロジェクト設定で Settings インスタンスを取得できます。

以下は、例として testspiders プロジェクトを使用して、それを行う方法の実際の例です。

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

process = CrawlerProcess(get_project_settings())

# 'followall' is the name of one of the spiders of the project.
process.crawl('followall', domain='scrapy.org')
process.start() # the script will block here until the crawling is finished

クロール・プロセスをより詳細に制御する別のScrapyユーティリティがあります。それは scrapy.crawler.CrawlerRunner です。このクラスは、複数のクローラーを実行するための単純なヘルパーをカプセル化する薄いラッパーですが、既存のリアクターを開始したり、それに干渉したりすることはありません。

このクラスを使用すると、スパイダーをスケジュールした後にリアクターを明示的に実行する必要があります。アプリケーションがすでにTwistedを使用しており、同じリアクターでScrapyを実行する場合は、 CrawlerProcess の代わりに CrawlerRunner を使用することをお勧めします。

スパイダーが終了した後、自分でTwistedリアクターをシャットダウンする必要があることに注意してください。これは、 CrawlerRunner.crawl メソッドによって返される遅延オブジェクトにコールバックを追加することで実現できます。

以下に使用例と、 MySpider の実行が終了した後に手動でリアクターを停止するコールバックを示します。

from twisted.internet import reactor
import scrapy
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging

class MySpider(scrapy.Spider):
    # Your spider definition
    ...

configure_logging({'LOG_FORMAT': '%(levelname)s: %(message)s'})
runner = CrawlerRunner()

d = runner.crawl(MySpider)
d.addBoth(lambda _: reactor.stop())
reactor.run() # the script will block here until the crawling is finished

同じプロセスで複数のスパイダーを実行する

デフォルトでは、あなたが scrapy crawl を実行すると、Scrapyはプロセスごとに1つのスパイダーを実行します。ただし、Scrapyは、内部API を使用して、プロセスごとに複数のスパイダーを実行することをサポートしています。

複数のスパイダーを同時に実行する例を次に示します:

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider1(scrapy.Spider):
    # Your first spider definition
    ...

class MySpider2(scrapy.Spider):
    # Your second spider definition
    ...

process = CrawlerProcess()
process.crawl(MySpider1)
process.crawl(MySpider2)
process.start() # the script will block here until all crawling jobs are finished

CrawlerRunner を使用した同じ例:

import scrapy
from twisted.internet import reactor
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging

class MySpider1(scrapy.Spider):
    # Your first spider definition
    ...

class MySpider2(scrapy.Spider):
    # Your second spider definition
    ...

configure_logging()
runner = CrawlerRunner()
runner.crawl(MySpider1)
runner.crawl(MySpider2)
d = runner.join()
d.addBoth(lambda _: reactor.stop())

reactor.run() # the script will block here until all crawling jobs are finished

同じ例ですが、遅延オブジェクトを連鎖させてスパイダーを順番に実行します:

from twisted.internet import reactor, defer
from scrapy.crawler import CrawlerRunner
from scrapy.utils.log import configure_logging

class MySpider1(scrapy.Spider):
    # Your first spider definition
    ...

class MySpider2(scrapy.Spider):
    # Your second spider definition
    ...

configure_logging()
runner = CrawlerRunner()

@defer.inlineCallbacks
def crawl():
    yield runner.crawl(MySpider1)
    yield runner.crawl(MySpider2)
    reactor.stop()

crawl()
reactor.run() # the script will block here until the last crawl call is finished

分散クロール

Scrapyは、分散(マルチサーバー)方式でクロールを実行するための組み込み機能を提供しません。ただし、クロールを配布する方法はいくつかあり、それらは配布方法によって異なります。

多数のスパイダーがある場合、負荷を分散する明白な方法は、多くのScrapydインスタンスをセットアップし、それらの間でスパイダー実行を分散することです。

代わりに、多くのマシンで単一の(大きな)スパイダーを実行したい場合、通常行うことは、クロールするURLをパーティション分割して、各スパイダーに送信します。 具体例を次に示します:

最初に、クロールするURLのリストを準備し、それらを個別のファイル/URLに入れます:

http://somedomain.com/urls-to-crawl/spider1/part1.list
http://somedomain.com/urls-to-crawl/spider1/part2.list
http://somedomain.com/urls-to-crawl/spider1/part3.list

次に、3つの異なるScrapydサーバーで実行されるスパイダーを起動します。スパイダーはクロールするパーティションの番号を含む(スパイダー)引数 part を受け取ります:

curl http://scrapy1.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=1
curl http://scrapy2.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=2
curl http://scrapy3.mycompany.com:6800/schedule.json -d project=myproject -d spider=spider1 -d part=3

バン(拒否)されるのを避ける

一部のWebサイトでは、高度なレベルのさまざまなボットによるクロールを防止するための特定の手段を実装しています。これらの対策を回避することは難しい場合があり、特別なインフラストラクチャが必要になる場合があります。疑問がある場合は、(有償の)商用サポート(commercial support)に連絡することを検討してください。

これらの種類のサイトを扱う際に留意するべきいくつかのヒントは以下にあります:

  • ブラウザから取得したよく使われているユーザーエージェントのプールを使ってユーザーエージェントをローテーションします(googleでそれらのリストを取得します)

  • クッキーを無効にします( COOKIES_ENABLED 参照)

  • ダウンロード遅延(2以上)を使用します。 DOWNLOAD_DELAY 設定を参照してください。

  • 可能であれば、サイトに直接アクセスするのではなく、Googleキャッシュ(Google cache)を使用してページを取得します

  • ローテートIPのプールを使用します。 たとえば、無料のTorプロジェクト(Tor project) または ProxyMesh のような有料サービスです。オープンソースの代替手段は、 scrapoxy です。これは、独自のプロキシをアタッチできるスーパープロキシです。

  • 内部的に禁止を回避する高度に分散されたダウンローダーを使用することで、クリーンなページのパースに集中できます。そのようなダウンローダーの一例は Zyte Smart Proxy Manager です

それでもボットが禁止されるのを防ぐことができない場合は、(有償の)商用サポート(commercial support)に連絡することを検討してください。