質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.11%

scrapyで上手くjsonファイルに保存できない問題について

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,289

trafalbad

score 219

scrapyで食べログないのデータを取得しようとして以下のようにItemとspiderを作成し、

scrapy crawl tabelog -o retaurants.jl

をコマンド実行しました。一応、retaurants.jlファイルは作成されるのですが、抽出内容が記述されずに、ファイルのみ作成されます。

何か問題があるのでしょうか?ご教授お願いします。

Item(item.py)

import json
import scrapy


class Restaurant(scrapy.Item):
    """
        食べログのレストラン情報
    """
    name = scrapy.Field()   # spaiderのresponse.css()で取得したデータを保存するItemを作成
    address = scrapy.Field()
    latitude= scrapy.Field()
    logitude = scrapy.Field()
    station = scrapy.Field()
    score = scrapy.Field()

spider(spiders/tabelog.py)

from scrapy.spiders import CrawlSpider, Rule
# CrawlSpider:定期的なウェブサイトをクロールするために最も一般的に使用されるスパイダー.
# 一連のルールを定義してリンクをたどるための便利なメカニズムを提供.
# CrawlSpiderの例はhttp://scrapy-ja.readthedocs.io/ja/latest/topics/spiders.html
import re
from scrapy.linkextractors import LinkExtractor
from myproject.items import Restaurant

class TabelogSpider(CrawlSpider):
    name = "tabelog"  # スパイダーの名前(ドメイン名)と同じの名前を付ける
    allowed_domains = ["tabelog.com"]
    start_urls =('http://tabelog.com/tokyo/rstLst/lunch/?LstCosT=2&RdoCosTp=1',)
    # ↑クロールを開始するURLのリスト.ダウンロードされる最初のページはここにリストされたページになる

    rules = [  # トピックへのルールをたどり、レスポンスをcallback関数で処理する。
        # allowで正規表現にマッチしたURL「一覧ページ(P272)」の1~9ページまで抽出。。\dを\d+に変えると10ページ目以降も辿れる。
        Rule(LinkExtractor(allow=r'/\w+/rstLst/lunch/\d'), follow=True),

        # レストランの「詳細ページ(P272)」をたどり、parse_retaurant()でパース(処理)する]
        Rule(LinkExtractor(allow=r'/\w+/A\d+/A\d+/\d+/$'), callback='parse_restaurant'),]
        # リンクをたどるためのルールリスト。各Ruleは, サイトをクロールするための特定の動作を定義

    def parse_restaurant(self, response):
        """
        レストランの詳細ページをパースする
        """
        # Google Static Mapの画像のURLから緯度と軽度を取得
        latitude, longitude = response.css('img.js-map-lazyload::attr("data-original")').re(
            r'makers=.*?%7C([\d.]+),([\d.]+)')

        # キー(Itemで作成したscrapy.field())の値を指定して、ItemのclassのRestaurantオブジェクトを作成
        item = Resraurant(
        name=renponse.css('.display-name').xpath('string()').extract_first().strip(),
        adress=renponse.css('[rel="v:address"]').xpath('string()').extract_first().strip(),
        latitude=latitude,
        longitude=longitude,
        station=renponse.css('dt:contains("最寄り駅")+dd span::text').extract_first(),
        score=renponse.css('[property="v:average"]::text').extract_first(),)

        yield item
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

import scrapy


class Restaurant(scrapy.Item):
    name = scrapy.Field()
    address = scrapy.Field()
    latitude = scrapy.Field()
    longitude = scrapy.Field()
    station = scrapy.Field()
    score = scrapy.Field()
from scrapy.spiders import CrawlSpider, Rule
import re
from scrapy.linkextractors import LinkExtractor
from myproject.items import Restaurant


class TabelogSpider(CrawlSpider):
    name = "tabelog"
    allowed_domains = ["tabelog.com"]
    start_urls = (
        'http://tabelog.com/tokyo/rstLst/lunch/?LstCosT=2&RdoCosTp=1',)

    rules = [
        # 9ページ以上抽出してしまうので最後に'/'を追加
        Rule(LinkExtractor(allow=r'/\w+/rstLst/lunch/\d/'), follow=True),

        Rule(LinkExtractor(allow=r'/\w+/A\d+/A\d+/\d+/$'), callback='parse_restaurant'), ]

    def parse_restaurant(self, response):

        # 取得できていなかったですが単純にtypoでした(makers -> markers)
        latitude, longitude = response.css('img.js-map-lazyload::attr("data-original")').re(
            r'markers=.*?%7C([\d.]+),([\d.]+)')

        # addressが取得できていなかったので修正
        prefectures = response.css(
            'p.rstinfo-table__address span a::text').extract()
        street_number = response.css(
            'p.rstinfo-table__address span::text').extract()

        item = Restaurant(
            name=response.css(
                '.display-name').xpath('string()').extract_first().strip(),
            address=''.join(prefectures + street_number),
            latitude=latitude,
            longitude=longitude,
            station=response.css(
                'dt:contains("最寄り駅")+dd span::text').extract_first(),

            # scoreもNoneで返ってきたので修正
            score=response.css('span.rdheader-rating__score-val-dtl::text').extract_first(),
        )

        yield item


とりあえず修正してみました。
修正箇所と理由はコメントで書いてあります。
他にもtypoが沢山ありましたが、そちらで確認してください。

追記
settings.pyにFEED_EXPORT_ENCODING = 'utf-8'を書かないと日本語で抽出できませんでした。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/09 05:29

    ありがとうございます!教えて頂きたいのですが、scrapyでaddressの項目なのですが、必要と判断したのは何か参考になるサイトや資料等あったのでしょうか?判断材料になったものや理由がありましたら教えて下さい!

    キャンセル

  • 2018/04/09 07:18

    プログラムでなにか問題があったとき基本的にエラーログを見ないと修正箇所はわからないです。
    今回は怪しいところにprintデバッグを使って値が取得できているか確認。
    chromeのデベロッパーツールで検索してCSSの指定という泥臭いやり方で修正しました。
    私自身cssやxpath、デベロッパーツールについて薄い知識しかないので、もっとスマートなやり方があると思います。
    scrapyは以前、私も食べログで一度だけ使ったことがあるので分かるかなと思い回答に挑戦してみました。
    なので、知識は公式のチュートリアルを終えた程度のものです。

    キャンセル

  • 2018/04/10 22:56

    ありがとうございます。とても参考になりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.11%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる