在Scrapy中使用Sqlalchemy更新表行

时间:2017-12-22 15:02:03

标签: python sqlalchemy scrapy

我正在使用scrapy和sqlalchemy。在我的蜘蛛中,我从表中选择并使用以下命令创建请求:

def start_requests(self):

    db_path = "sqlite:///"+settings.SETTINGS_PATH+"\\data.db"
    source_table= self.table

    engine = create_engine(db_path)
    Base = declarative_base()
    # metadata = Base.metadata
    # Look up the existing tables from database
    Base.metadata.reflect(engine)

    # Create class that maps via ORM to the database table
    table = type(source_table, (Base,), {'__tablename__': source_table})

    Session = sessionmaker(bind=engine)
    session = Session()
    i = 0

for row in session.query(table).filter(table.url.contains('http')).limit(3):

    i += 1
    print(row.url)
    yield Request(url=row.url, headers= headers, callback=self.get_PDF,meta={'session': session,'row': row, 'cookiejar': i },dont_filter = True)

正如您所看到的,我正在为每个scrapy请求传递sqlalchemy行对象。每个行对象都包含空格字段,我从scrapy响应中更新。

def get_PDF(self, response):

    row = response.meta['row']

    row.field1 = response.field1 # simplified pseudocode

现在我想更新行对象,以便将其更改存储在db中。 如果我传递会话对象,我可以做session.commit()。使用row_object执行此操作的最佳方法是什么?我是否需要传递会话对象?

编辑:我已经更改了我的蜘蛛以传递会话对象:

def get_PDF(self, response):

    row = response.meta['row']
    session = response.meta['session']

    row =process_output(o, row)
    session.add(row)
    session.commit()

1 个答案:

答案 0 :(得分:3)

我想说总是处理数据库的最好方法是"外部"存储将使用Pipeline,因为它是一种分离代码逻辑的方法。 Pipeline只处理蜘蛛返回的项目,因此您不必担心蜘蛛代码中的请求或内容。

此外,Pipeline会创建一个与抓取工具关联的对象,并且只会实例化一次,这对此<div>Counter: {{counter}}</div> 情况非常有帮助。

如果您需要以不同方式处理项目,您总是可以为每个项目发送唯一标识符,因此管道知道如何处理每个项目。

修改 要在spider中创建session对象,并在Pipeline中重用它,你可以这样做:

<强>蜘蛛:

Session

<强>管道

def start_requests(self):
    self.session = Session()

def process_item(self, item, spider): ... spider.session.commit() 是&#34;唯一&#34;整个爬虫的spider实例,所以你可以在那里使用它的属性。