Advent Calendar 2017 クローラー/Webスクレイピング の2日目が空いておりましたので、駆け込みで参加させていただきました!
目的
直近のニュースの概要をスクレイピングし1つのファイルにまとめる
動作環境
Ubuntu16.04でプログラムを作成しております。
NAME="Ubuntu"
VERSION="16.04 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
UBUNTU_CODENAME=xenial
Install方法
今回は pip
でインストールしました。
pip install Scrapy
Project作成
今回はニュースを収集するので、「news」という命名でプロジェクトを作成します。
任意のフォルダで以下のコマンドを入力し、プロジェクトを作成します。
scrapy startproject news
そうすると news
フォルダが作成されますので、
cd news
と入力し、プロジェクトフォルダ内に移動します。
以下の作業はすべてプロジェクトフォルダ内で実施します。
Project構造
作成したプロジェクトフォルダは下記のような構造になっています。
news/ ← 現時点ではココがカレントフォルダ
scrapy.cfg
news/
__init__.py
items.py
pipelines.py
settings.py
middlewares.py
spiders/
__init__.py
クロール設定の変更
news/settings.py/
というファイルを編集します。
デフォルトだとダウンロード間隔が0になっているため、クロール先に大きな負荷がかかります。
そのためクロール時に5秒間隔を空けるように以下のように設定を変更します。
DOWNLOAD_DELAY = 5
itemの設定
itemはスクレイピングしたデータを格納するオブジェクトです。
今回はプログラム実行時にどのようなデータが格納されているかを確認するために設定しています。
news/items.py/
というファイルを編集します。
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class NewsItem(scrapy.Item):
title = scrapy.Field()
category = scrapy.Field()
url = scrapy.Field()
summary = scrapy.Field()
Source
news/spider/
配下にスクレイピングのソースファイルを配置します。
今回は scraping.py
というファイルを作成しました。
ソースは以下です。
# -*- coding: utf-8 -*-
import scrapy
# itemを使用するためにはImportが必要
from news.items import NewsItem
class YnewsSpider(scrapy.Spider):
# Spiderの名前です。プログラム実行時にここで設定した名前を使用します。
name = "ynews"
# クローリングの始点URLです。ここからクローリングを開始します。
start_urls = ['https://news.yahoo.co.jp/list']
# スクレイピング処理
def parse(self, response):
# 欲しい情報が内包されているニュースのリスト表示部分を取得します
for selectElements in response.css("div.listArea ul.list li"):
# 設定したアイテムに情報を格納したいので、インスタンスを生成します
item = NewsItem()
# 欲しい要素を取得し、対応するフィールドに格納します
item['title'] = selectElements.css(".ttl::text").extract_first()
item['category'] = selectElements.css(".cate::text").extract_first()
item['url'] = selectElements.css("a::attr('href')").extract_first()
# 別ページに遷移して取得するデータはrequestとして受け取って、itemに格納し遷移後に再度スクレイピングします
request = scrapy.Request(item['url'], callback=self.getArticle)
request.meta['item'] = item
yield request
# ニュース概要スクレイピング処理
def getArticle(self, response):
item = response.meta['item']
item['summary'] = response.css("div.headlineTxt p.hbody::text").extract_first()
# 値を格納したitemを返します
yield item
実行
以下のコマンドでクローリング・スクレイピングを実行します。
scrapy crawl ynews -o news.json
実行完了後、コマンド実行ディレクトリと同フォルダに news.json
が生成されます。
最後に
上記の方法はPython、クローリング、スクレイピングの初心者が、試行錯誤しながら行った方法です。
もっともっと良い方法があると思いますので、おかしい点や改善点などドンドンご指摘いただければと思います!