Scrapyチュートリアル

17187 ワード

Scrapyをインストールしたとしますが、インストールガイドを参照してください.
捕まえるぞtoscrape.comサイト.
このチュートリアルでは、次のタスクを実行します.
  • 新規Scrapyエンジニアリング
  • spiderサイト抽出データ
  • を作成
  • コマンド・ラインでフェッチするデータ
  • を導出する.
  • spider再帰爬行リンク
  • を変更する
  • spiderパラメータ
  • を使用
    プロジェクトの作成
    キャプチャする前に、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
    
            pipelines.py      # project pipelines file
    
            settings.py       # project settings file
    
            spiders/          # a directory where you'll later put your spiders
                __init__.py
    

    最初の爬虫類
    Spiderは、Webサイト情報を取得するクラスとして定義されています.scrapy.Spiderから継承し、初期要求を定義し、urlをページから抽出する方法、およびページコンテンツ抽出データを解析する方法を選択する必要があります.
    これは私たちの最初の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 = 'quotes-%s.html' % page
            with open(filename, 'wb') as f:
                f.write(response.body)
            self.log('Saved file %s' % filename)
    

    以上のようにspiderはscrapyから継承する.Spiderはいくつかの属性と方法を定義した.
  • name:spiderを識別します.プロジェクトで一意である必要があります.異なるspiderに同じ名前を設定することはできません.
  • start_requests():リクエストの反復(リクエストのリストを返すかジェネレータ関数を書くことができる)を返さなければなりません.spiderはここから登り始めます.サブシーケンス要求は、これらの初期要求から自動的に生成されます.
  • parse():各リクエストの完了時にメソッドを破棄します.responseパラメータは、ページコンテンツやセレクタなどの関数操作を含むTextResponseクラスの例である.
  • parse()関数は通常htmlを解析し、取得したデータをdictsとして抽出し、その後、新しいURLSを検索して新しい要求を作成する.
    クモをどう動かすか
    プロジェクトの最上位ディレクトリで実行: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)  (referer: None)
    2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200)  (referer: None)
    2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200)  (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)
    ...
    

    現在のディレクトリを確認します.2つの新しいファイルquotes-1が作成されたことに気づきます.htmlとquotes-2.htmlにはurlsの応答データが含まれています.
    内部メカニズムとは
    Scrapyはクモのstart_requestsメソッドを呼び出し、応答を受信するとすぐにResponseオブジェクトを初期化し、要求された戻り関数(この例では、時parse()関数)を呼び出してresponseオブジェクトをパラメータとする.
    start_requests関数の概要start_requests関数の代わりに、start_urlsのシードリストを定義することができる.デフォルトのstart_requests()関数インプリメンテーションでは、start_urlsを使用して初期要求が作成されます.
    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 = 'quotes-%s.html' % page
            with open(filename, 'wb') as f:
                f.write(response.body)
    

    urlsのリクエストのたびにparse()が呼び出されます.これはparse()がScrapyが明示的に戻り関数に値を与えていない場合のデフォルトの戻り関数であるためである.
    データの抽出
    最も良い学習はScrapyのセレクタを使う方法はScrapy shellを使うことです.scrapy shell 'http://quotes.toscrape.com/page/1/'
    ヒント
    単一引用符でアドレスをラップすることを忘れないでください.そうしないと、&文字などのパラメータが含まれています.
    Windowsで二重引用符を使う
    次のようになります.
    [ ... Scrapy log here ... ]
    2016-09-19 12:09:27 [scrapy.core.engine] DEBUG: Crawled (200)  (referer: None)
    [s] Available Scrapy objects:
    [s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
    [s]   crawler    
    [s]   item       {}
    [s]   request    
    [s]   response   <200 http://quotes.toscrape.com/page/1/>
    [s]   settings   
    [s]   spider     
    [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
    >>>
    

    shellではresponseオブジェクトのCSS関数を使用して要素を選択できます.
    >>> response.css('title')
    []
    
    response.css('title')の実行結果は、XML/HTML要素を含むSelectorListというlist-likeオブジェクトであり、選択とデータの抽出をさらに問い合わせることができます.
    titleのテキストをエクスポートするには、次のようにします.
    >>> response.css('title::text').extract()
    ['Quotes to Scrape']
    

    ここで注意しなければならない点は2つあります.1つは、::textをCSSクエリに追加しました.つまり、</code> text 。 <code>::text</code>, title 。</p> <pre><code>>>> response.css('title').extract() ['<title>Quotes to Scrape'] のみを選択したことを意味します.
    二、.extract()は、SelectorListのテキストリストを返す.最初の要素のテキストのみを取得します.
    >>> response.css('title::text').extract_first()
    'Quotes to Scrape'
    

    pythonのリスト書き方も使用できます.
    >>> response.css('title::text')[0].extract()
    'Quotes to Scrape'
    

    しかし、extract()およびextract_first()の方法を使用すると、一致する要素が見つからないときにNoneに戻り、IndexErrorを回避することができる.extract()メソッドとextract_first()メソッドに加えて、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セレクタを見つけるには、shellからview(response)を使用して応答インタフェースを参照します.Firebugなどのブラウザ開発ツールやプラグインを使用できます(ここではFirebugを使用してキャプチャし、FireFoxを使用してキャプチャするを参照してください).
    セレクタウィジェットもCSSセレクタを検索するのに良いツールで、要素を可視化することができ、多くのブラウザで作業することができます.
    XPATH:概要
    cssに加えて、ScrapyセレクタもXPath式をサポートします.
    >>> response.xpath('//title')
    []
    >>> response.xpath('//title/text()').extract_first()
    'Quotes to Scrape'
    

    XPATH式は強力で、Scrapyセレクタの基礎です.実際、CSSセレクタは内部でXpathに変換されます.shellでテキストセレクタのオブジェクトタイプを表示できます.
    CSSセレクタほど流行していないにもかかわらず、Xpath式はもっと強い.構造にナビゲートするだけでなく、コンテンツを検索することもできます.xpathを使用すると、次のように選択できます.Next Pageを含むテキスト接続を選択します.これにより、xpathはキャプチャに非常に適しており、CSSセレクタをどのように構築するかを知っていても、Xpathを学ぶことを奨励します.
    私たちはここでXPathにあまり触れません.XPathを読むことができます.Xpathを学ぶために、例を通してXPathチュートリアルを学ぶことと、XPathを使って考える方法をお勧めします.
    quotesとauthorsの抽出
    選択と抽出に関する知識を少し知っています.私たちのspiderを改善し、コードを書いてウェブサイトのページからquotesを抽出しましょう.
    http://quotes.toscrape.comの各quoteのHTML形式は次のようになります.
    “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.” by Albert Einstein (about)

    scrapy shellを開いて、私たちが望んでいるデータを抽出しようとします.
    $ scrapy shell 'http://quotes.toscrape.com'
    

    次の構文を使用して、一連のquote要素のセレクタを得ます.
    >>> response.css("div.quote")
    

    各セレクタは、サブ要素をクエリーできます.最初のセレクタを変数に割り当て、指定したquoteセレクタを直接実行できます.
    quote = response.css("div.quote")[0]
    

    次に、quoteからtitleauthor、およびtagsをエクスポートし、作成したばかりのquoteオブジェクトを使用します.最初の結果だけが必要だと知ったら、次のことができます.
    >>> title = quote.css("span.text::text").extract_first()
    >>> title
    '“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").extract_first()
    >>> author
    'Albert Einstein'
    

    ラベルが文字列リストであることを考慮すると、.extract()メソッドを使用して取得できます.
    >>> tags = quote.css("div.tags a.tag::text").extract()
    >>> tags
    ['change', 'deep-thoughts', 'thinking', 'world']
    

    各エクスポート方法を解決し、すべてのquotes要素を反復してPython辞書に保存できます.
    >>> for quote in response.css("div.quote"):
    ...     text = quote.css("span.text::text").extract_first()
    ...     author = quote.css("small.author::text").extract_first()
    ...     tags = quote.css("div.tags a.tag::text").extract()
    ...     print(dict(text=text, author=author, tags=tags))
    {'tags': ['change', 'deep-thoughts', 'thinking', 'world'], 'author': 'Albert Einstein', 'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'}
    {'tags': ['abilities', 'choices'], 'author': 'J.K. Rowling', 'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”'}
        ... a few more of these, omitted for brevity
    >>>
    

    spiderを使用してデータをエクスポートする
    spiderに戻りましょう.今でもデータはエクスポートされず、HTMLページをローカルファイルに保存するだけです.導出ロジックをspiderに統合した.
    1つのScrapyクモには、通常、複数のページでデータをキャプチャする辞書が含まれます.これにより、コールバック関数でyield Pythonキーワードを使用することができます.以下に示します.
    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').extract_first(),
                    'author': quote.css('span small::text').extract_first(),
                    'tags': quote.css('div.tags a.tag::text').extract(),
                }
    

    このクモを実行すると、エクスポートデータがログに出力されます.
    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.”"}
    

    取得したデータの保存
    最も簡単なキャプチャデータの保存はFeed exportsを使用し、次のコマンドラインを使用します.
    scrapy crawl quotes -o quotes.json
    

    これによりquotesが生成されますjsonファイルには、すべてのキャプチャイメージがjsonにシーケンス化されています.
    履歴上の理由で、Scrapyは上書きではなく追加を使用します.このコマンドを2回実行して2回目の削除前のファイルがなければ、破損したJSONファイルが得られます.
    Json Linesのような他のフォーマットも使用できます
    scrapy crawl quotes -o quotes.jl
    

    Json Linesフォーマットはstream-likeなので役に立ちます.新しい記録を簡単に追加することができます.彼は上のJSONファイルの問題を持っていません.あなたが2回実行したとき.また、各レコードは1行なので、メモリの問題を心配することなく、大きなファイルを処理できます.JQのようなツールはコマンドラインで処理できます.
    小さなプロジェクト(例のようにチュートリアル)では、これで十分です.しかし、より複雑なキャプチャ項目を処理したい場合は、[Itemパイプ]を作成することができます.プロジェクトが作成されると、tutorial/pipelines.pyにItemパイプファイルが構築されます.これにより、キャプチャしたアイテムを保存したいだけであれば、Itemパイプを実装する必要はありません.
    次の接続
    捕まえたいだけじゃなくhttp://quotes.toscrape.comサイトの中の2つのページではなく、すべてのサイトのページをキャプチャしたいと思っています.
    ページからデータをキャプチャする方法を知っています.次の接続を見てみましょう.
    まずページから目的の接続を抽出します.ページを表示すると、次のページに次のフラグが接続されています.
    
    

    shellから抽出してみます.
    >>> response.css('li.next a').extract_first()
    'Next →'
    

    これはanchor要素全体を得たが、href属性がほしい.そのため、ScrapuはCSSの拡張機能を提供し、以下のように属性の内容を選択することができます.
    >>> response.css('li.next a::attr(href)').extract_first()
    '/page/2/'
    

    次のページを追跡してデータをエクスポートできるようにspiderが変更されました.
    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').extract_first(),
                    'author': quote.css('span small::text').extract_first(),
                    'tags': quote.css('div.tags a.tag::text').extract(),
                }
    
            next_page = response.css('li.next a::attr(href)').extract_first()
            if next_page is not None:
                next_page = response.urljoin(next_page)
                yield scrapy.Request(next_page, callback=self.parse)
    

    次に、データをエクスポートした後、parse()関数は次のページを検索し、urljoinを使用して絶対パスURLを構築し、次のページへの新しいリクエストを生成し、次のページのリクエストをコールバックとして登録してクモがすべてのページに登ることができるようにします.
    これはScrapyがページを追跡するメカニズムです.コールバックで要求オブジェクトを生成すると、要求の送信とコールバック関数の登録が要求の終了時に実行されます.
    これらを使用すると、複雑な爬虫類システムを構築したり、リンクルールをカスタマイズしたり、アクセスページに基づいてさまざまなデータをエクスポートしたりすることができます.
    私たちの例では、ブログ、フォーラム、または他のナビゲーションサイトを簡単にアクセスできるように、すべてのリンクを次のページに追跡する一連のループを作成します.
    その他の例とモード
    これは別のクモがコールバックと追跡接続を説明するために使用され、今回は著者の情報をキャプチャします.
    import scrapy
    
    
    class AuthorSpider(scrapy.Spider):
        name = 'author'
    
        start_urls = ['http://quotes.toscrape.com/']
    
        def parse(self, response):
            # follow links to author pages
            for href in response.css('.author+a::attr(href)').extract():
                yield scrapy.Request(response.urljoin(href),
                                     callback=self.parse_author)
    
            # follow pagination links
            next_page = response.css('li.next a::attr(href)').extract_first()
            if next_page is not None:
                next_page = response.urljoin(next_page)
                yield scrapy.Request(next_page, callback=self.parse)
    
        def parse_author(self, response):
            def extract_with_css(query):
                return response.css(query).extract_first().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コールバック関数を使用してナビゲーション接続を追跡します.parse_authorコールバック関数は、CSSクエリからPython dictを抽出してクリーンアップし、作成者データを使用して生成するヘルプメソッドを定義します.
    もう一つのクモに関する興味深いことは、同じ著者から多くの名言が出ても、同じ著者のページに何度もアクセスする心配はありません.デフォルトでは、Scrapyは重複したアクセス済みリクエストアドレスをフィルタリングし、プログラムがサーバをクリックしすぎる問題を回避します.これはDUPEFILTERでCLASS構成.
    Scrapyがページとコールバックを追跡するメカニズムを理解してほしい.
    このプログラムは追跡リンクメカニズムを利用して実現され、CrawlSpiderクラスを表示します.それは共通のクモで小さなルールエンジンを実現し、それ以上に自分の爬虫類を書くことができます.
    https://doc.scrapy.org/en/latest/intro/tutorial.html