Scrapyで辞書をスクレイピングしてみた

はじめに

趣味でやってる自然言語処理で、勉強したこととか、進捗があったところとか、メモに残しておくためにブログ始めてみた。内容はしょぼいし説明も足りないと思うけど、公開しておいてひょっとして誰かの役に立ったらいいな。

スクレイピングの目的

機械学習の学習用データです。weblioはことわざだけでなくて、「成句」として、故事成句、ことわざ、慣用句などなどが揃っているので素晴らしいです。三省堂さん、ありがとうございます。

http://www.weblio.jp/robots.txt はこうなってます。和英・英和辞書はダメみたい。

User-agent: *
Disallow: /ejje/content/
Disallow: /feedback/
Disallow: /postal/content/
Disallow: /shuwa/content/
Disallow: /thesaurus/content/
Disallow: /cjjc/content/

Scrapyの底本

Pythonエンジニアファーストブック見ながらやったらだいたいできた。スクレイピング専門の本とかもあるのに、たった30ページくらいで必要なこと9割くらいカバーしててすごい。

www.amazon.co.jp

仮想環境とインストール

趣味で自然言語処理してるだけなので、以前は仮想環境いらないっておもってた。でも、pythonのversion上げた時に今まで作ってたプログラムが動かなくなってから、使うようにしている。特に、自分みたいに何が起きているか分析できない弱者は、バグの可能性を減らせるので安心。scrpって仮想環境に、beautiful soupとかscrapyとか入れている。

最初から仮想環境作る場合のコマンドはこれ。

$ python3.6 -m venv scrp
$ scrp/bin/activate
(scrp) pip install scrape

SHELLの使い方

shellでうまく取り出せるか試してみる。

http://www.weblio.jp/phrase/ことわざ_1 のページから、子カテゴリーのURLを取得する場合はこんな感じ。

$ scrape shell http://www.weblio.jp/phrase/ことわざ_1
>>> response.css('div.subCatChildNxt a::attr("href")').extract()

プロジェクトの作成

(scrp) $ scrappy startproject weblio_scraper 

プロジェクトが作成されたら、settings.pyを編集する。インターバル秒を設定して、キャッシュを有効にする。この後、spiderがうまく動いてくれなくて何十回と同じところをスクレイピングしていたけれど、キャッシュがあればすぐ処理終わって(うまくいかなかったという)結果がすぐわかる。

  • DOWNLOAD_DELAY = 3:

  • HTTPCACHE_ENABLED = True

Spiderを作る

まず、Spiderを作成。

$ cd weblio_scraper
$ scrappy genspider

スクレイピングしたいページがtree状のリンクを辿らなければならないので、3日くらいあれやこれや戦ってた。 http://www.weblio.jp/phrase/ことわざ_1 のページはこんな構造。

ことわざ top page
├── 藁で束ねても男は男──ことわざの意味
├── 色男金と力は無かりけり──ことわざの意味
├── 男子家を出れば七人の敵あり──ことわざの意味
├── 据え膳食わぬは男の恥──ことわざの意味
├── 男は閾を跨げば七人の敵あり──ことわざの意味
├── 「男」のことわざ一覧
│     ├── 藁で束ねても男は男──ことわざの意味
│     ├── 色男金と力は無かりけり──ことわざの意味
│     ├── 男子家を出れば七人の敵あり──ことわざの意味
│     ├── 据え膳食わぬは男の恥──ことわざの意味
│     ├── 男は閾を跨げば七人の敵あり──ことわざの意味
│     ├── 男子の一言金鉄の如し──ことわざの意味
│     ├── ...
│     └── 英雄色を好む──ことわざの意味
├── 七人の子は生すとも女に心許すな──ことわざの意味
├── 大蛇を見るとも女を見るな──ことわざの意味
├── 女の一念岩をも通す──ことわざの意味
├── 女の足駄にて造れる笛には秋の鹿寄る──ことわざの意味
├── 女氏無くして玉の輿に乗る──ことわざの意味
├── 「女」のことわざ一覧
│     ├── 七人の子は生すとも女に心 許すな──ことわざの意味
│     ├── 大蛇を見るとも女を見るな──ことわざの意味
│     ├── ...

うまく、親カテゴリ→子カテゴリ→ことわざの意味、とSpiderが移動してくれなくて苦労した。

結局、shellでchild categoryのURLを取得して、start_urlsに入れることで解決。top pageとchild categoryで重複してスクレイピングしちゃうかと思ったけど、同じURLはスクレイピングしないようにできているみたい。

# -*- coding: utf-8 -*-
import scrapy

class WeblioSpider(scrapy.Spider):
    name = 'weblio_spider'
    allowed_domains = ['www.weblio.jp']

    # 故事成語、ことわざ、慣用句のどれかのトップページのURLと、
    # Child categoryのURL合わせてstart_urlsにする。とりあえず3つ載せてます。
    start_urls = ['http://www.weblio.jp/phrase/%E6%95%85%E4%BA%8B%E6%88%90%E8%AA%9E_1',
        'http://www.weblio.jp/phrase/%E9%B3%A5_1',
        'http://www.weblio.jp/phrase/%E7%83%8F%28%E3%81%8B%E3%82%89%E3%81%99%29_1'
        ]

    def parse(self, response):
        metas = response.css('meta').extract()
        yield {
            'description': metas[1]
            }

        urls = response.css('div.subCatWordsB a::attr("href")').extract()
        counts = 0
        next_url = urls[ counts ]
        while next_url:    # 各フレーズのデータをscrapingする。
            yield scrapy.Request(next_url)
            counts += 1
            next_url = urls[ counts ]

            metas = response.css('meta').extract()
            yield {
                'description': metas[1]
                }

Spiderの実行

準備ができたらSpiderを実行。

$ scrappy crawl weblio_spider -o kotozaka.json