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

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

新規登録して質問してみよう
ただいま回答率
85.50%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Scrapy

Scrapyは、Pythonで開発されたオープンソースソフトウェアです。スクレイピングという、Webサービスから必要な情報を取り出したり自動操作をしたりする技術を使うものです。

Q&A

0回答

757閲覧

Python3 Scrapyでレビューサイトからレビューを取得したい。

Malo

総合スコア19

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Scrapy

Scrapyは、Pythonで開発されたオープンソースソフトウェアです。スクレイピングという、Webサービスから必要な情報を取り出したり自動操作をしたりする技術を使うものです。

0グッド

0クリップ

投稿2020/07/06 07:40

現在、Python3を利用しScrapyで「もぐナビ (https://mognavi.jp/okashi/product)」というサイトからお菓子のレビューを取得し、それをlocalのサーバのMySQLに保存するという作業を行っています。
しかし、この中のレビューで一部レビュー文全体を取得できないものがあり、その原因が分からず困っています。解決方法がありましたら、お教え頂けると幸いです。

以下がソースコードです。まだ作成途中なので、Itemで使っていない変数などもあります。

[items.py]

Python3

1# -*- coding: utf-8 -*- 2 3from scrapy import Item, Field 4 5# 対象の食品に関する情報 6class Food(Item): 7 food_category = Field() 8 food_brand = Field() 9 food_name = Field() 10 maker_name = Field() 11 pass 12 13# レビュー及びレビュアーに関する情報 14class Review(Item): 15 food_name = Field() 16 review_title = Field() 17 review_text = Field() 18 user_id = Field() 19 user_name = Field() 20 date = Field() 21 pass 22 23# FoodとReviewを包括 24class Info(Item): 25 food = Field() 26 review = Field()

[spider.py]

Python3

1# -*- coding: utf-8 -*- 2import scrapy 3from test_scrapy.items import Food, Review, Info 4 5class ScrapyBlogSpiderSpider(scrapy.Spider): 6 name = 'scrapy_blog_spider' 7 allowed_domains = ['mognavi.jp'] 8 start_urls = ['https://mognavi.jp/okashi/product/'] 9 10 # トップページ用parse。 商品ラインナップを漁る。 11 def parse(self, response): 12 for product in response.css('#searchResList > ul > li'): 13 product_link = response.urljoin(product.css('.txt h3 > a::attr(href)').extract_first()) 14 yield scrapy.Request(product_link, callback=self.parse_food) 15 16 # 次ページの情報を取得 17 links = response.css('#mainCol .cnt .nam a') 18 for l in links: 19 if l.css('a::text').extract_first()=='次の20件を見る': 20 next_link = response.urljoin(l.css('a::attr(href)').extract_first()) 21 22 # 次ページがあれば遷移 23 if next_link: 24 yield scrapy.Request(next_link, callback=self.parse) 25 26 27 # 食品情報用parse。 食品情報を漁る。 28 def parse_food(self, response): 29 Food_info = Food() 30 31 # 食品に関する情報を取得 32 info = response.css('.dataTable') 33 key = info.css('tr > th::text').extract() 34 if '内容量・参考価格' in key: 35 key.remove('内容量・参考価格') 36 value = info.css('tr > td > a::text').extract() 37 38 for i, k in enumerate(key): 39 if k=='カテゴリー': 40 Food_info['food_category'] = value[i] 41 elif k=='メーカー': 42 Food_info['maker_name'] = value[i] 43 elif k=='ブランド': 44 Food_info['food_brand'] = value[i] 45 Food_info['food_name'] = response.css('.system-h2-container .fn span::text').extract_first().replace(Food_info['maker_name'], '').strip() 46 47 # 口コミのリンクへ移動 48 kuchikomi_link = response.urljoin(response.css('.productPage-tab #tabsBtn li:nth-child(2) a::attr(href)').extract_first()) 49 yield scrapy.Request(kuchikomi_link, callback=self.parse_review, meta={'Food_info': Food_info}) 50 51 52 # レビュー情報用parse。 53 def parse_review(self, response): 54 Food_info = response.meta['Food_info'] 55 56 # レビュー情報を取得 57 for review in response.css('#pKutikomi .kutikomi'): 58 # レビュー1件の情報を格納 59 Review_info = Review( 60 review_title=''.join([t.strip() for t in review.css('.clearfix .txt .in .title a::text').extract()]), 61 review_text=' '.join([t.strip() for t in review.css('.clearfix .txt .in .infukidashi p::text').extract()]), 62 date=review.css('.clearfix .txt .in .title p::text').extract_first().strip() 63 ) 64 # レコードを出力 65 yield Info( 66 food = Food_info, 67 review = Review_info 68 ) 69 70 # 次のページへのリンクを取得し、あれば遷移して繰り返す 71 links = response.css('#wrapperNew #mainCol .cntNam a') 72 next_link = '' 73 for l in links: 74 if l.css('a::text').extract_first() == '次の20件を見る': 75 next_link = response.urljoin(l.css('a::attr(href)').extract_first()) 76 if next_link: 77 yield scrapy.Request(next_link, callback=self.parse_review, meta={'Food_info': Food_info})

[pipelines.py]

Python3

1# -*- coding: utf-8 -*- 2 3import mysql.connector as connector 4from datetime import datetime 5 6class TestScrapyPipeline: 7 _db = None 8 9 @classmethod 10 def get_database(cls): 11 # DBへの接続 12 cls._db = connector.connect(host='localhost', 13 user='user', 14 password='password', 15 database='database') 16 # DBの自動再接続設定 17 cls._db.ping(reconnect=True) 18 19 return cls._db 20 21 22 ''' 23 Pipelineにデータが渡される時に実行される 24 itemにSpiderから渡されたitemがセットされる 25 ''' 26 def process_item(self, item, spider): 27 self.save_post(item) 28 return item 29 30 31 ''' 32 itemをDBに保存する 33 ''' 34 def save_post(self, item): 35 Food_info = item['food'] 36 Review_info = item['review'] 37 38 db = self.get_database() 39 cursor = db.cursor() 40 41 ### 食品情報に関して ### 42 if not self.find_post_food(Food_info['food_name']): # 既に同じレコードがある場合はスキップ 43 cursor.execute( 44 'INSERT INTO Food (food_name, food_brand, food_category) VALUES (%s, %s, %s)', ( 45 Food_info['food_name'], 46 Food_info['food_brand'] if 'food_brand' in Food_info else '', 47 Food_info['food_category'] 48 ) 49 ) 50 51 ### レビューに関して ### 52 if self.find_post_review(Review_info['review_text']): #既に同じレコードがある場合はスキップ 53 return 54 55 # Foodテーブルのidを引っ張ってくる 56 cursor.execute( 57 'SELECT food_id FROM Food WHERE food_name=%s', (Food_info['food_name'], ) 58 ) 59 food_id = cursor.fetchone()[0] 60 61 # Reviewテーブルにレコードを追加 62 cursor.execute( 63 'INSERT INTO Review (food_id, review_title, review_text, date) VALUES (%s, %s, %s, %s)', ( 64 food_id, 65 Review_info['review_title'], 66 Review_info['review_text'] 67 ) 68 ) 69 70 db.commit() 71 72 73 ''' 74 Foodテーブルで同じレコードがあるかどうかを確認する 75 ''' 76 def find_post_food(self, info): 77 db = self.get_database() 78 cursor = db.cursor() 79 cursor.execute( 80 "SELECT * FROM Food WHERE food_name=%s", (info, ) 81 ) 82 83 return cursor.fetchone() 84 85 ''' 86 Reviewテーブルで同じレコードがあるかどうかを確認する 87 ''' 88 def find_post_review(self, info): 89 db = self.get_database() 90 cursor = db.cursor() 91 cursor.execute( 92 "SELECT * FROM Review WHERE review_text=%s", (info, ) 93 ) 94 95 return cursor.fetchone()

追記する必要のある情報がありましたら、ご指摘頂けると幸いです。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問