2010-07-16 14 views
5

Je cherche un exemple de code d'un pipeline SQLite dans Scrapy. Je sais qu'il n'y a pas de soutien intégré, mais je suis sûr que cela a été fait. Seul le code actuel peut m'aider, car je ne connais que Python et Scrapy pour accomplir ma tâche très limitée et j'ai besoin du code comme point de départ.Quelqu'un a-t-il un exemple de code pour un pipeline sqlite dans Scrapy?

+0

Est-ce que Scrapy, qui s'exécute de manière asynchrone, nécessite un magasin de données non bloquant? Dans quel cas SQLite ne fonctionnerait pas? – zelusp

+0

Il semble que sqlite3 soit assez rapide et intelligent pour gérer la concurrence (jusqu'à un certain point). [Voir ici] (http://stackoverflow.com/questions/4060772/sqlite3-concurrent-access) – zelusp

Répondre

2

Si vous vous sentez à l'aise avec le adbapi de tordu, vous pouvez prendre comme point de départ ce pipeline mysql: http://github.com/darkrho/scrapy-googledir-mysql/blob/master/googledir/pipelines.py

Et utiliser cette ligne à __init__:

self.dbpool = adbapi.ConnectionPool("sqlite3", database="/path/sqlite.db") 
+0

Si vous utilisez sqlite3, tenez compte des exigences de threading qui requièrent que des objets sqlite soient utilisés dans le même thread que la création – Lionel

9

Je l'ai fait quelque chose comme ceci:

# 
# Author: Jay Vaughan 
# 
# Pipelines for processing items returned from a scrape. 
# Dont forget to add pipeline to the ITEM_PIPELINES setting 
# See: http://doc.scrapy.org/topics/item-pipeline.html 
# 
from scrapy import log 
from pysqlite2 import dbapi2 as sqlite 

# This pipeline takes the Item and stuffs it into scrapedata.db 
class scrapeDatasqLitePipeline(object): 
    def __init__(self): 
     # Possible we should be doing this in spider_open instead, but okay 
     self.connection = sqlite.connect('./scrapedata.db') 
     self.cursor = self.connection.cursor() 
     self.cursor.execute('CREATE TABLE IF NOT EXISTS myscrapedata ' \ 
        '(id INTEGER PRIMARY KEY, url VARCHAR(80), desc VARCHAR(80))') 

    # Take the item and put it in database - do not allow duplicates 
    def process_item(self, item, spider): 
     self.cursor.execute("select * from myscrapedata where url=?", item['url']) 
     result = self.cursor.fetchone() 
     if result: 
      log.msg("Item already in database: %s" % item, level=log.DEBUG) 
     else: 
      self.cursor.execute(
       "insert into myscrapedata (url, desc) values (?, ?)", 
        (item['url'][0], item['desc'][0]) 

      self.connection.commit() 

      log.msg("Item stored : " % item, level=log.DEBUG) 
     return item 

    def handle_error(self, e): 
     log.err(e) 
1

Pour ceux qui tentent de résoudre un problème similaire, je suis tombé sur un bon Exproter d'objet Sqlite pour SQLite: https://github.com/RockyZ/Scrapy-sqlite-item-exporter.

Après y compris à vos paramètres du projet, vous pouvez l'utiliser avec:

scrapy crawl <spider name> -o sqlite.db -t sqlite 

Il pourrait également être adapté pour être utilisé comme un pipeline article au lieu de l'exportateur d'article.

4

Voici un pipeline sqlite avec sqlalchemy. Avec sqlalchemy, vous pouvez facilement modifier votre base de données si nécessaire.

Dans la configuration de base de données settings.py add

# settings.py 
# ... 
DATABASE = { 
    'drivername': 'sqlite', 
    # 'host': 'localhost', 
    # 'port': '5432', 
    # 'username': 'YOUR_USERNAME', 
    # 'password': 'YOUR_PASSWORD', 
    'database': 'books.sqlite' 
} 

Puis, en pipelines.py ajouter ce qui suit

# pipelines.py 
import logging 

from scrapy import signals 
from sqlalchemy import Column, Integer, String, DateTime 
from sqlalchemy import create_engine 
from sqlalchemy.engine.url import URL 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy.pool import NullPool 

logger = logging.getLogger(__name__) 

DeclarativeBase = declarative_base() 

class Book(DeclarativeBase): 
    __tablename__ = "books" 

    id = Column(Integer, primary_key=True) 
    title = Column('title', String) 
    author = Column('author', String) 
    publisher = Column('publisher', String) 
    url = Column('url', String) 
    scrape_date = Column('scrape_date', DateTime) 

    def __repr__(self): 
     return "<Book({})>".format(self.url) 


class SqlitePipeline(object): 
    def __init__(self, settings): 
     self.database = settings.get('DATABASE') 
     self.sessions = {} 

    @classmethod 
    def from_crawler(cls, crawler): 
     pipeline = cls(crawler.settings) 
     crawler.signals.connect(pipeline.spider_opened, signals.spider_opened) 
     crawler.signals.connect(pipeline.spider_closed, signals.spider_closed) 
     return pipeline 

    def create_engine(self): 
     engine = create_engine(URL(**self.database), poolclass=NullPool, connect_args = {'charset':'utf8'}) 
     return engine 

    def create_tables(self, engine): 
     DeclarativeBase.metadata.create_all(engine, checkfirst=True) 

    def create_session(self, engine): 
     session = sessionmaker(bind=engine)() 
     return session 

    def spider_opened(self, spider): 
     engine = self.create_engine() 
     self.create_tables(engine) 
     session = self.create_session(engine) 
     self.sessions[spider] = session 

    def spider_closed(self, spider): 
     session = self.sessions.pop(spider) 
     session.close() 

    def process_item(self, item, spider): 
     session = self.sessions[spider] 
     book = Book(**item) 
     link_exists = session.query(Book).filter_by(url=item['url']).first() is not None 

     if link_exists: 
      logger.info('Item {} is in db'.format(book)) 
      return item 

     try: 
      session.add(book) 
      session.commit() 
      logger.info('Item {} stored in db'.format(book)) 
     except: 
      logger.info('Failed to add {} to db'.format(book)) 
      session.rollback() 
      raise 

     return item 

et items.py devrait ressembler à ceci

#items.py 
import scrapy 

class BookItem(scrapy.Item): 
    title = scrapy.Field() 
    author = scrapy.Field() 
    publisher = scrapy.Field() 
    scrape_date = scrapy.Field() 

Vous pouvez également envisager de se déplacer class Book dans items.py