Scrapyで簡単webスクレイピング

webスクレイピングを可能にするframeworkであるScrapyの実行方法を分かりやすく記載いたしました。
参考になれば幸いです。

参考：
Python - Scrapyを使ってクローラーを作る
https://qiita.com/naka-j/items/4b2136b7b5a4e2432da8

所要時間15分
内容
1.Scrapyのインストールとプロジェクト作成
2.Spiderについて
3.実際にwebページ情報を取得してみよう！

#1.Scrapyのインストールとプロジェクト作成

ターミナル上で下記のpipを実行しscrapyをインストール

```python
pip install scrapy
```
その後、scrapyプロジェクトを作成したいディレクトリに移動し下記を実行しましょう

```python
scrapy startproject sake
```

このあと日本酒関係のwebサイトをスクレイピング致しますのでプロジェクトの名前を"sake"に致しました
そうすると現在のディレクトリ以下に下記のフォルダが構成されます。

![Screen Shot 2020-04-09 at 11.52.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172677/3bb83b84-7a27-ab60-3dcd-a27b40a24a1d.png)


#2.Spiderについて
上記のファイルだけではまでwebのスクレイピングは出来ませんので下記コマンドを入力し、
spidersディレクトリ内にファイルを作成していきます。


```python
#scrapy genspider <ファイル名> <スクレイピングしたいweb URL>
scrapy genspider scrapy_sake https://www.saketime.jp/ranking/
```

そうするとspidersディレクトリ内に"scrapy_sake.py"というファイルが出来ていることが確認できると思います。
![Screen Shot 2020-04-09 at 11.57.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172677/c70f4f21-07f9-6623-5574-a13bf1f0c536.png)
作成されたファイルの中身は下記です。

```python:sake/sake/spiders/scrapy_sake.py
# -*- coding: utf-8 -*-
import scrapy


class ScrapySakeSpider(scrapy.Spider):
    name = 'scrapy_sake'
    allowed_domains = ['https://www.saketime.jp/ranking/']
    start_urls = ['http://https://www.saketime.jp/ranking/']

    def parse(self, response):
        pass
```
後ほど詳しく説明しますがこの"def parse"部分を主にコーディングしていくことになります。
コーディングしていく前に一度正確にweb情報を取得できているかを確認しましょう。
"def parse"部分にprint文を追記して取得情報を見てみます。

```python:sake/sake/spiders/scrapy_sake.py
# -*- coding: utf-8 -*-
import scrapy


class ScrapySakeSpider(scrapy.Spider):
    name = 'scrapy_sake'
    allowed_domains = ['https://www.saketime.jp/ranking/']
    start_urls = ['http://https://www.saketime.jp/ranking/']

    def parse(self, response):
        #passを削除しprint文を追記
        print(response)
```

そして下記コマンドを実行するとかなり多くのアウトプットが帰ってきますがその中でしっかりとhtmlが取得できていることを確認できます。

```:実行コマンド
#scrapy crawl <ファイル名>
scrapy crawl scrapy_sake
```

```html:アウトプット

               <li class="brand_review clearfix">
                <div>
                  <p>
                    磯自慢　特別本醸造生酒原酒

本日のお酒はこちら、磯自慢の特別本醸造の生原酒！
米は...                    <br>
                    <span class="brand_review_user">
                      by
                      <span>すーさん</span>
                      <span>
                        <span class="review-star">★</span>
                        <span>4.5</span>
                      </span>
                      <span class="reviewtime">
                        <span>2020年3月23日</span>
                      </span>
                    </span>

                  </p>
                </div>
              </li>
                                        </ul>
          </a>
                  </div>
:
:
:
'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2020, 4, 9, 3, 23, 24, 461847)}
2020-04-09 12:23:26 [scrapy.core.engine] INFO: Spider closed (finished)
```
それではこの次にここから必要な情報だけを抜き出して見ましょう！

#3.実際にwebページ情報を取得してみよう！
基本的にscrapyで実装するファイルは下記の2つだけです
- items.py
- spiders > scrapy_sake.py

まずitem.pyから編集していきましょう。
まず開くと元々は下記のファイルのようになってます。

```python:sake/items.py
# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy

class SakeItem(scrapy.Item):
    pass

```
このclass部分にscrapyで取得したい情報を任意で登録します。

```python:sake/items.py
# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class SakeItem(scrapy.Item):
    #取得したい情報名称(任意) = scrapy.Field()
    prefecture_maker = scrapy.Field()
    prefecture = scrapy.Field()
    maker = scrapy.Field()
    brand = scrapy.Field()
    pass

```

以上で、items.pyの記述は終了です。
次にscrapy_sake.pyのコーディングに移ります。

完成形が下記となります。
上記2章でみたものと比べdef parse()内がリッチになっていると思います。

```python:sake/sake/spiders/scrapy_sake.py
# -*- coding: utf-8 -*-
import scrapy
#items.pyをimportすることを忘れないようにしましょう
from sake.items import SakeItem

class ScrapySakeSpider(scrapy.Spider):
    name = 'scrapy_sake'
    #allowed_domains = ['ja.wikipedia.org']
    start_urls = ['https://www.saketime.jp/ranking/']
    
    def parse(self, response):
        items = []
        #htmlタグのli.clearfixという場所に日本酒情報が格納されていました。
        sakes = response.css("li.clearfix")

        #ページ内にある複数あるli.clearfixの1つずつをみていく
        for sake in sakes:
            #item.pyで定義したSakeItemオブジェクトを宣言 
            item = SakeItem()
            item["prefecture_maker"] = sake.css("div.col-center p.brand_info::text").extract_first()

            #<div class="headline clearfix">のような記述の場合,headline.clearfixとして間に.をつけること
            item["brand"] = sake.css("div.headline.clearfix h2 a span::text").extract_first()

            #取得したデータのクレンジング
            if (item["prefecture_maker"] is not None) or (item["brand"] is not None):
                #¥nとスペースの削除
                item["prefecture_maker"] = item["prefecture_maker"].replace(' ','').replace('\n','')
                #prefectureとmakerの分離
                item["prefecture"] = item["prefecture_maker"].split('|')[0]
                item["maker"] = item["prefecture_maker"].split('|')[1]
                items.append(item) 
        print(items)

    #ページ切り替えを再起的処理で反映
        #aタグのrel="next"の要素をリンク形式で取得する
        next_page = response.css('a[rel="next"]::attr(href)').extract_first()
        if next_page is not None:
            # URLが相対パスだった場合に絶対パスに変換する
            next_page = response.urljoin(next_page)
            #yieldで1回ずつRequestを返す、リクエスト後のページでsakesが登録され、上のfor文が再度実行される
            yield scrapy.Request(next_page, callback=self.parse)
```

これらを実行すると下記となります。

```html
:
:
:
2020-04-10 16:52:58 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (301) to <GET https://www.saketime.jp/ranking/page:110/> from <GET https://www.saketime.jp/ranking/page:110>
2020-04-10 16:52:59 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.saketime.jp/ranking/page:110/> (referer: https://www.saketime.jp/ranking/page:109/)
[{'brand': 'おろちの舌鼓',
 'maker': '木次酒造',
 'prefecture': '島根',
 'prefecture_maker': '島根|木次酒造'}, {'brand': '禱と稔',
 'maker': '福光屋',
 'prefecture': '石川',
 'prefecture_maker': '石川|福光屋'}, {'brand': '金沢美人',
 'maker': '福光屋',
 'prefecture': '石川',
 'prefecture_maker': '石川|福光屋'}, {'brand': '甚九郎',
 'maker': '北雪酒造',
 'prefecture': '新潟',
 'prefecture_maker': '新潟|北雪酒造'}, {'brand': '兼六桜',
 'maker': '中村酒造',
 'prefecture': '石川',
 'prefecture_maker': '石川|中村酒造'}, {'brand': '誕生',
 'maker': '東北銘醸',
 'prefecture': '山形',
 'prefecture_maker': '山形|東北銘醸'}, {'brand': 'SUMMERGODDESS',
 'maker': '真名鶴酒造',
 'prefecture': '福井',
:
:
:
 'scheduler/dequeued/memory': 221,
 'scheduler/enqueued': 221,
 'scheduler/enqueued/memory': 221,
 'start_time': datetime.datetime(2020, 4, 10, 7, 51, 13, 756973)}
2020-04-10 16:53:00 [scrapy.core.engine] INFO: Spider closed (finished)
```
JSON形式で110ページの日本酒情報が20秒程で入手できました。
便利ですね。

自身の興味があるサイト等をスクレイピングしてみて情報を取得してみましょう。

##メモ
基本情報ですがスクレイピングしたいサイトのhtml情報の見方としてはchromeブラウザかつmacOSの場合、cmd + option + iで表示することが可能です。
さらにcmd + shift + c を押すことでサイト内の要素をクリックすることでhtmlコード内のどこを表すかを見ることができます。
![Screen Shot 2020-04-10 at 17.09.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172677/14c3fc50-512b-3214-1d78-a630895420c0.png)