2017-08-31 19 views
0

私のスパイダーにthis pipelineを実装しようとしました。 必要な依存関係をインストールした後、私はスパイダーをエラーなく実行できますが、なんらかの理由でデータベースに書き込まれません。パイプラインはMySQLに書き込まれませんが、エラーもありません

データベースに接続する際に問題が発生することは間違いありません。私が間違ったパスワードを与えると、私はまだ何の誤りもありません。

スパイダーがすべてのデータをスクラップしたとき、統計情報のダンプを開始するまでに数分かかります。

2017-08-31 13:17:12 [scrapy] INFO: Closing spider (finished) 
2017-08-31 13:17:12 [scrapy] INFO: Stored csv feed (27 items) in: test.csv 
2017-08-31 13:24:46 [scrapy] INFO: Dumping Scrapy stats: 

パイプライン:

import MySQLdb.cursors 
from twisted.enterprise import adbapi 

from scrapy.xlib.pydispatch import dispatcher 
from scrapy import signals 
from scrapy.utils.project import get_project_settings 
from scrapy import log 

SETTINGS = {} 
SETTINGS['DB_HOST'] = 'mysql.domain.com' 
SETTINGS['DB_USER'] = 'username' 
SETTINGS['DB_PASSWD'] = 'password' 
SETTINGS['DB_PORT'] = 3306 
SETTINGS['DB_DB'] = 'database_name' 

class MySQLPipeline(object): 

    @classmethod 
    def from_crawler(cls, crawler): 
     return cls(crawler.stats) 

    def __init__(self, stats): 
     print "init" 
     #Instantiate DB 
     self.dbpool = adbapi.ConnectionPool ('MySQLdb', 
      host=SETTINGS['DB_HOST'], 
      user=SETTINGS['DB_USER'], 
      passwd=SETTINGS['DB_PASSWD'], 
      port=SETTINGS['DB_PORT'], 
      db=SETTINGS['DB_DB'], 
      charset='utf8', 
      use_unicode = True, 
      cursorclass=MySQLdb.cursors.DictCursor 
     ) 
     self.stats = stats 
     dispatcher.connect(self.spider_closed, signals.spider_closed) 

    def spider_closed(self, spider): 
     print "close" 
     """ Cleanup function, called after crawing has finished to close open 
      objects. 
      Close ConnectionPool. """ 
     self.dbpool.close() 

    def process_item(self, item, spider): 
     print "process" 
     query = self.dbpool.runInteraction(self._insert_record, item) 
     query.addErrback(self._handle_error) 
     return item 

    def _insert_record(self, tx, item): 
     print "insert" 
     result = tx.execute(
     " INSERT INTO matches(type,home,away,home_score,away_score) VALUES (soccer,"+item["home"]+","+item["away"]+","+item["score"].explode("-")[0]+","+item["score"].explode("-")[1]+")" 
     ) 
     if result > 0: 
      self.stats.inc_value('database/items_added') 

    def _handle_error(self, e): 
     print "error" 
     log.err(e) 

スパイダー:

import scrapy 
import dateparser 
from crawling.items import KNVBItem 

class KNVBspider(scrapy.Spider): 
    name = "knvb" 
    start_urls = [ 
     'http://www.knvb.nl/competities/eredivisie/uitslagen', 
    ] 
    custom_settings = { 
     'ITEM_PIPELINES': { 
      'crawling.pipelines.MySQLPipeline': 301, 
     } 
    } 
    def parse(self, response): 
     # www.knvb.nl/competities/eredivisie/uitslagen 
     for row in response.xpath('//div[@class="table"]'): 
      for div in row.xpath('./div[@class="row"]'): 
       match = KNVBItem() 
       match['home'] = div.xpath('./div[@class="value home"]/div[@class="team"]/text()').extract_first() 
       match['away'] = div.xpath('./div[@class="value away"]/div[@class="team"]/text()').extract_first() 
       match['score'] = div.xpath('./div[@class="value center"]/text()').extract_first() 
       match['date'] = dateparser.parse(div.xpath('./preceding-sibling::div[@class="header"]/span/span/text()').extract_first(), languages=['nl']).strftime("%d-%m-%Y") 
       yield match 

私はそれが同様に歓迎されるだろう達成しようとしているものを行うことが可能な優れたパイプラインが存在する場合。ありがとう!

アップデート:私は最終的に働いて、この関数になった(したがって、私の問題を解決しました)受け入れ答えにあるリンクを使用して、 :

def process_item(self, item, spider): 
    print "process" 
    query = self.dbpool.runInteraction(self._insert_record, item) 
    query.addErrback(self._handle_error) 
    query.addBoth(lambda _: item) 
    return query 
+0

あなたのインデントが間違っているようです。 '_insert_error'と' _handle_error'はパイプラインの一部ではありません。あなたのパイプラインの 'process_item'が呼び出されているかどうかチェックしましたか? –

+0

コードをいくつかの印刷と固定インデントで更新しました。 'process_item'と' _insert_record'と '_handle_error'を除く他のすべての関数が呼び出されます。私は実際には 'init'関数の接続が間違ったパスワードで失敗するのに対し、これまでには驚いていますが、何らかの理由でこれに対してエラーが出ません。 – Casper

+0

@Casper MySQLサーバーのログにアクセスできますか?もしそうなら、それをチェックしてみてください。何かを見つけるかもしれません。 –

答えて

0

スクラップしたアイテムを保存するために、MySQLでadbapiを使用する方法についてはat thisをご覧ください。 process_itemとその方法の実装の違いは、process_itemです。アイテムをすぐに返す間に、runInteractionメソッドの結果であるDeferredオブジェクトが返され、完了時にアイテムが返されます。私はこれがあなたの_insert_recordが決して呼び出されない理由だと思う。

+0

私はrunInteractionを返すことでテストしましたが、私はAttributeErrorを取得します。これを質問に追加しました。 – Casper

+0

'query.addBoth(lambda _:item)'を追加しなければなりませんでした。今私はそれが私のプロバイダとこれをチェックしているので、サーバーに接続できないと私に言って、適切なエラーが表示されます。今までありがとう! – Casper

+0

私のプロバイダに最後の問題を解決しました。このコードを提供していただきありがとうございます@TomášLinhart – Casper

0

あなたはすでにだ、あなたの出力の挿入を確認することができた場合良いしるし。 私はinsert関数をこのように書き換えたい:

def _insert_record(self, tx, item): 
    print "insert" 
    raw_sql = "INSERT INTO matches(type,home,away,home_score,away_score) VALUES ('%s', '%s', '%s', '%s', '%s')" 
    sql = raw_sql % ('soccer', item['home'], item['away'], item['score'].explode('-')[0], item['score'].explode('-')[1]) 
    print sql 
    result = tx.execute(sql) 
    if result > 0: 
     self.stats.inc_value('database/items_added') 

それはあなたが使用しているSQLをデバッグすることができます。あなたのバージョンでは、mysqlの構文エラーである'の文字列をラップしていません。 最後の値(スコア)がわからないので、文字列として扱いました。

+0

私は彼が* 'process_item'が' _insert_record'を除く他のすべての関数と同様に呼び出されたと思います。* –

+0

そうです。 '_insert_record'は決して呼び出されないようです。したがって、私はこの機能の変化が違いを生むとは考えていませんか? – Casper

+0

本当に、私は何とかそれを見ませんでした。 –

関連する問題