banner
bladedragon

bladedragon

scrapyクローリング入門

今、クローリングについて話すと、誰もが多かれ少なかれ Python とクローリングを結びつけるでしょう。根本的には、Python の豊富なエコシステムと柔軟でシンプルな文法によるものです。同時に、Python に基づいていくつかの強力なクローリングフレームワークが存在し、クローリングの難易度を大幅に下げ、プログラムの作成効率を向上させました。最近、私も Scrapy を体験してみたので、入門の記録を残しておきます。

概要#

Scrapy は、ウェブサイトをクローリングし、構造化データを抽出するためのアプリケーションフレームワークであり、データマイニング、情報処理、または歴史的アーカイブなど、さまざまな有用なアプリケーションに使用できます。

—— 公式サイトからの翻訳

直接公式サイトを確認することをお勧めします。そこには完全な Scrapy チュートリアルもあり、フレームワークを深く学ぶための必須の選択肢です!

インストール#

Scrapy フレームワークをインストールする際、インターネット上には多くの方法がありますが、Python の環境によっては奇妙なエラーが発生することがあります。ここでは Python3 環境を基にして、pip を事前にインストールし、実際にテストしてみました。

事前インストール環境

Windows 10 + python 3.7.0 + pip20.1 + virtualenv

他のパッケージの依存関係の衝突を避けるために、新しい virtual 環境を開いてください。

前提条件のインストールコンポーネント

  • lxml
  • pyOpenSSL
  • Twisted
  • PyWin32

lxml のインストール

直接pipでインストールできます。これはpythonHTMLXML解析ライブラリで、フレームワークを使用しなくても頻繁に使用されます。

pip3 install lxml

PyWin32 のインストール

公式サイトから対応するバージョンのインストーラをダウンロードしてダブルクリックでインストールします [pywin32]([https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/](https://sourceforge.net/projects/pywin32/files/pywin32/Build 221/))

残りのコンポーネントのインストール

ここでまずwheelについて紹介します。

wheelpythonのパッケージ形式で、以前はpythonの主流のパッケージ形式は.eggファイルでしたが、現在は*.whlファイルも人気になっています。

wheelは実際には Python の圧縮パッケージコンポーネントで、zip のようなものですが、この記事では wheel ファイル形式を使用することで、ライブラリを迅速に Python 環境にインストールできることを知っておけば大丈夫です。

インストールは実際にとても簡単です。

pip3 install wheel

これであなたのpython環境は.whlファイル形式のインストールをサポートします。

次のステップは、各公式サイトから各コンポーネントのwhl形式をダウンロードすることです。注意して、あなたの Python 環境に合わせてください。

インストール

pip3 install pyOpenSSL-19.1.0-py2.py3-none-any.whl 
  • Twistedあなたの Python バージョンに対応していることを確認してください。

私の環境では次のようになります。

pip3 install Twisted-20.3.0-cp37-cp37m-win_amd64.whl

Scrapy のインストール

すべての依存パッケージが正常にインストールされた後、直接 pip で Scrapy をインストールすれば問題ありません。

pip3 install Scrapy

コンポーネントの紹介#

まずプロジェクトを作成します。

クローリングプロジェクトを配置したいフォルダで実行します。xxx はあなたのプロジェクト名です。

scrapy startproject xxx

基本的な操作をいくつか記録しておきます。

  • プロジェクトの作成:scrapy startproject xxx
  • プロジェクトに入る:cd xxx #特定のフォルダに入る
  • クローラーを作成:scrapy genspider xxx(クローラー名) xxx.com (クローリングドメイン)
  • ファイルを生成:scrapy crawl xxx -o xxx.json (特定のタイプのファイルを生成)
  • クローラーを実行:scrapy crawl XXX
  • すべてのクローラーをリスト:scrapy list
  • 設定情報を取得:scrapy settings [options]

作成が完了すると、フォルダ内にこれらの内容が追加されているのが見えます。

image

これらのコンポーネントを一つずつ紹介します(spider_demoはあなたのクローリングプロジェクト名です)。

  • scrapy.cfg: プロジェクトの設定ファイル(プロジェクトフォルダの平行ディレクトリにあります)
  • spider_demo/spiders/: spiderコードを配置するディレクトリ(クローラーのロジックを配置する場所)
  • spider_demo/items.py: プロジェクト内のitemファイル(コンテナを作成する場所であり、最終的にクローラーが得る結果の形式を定義する場所)
  • spider_demo/pipelines.py: プロジェクト内のpipelinesファイル(データのクレンジング、保存、検証を実現)
  • spider_demo/settings.py: プロジェクトの設定ファイル(クローラーの具体的な設定、特定のミドルウェアの起動や機能のオンオフなど)
  • spider_demo/middlewares.py: プロジェクトのダウンローダーミドルウェアとクローラーミドルウェアを定義

まだ少し混乱しているかもしれませんが、次にscrapyの動作原理を簡単に紹介します。これにより、これらのコンポーネントの役割をより理解できると思います。


公式サイトのフローチャート

Scrapy アーキテクチャ

Scrapyは実行エンジンによって制御されます。

  1. SpiderEngineにリクエストを送信します。
  2. EngineがリクエストをSchedulerに割り当て、次のクローリングリクエストを受け取ります。
  3. Schedulerが次のリクエストを返します。
  4. EngineがリクエストをDownloader Middlewaresを介してDownloaderに送信します。
  5. Downloaderがウェブページをクローリングし、結果をDownloader Middlewaresを介してEngineに返します。
  6. エンジンが応答を受け取り、Spider Middlewareを介してSpiderに転送して処理します。
  7. Spiderparse()メソッドが取得したresponseを処理し、itemsまたはリクエストを解析し、解析されたitemsまたはリクエストをEngineに返します。
  8. EngineitemsItem Pipelineに送信し、リクエストをSchedulerに送信します。
  9. 新しいリクエストがなくなるまでステップ 1 を繰り返します。

上記のステップで出現するコンポーネントをまとめると、

コンポーネント名コンポーネント機能
Engineフレームワークのコア、全体のデータと信号のスケジューリングを担当フレームワーク実装
Schedulerリクエストを格納するキューフレームワーク実装
Downloader具体的なダウンロードタスクを実行するユニットフレームワーク実装
Spiderダウンロードした応答結果を処理し、必要なデータを抽出する(具体的なビジネスロジック)自分で実装
Item Pipeline最終的に得られたデータを処理し、永続化操作を行う自分で実装
Downloader Middlewares本格的にダウンロードタスクを実行する前に、カスタム処理を行うことができる。リクエストヘッダーの設定やプロキシの設定など自分で実装
Spider Middlewaresリクエストをカスタマイズし、応答をフィルタリングする自分で実装

この一連の組み合わせで、このフレームワークに対する基本的な理解が得られたと思います。次は実戦を通じて記憶を強化しましょう。

簡単なアプリケーション#

今回は、インターネット上で猫眼映画のランキングをクローリングするデモを作成しました。今後、時間があれば、より複雑なデモに変更します。

実現目標は、映画ランキングのタイトル、スコア、順位をクローリングし、結果を.jsonファイルにjson形式で保存することです。

image

まず、クローリングするデータを決定し、必要なデータをコンテナに記録します。item.pyで次のように記述します:

import scrapy

#ここでは順位、タイトル、評価人数、公開時間、スコアが必要です
class SpiderDemoItem(scrapy.Item):
    # アイテムのフィールドをここで定義します:
    # name = scrapy.Field()
    index = scrapy.Field()
    title = scrapy.Field()
    star = scrapy.Field()
    releasetime = scrapy.Field()
    score = scrapy.Field()

次に、Spidersフォルダ内に新しいクローラーファイルを作成します。例えば、MoyanSpider.pyというファイルを新しく作成しました。

import scrapy
from spider_demo.items import SpiderDemoItem


class MaoyanSpider(scrapy.Spider):
    # これはクローラーの起動名で、後でクローラーを起動する際に使用します
    name = "maoyan"
    # クローリング可能なドメインの選択リスト
    allowed_domains = ["maoyan.com"]
    # 目標クローリングURL
    start_urls = [
        "http://maoyan.com/board/7/", 
        "http://maoyan.com/board/4/",
    ]

    # ダウンロード済みのページを処理します
    def parse(self, response):
        
        dl = response.css(".board-wrapper dd")
        # 解析を通じて具体的なデータをコンテナに格納します
        for dd in dl:
            item = SpiderDemoItem()
            item["index"] = dd.css(".board-index::text").extract_first()
            item["title"] = dd.css(".name a::text").extract_first()
            item["star"] = dd.css(".star::text").extract_first()
            item["releasetime"] = dd.css(".releasetime::text").extract_first()
            score = dd.css('.integer::text').extract_first()
            if score is not None:
                item["score"] = score  + dd.css('.fraction::text').extract_first()
            else:
                item["score"] = 0

            # yieldを通じて結果を返します
            yield item

ここで、scrapyはさまざまなタイプの解析をサポートしており、Python の一般的な三大解析ライブラリを使用して解析できますが、フレームワークも独自の解析方法(Selector)を提供しています。

  • セレクタ
  • Xpath

ここでは詳細には述べませんが、後で時間があれば詳しく話しましょう。

同時に、setting.pyで設定を少し変更する必要があります(setting.pyには多くのデフォルト設定がありますが、ここでは変更部分のみを示します)。

# 自動生成されたUAがない場合は手動で定義する必要がありますが、毎回同じUAでクローリングすると検証操作が発生しやすいため、後でUAをランダム生成する方法も紹介します。
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'

# ロボットプロトコルの許可、ロボットプロトコルの具体的な内容は自分でインターネットで調べてください。
ROBOTSTXT_OBEY = False

これで、基本的なクローラーが完成しました。実行するにはscrapy crawl maoyan(最後の部分はあなたのクローラー名)を実行するだけです。

image

その後、2 つの重要なポイントがあります。一つはプロジェクトの永続化、もう一つはUser-Agentのランダム化です。

まず永続化を見てみましょう。ここでは簡単のため、クローラーのデータをjson形式でエクスポートする方法を示します。

ここでpipline.pyを変更する必要があります。なぜなら、以前のコンポーネントの紹介を見れば理解できると思います。

import json
import codecs


class SpiderDemoPipeline:
    def process_item(self, item, spider):
        return item


class JsonPipline(object):
    def __init__(self):
        print("ファイルを開いて書き込みの準備をします....")
        self.file = codecs.open("maoyan.json", "wb", encoding='utf-8')

    def process_item(self, item, spider):
        print("書き込みの準備をしています...")
        line = json.dumps(dict(item), ensure_ascii=False) + "\n"
        self.file.write(line)
        return item

    def close_spider(self, spider):
        print("書き込み完了、ファイルを閉じます")
        self.file.close

次に、setting.pyでカスタムpiplineを有効にします。

ITEM_PIPELINES = {
    #    'spider_demo.pipelines.SpiderDemoPipeline': 300,
    'spider_demo.pipelines.JsonPipline': 200
}

User-Agentのランダム化については、UA を追加する原理を説明します。

scrapyは最初にsetting.py内の UA 設定を読み込み、その後middlewareを通過します。カスタム操作を行わなければ、設定された UA がリクエストヘッダーに追加されます。したがって、UA をランダム化するには、実際にはウェブリクエストを発起する前にDownload Middlewareで処理を行うことができます。

ここでmiddleware.pyを変更し、サードパーティパッケージfake_useragentを導入しました。

from scrapy import signals
import random
from fake_useragent import UserAgent


class RandomUserAgentMiddleware(object):
    # User-Agentをランダムに変更します
    def __init__(self, crawler):
        super(RandomUserAgentMiddleware, self).__init__()
        self.ua = UserAgent()
        self.ua_type = crawler.settings.get("RANDOM_UA_TYPE", "random")

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)

    def process_request(self, request, spider):
        def get_ua():
            return getattr(self.ua, self.ua_type)

        request.headers.setdefault('User-Agent', get_ua())

同時に、setting.pyでも変更を行います。

DOWNLOADER_MIDDLEWARES = {
    'spider_demo.middlewares.SpiderDemoDownloaderMiddleware': 543,
     'spider_demo.middlewares.RandomUserAgentMiddleware': 400,
    'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,
}

# UAをランダムに選択します
# これは自分で設定したもので、fake-useragentに依存しています
RANDOM_UA_TYPE = 'random'

これで、簡単なクローラーアプリケーションが実現しました!

UA が変更されたのが見えます。

image

同時にmaoyan.jsonファイルが生成されました。

json ファイル

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。