geek開発日誌

超一流のプログラマーを目指してます!作成したポートフォリオを記録していく開発日誌です。

Scrapyでニュースを取得②

こんにちは。nakatatsuです。

前回に引き続きフレームワークScrapyを使用して複数のニュースサイトから情報を取得するスクレイピングツールを作成します。今回はgooニュースから情報を取得します。

仕様

完成形の仕様です。途中で変更があるかもしれません。

・複数のニュースサイトから情報を取得

・記事のタイトルと要約を取得

準備

Scrapyを使用するための準備についてはこのブログの過去記事「Scrapyでニュースを取得」を参照してください。

nakatatsu-com.hatenablog.com


フォルダ構成

news
├── news
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-36.pyc
│   │   ├── items.cpython-36.pyc
│   │   ├── pipelines.cpython-36.pyc
│   │   └── settings.cpython-36.pyc
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       ├── __init__.py
│       ├── __pycache__
│       │   ├── __init__.cpython-36.pyc
│       │   ├── goo.cpython-36.pyc
│       │   └── yahoo.cpython-36.pyc
│       ├── goo.py
│       └── yahoo.py
└── scrapy.cfg

フォルダ構成はこのようになっております。

ソースコード

Itemは前回から変更なしです。

item.py

import scrapy


class Headline(scrapy.Item):
    '''
    ニュースのヘッドラインを格納するためのItem
    '''

    title = scrapy.Field()
    summary = scrapy.Field()


Spiderを作成します。

(scraping) $ scrapy genspider goo news.goo.ne.jp

spidersディレクトリ内にgoo.pyというファイルが生成されます。これをベースに書き換えていきます。

goo.py

import scrapy
from news.items import Headline


class GooSpider(scrapy.Spider):
    name = 'goo' # Spiderの名前
    allowed_domains = ['news.goo.ne.jp'] # クロール対象とするドメインのリスト
    start_urls = ['http://news.goo.ne.jp/'] # クロールを開始するURLのリスト

    def parse(self, response):
        '''
        「トップ」>「注目」のトピックス一覧から個々のトピックスへのリンクを抜き出してたどる
        '''

        for url in response.css(
            '#topiarea_title > li > a::attr("href")').extract():
            yield scrapy.Request(response.urljoin(url), self.parse_topics)

    def parse_topics(self, response):
        '''
        トピックスページからタイトルと要約を抜き出す
        '''

        item = Headline()
        item['title'] = response.css(
            '.heading-title-topics::text').extract_first()
        item['summary'] = response.css(
            '.topics-text').xpath('string()').extract_first()
        yield item


また、Itemのtitleフィールドが正しく取得できているかを検証するためにItemPipelineを作成します。ItemPipelineはSpiderから抽出したItemに対して任意の処理を行うためのコンポーネントです。

pipelines.py

from scrapy.exceptions import DropItem


class ValidationPipeline(object):
    '''
    Itemを検証するPipeline
    '''

    def process_item(self, item, spider):
        if not item['title']: # titleフィールドが取得できていない場合は破棄
            raise DropItem('Missing title') # 破棄する理由を表すメッセージ
        return item

作成したItemPipelineはそのままでは使用できません。プロジェクトのsettings.pyに、以下の設定を追加する必要があります。

ITEM_PIPELINES = {
    'news.pipelines.ValidationPipeline': 300,
}

実際はsettings.pyにコメントとして記載されているので、コメントアウトするだけです。

結果

結果です。長いので省略してます。

{'summary': '\u3000'
            '大阪府吹田市の千里山交番で古瀬鈴之佑巡査(26)が刃物で刺され拳銃が奪われた事件で、吹田署捜査本部は17日、強盗殺人未遂容疑で、住所不定、職業不詳の飯森裕次郎容疑者(33)を逮捕した。飯森容疑者は拳銃を所持していた。大阪府箕面市で発見し確保した。\r\n'
            '\r\n',
 'title': '拳銃強奪、33歳男逮捕 1発使用か'}
・・・

トピックスページからタイトルと要約を取得することができました。

まとめ

・gooニュースサイトから情報を取得

・記事のタイトルと要約を取得

参考文献

参考文献です。