Создание соединения с базой данных в промежуточном программном обеспечении scrapy и доступ к нему в других модулях - PullRequest
0 голосов
/ 20 апреля 2020

У меня есть несколько разных пауков в проекте, которые используют одну и ту же базу данных, у меня есть разные классы предметов, поэтому я могу правильно с ними обращаться в конвейере и отправлять их в желаемое место назначения. В моем первом пауке база данных создается в конвейере следующим образом:

def __init__(self, database, user, password, host, port):
    self.database = database
    self.user = user
    self.password = password
    self.host = host
    self.port = port

@classmethod
def from_crawler(cls, crawler):
    db_settings = crawler.settings.getdict("DB_SETTINGS")
    if not db_settings:
        raise NotConfigured
    db = db_settings['database']
    user = db_settings['user']
    password = db_settings['password']
    host = db_settings['host']
    port = db_settings['port']
    return cls(db, user, password, host, port)

def open_spider(self, spider):
    self.connection = psycopg2.connect(database=self.database, user=self.user, password=self.password,
                                       host=self.host, port=self.port)
    self.cursor = self.connection.cursor()

def close_spider(self, spider):
    self.cursor_close = self.cursor.close()
    self.connection_close = self.connection.close()

, который работает нормально, однако для моего второго паука мне нужно получить доступ к некоторым данным из базы данных в самом пауке, чтобы я мог начать сканирование, а затем отправить элементы в конвейер, чтобы сохранить их в базе данных. Я мог бы создать экземпляр базы данных в пауке, используя тот же код, и прекратить делать это в конвейере, но есть несколько пауков, и я не хочу повторять этот процесс снова и снова. Мне было интересно, как создать соединение с базой данных в промежуточном программном обеспечении и получить к нему доступ как в пауке, так и в конвейере. Я думаю, что могу использовать тот же код выше для запуска базы данных. Я не знаю, как настроить его для доступа к курсору и соединению в пауке и конвейере

1 Ответ

0 голосов
/ 23 апреля 2020

Вот как я сделал это, вы можете сделать это в промежуточном программном обеспечении следующим образом:

## MiddleWare

class DBMiddleware(object):

    def __init__(self, db_settings):
        self.db_setting = db_settings

    @classmethod
    def from_crawler(cls, crawler):
        db_settings = crawler.settings.getdict("DB_SETTINGS")
        if not db_settings:  # if we don't define db config in settings
            raise NotConfigured

        s = cls(db_settings)
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        crawler.signals.connect(s.spider_closed, signal=signals.spider_closed)
        return s

    def spider_opened(self, spider):
        spider.connection = psycopg2.connect(database=self.db_setting['database'],
                                           user=self.db_setting['user'],
                                           password=self.db_setting['password'],
                                           host=self.db_setting['host'],
                                           port=self.db_setting['port'])


    def spider_closed(self, spider):
        spider.connection.close()

, затем вы можете добавить это к пауку, чтобы получить доступ к только что созданному соединению

## Spider
class MainSpider(scrapy.Spider):

    name = 'main_spider'
    start_urls = ['www.example.com']

    def __init__(self):
        pass

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

    def spider_opened(self, spider):
        pass

    def parse(self, response):
        cursor = self.connection.cursor()
        sql = "SELECT * FROM companies"
        cursor.execute(sql)
        result = cursor.fetchall()
        for element in result:
            loader = ItemLoader(item=Item_profile(), selector=element)
            loader.add_value('name', element[0])
            items = loader.load_item()
            yield items

    def spider_closed(self, spider):
        pass

это работает нормально, если вы просто хотите иметь доступ к соединению БД в методе spider pars, но мне нужно было открыть соединение до метода разбора, чтобы я мог получать ссылки из БД и crwal каждый из них по отдельности, поэтому мне нужно было соединение в методе ## Spider spider_opened (), но последовательность активации методов выглядит следующим образом:

1: #Spider __init__()
2: #Spider spider_opened()
3: #Middleware spider_opened() -->> connection is  created here
4: #Spider parse()
5: #Spider spider_closed()
6: #Middleware spider_closed()

, и это логично, поскольку согласно документации Основная функция Промежуточного программного обеспечения заключается в том, чтобы сидеть между двигателем и пауком, нам нужен модуль, который создается при запуске scrap, и это будет Extension . Поэтому я создал файл с именем extentions.py в каталоге root вместе с промежуточным программным обеспечением, конвейерами и т. Д. c. и добавил тот же код, что и в промежуточном программном обеспечении:

from scrapy import signals
from scrapy.exceptions import NotConfigured
import psycopg2


class DBExtension(object):
    def __init__(self, db_settings):
        self.db_setting = db_settings
        pass

    @classmethod
    def from_crawler(cls, crawler):
        db_settings = crawler.settings.getdict("DB_SETTINGS")
        if not db_settings:
            raise NotConfigured
        s = cls(db_settings)
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        crawler.signals.connect(s.spider_closed, signal=signals.spider_closed)
        return (s)

    def spider_opened(self, spider):
        spider.connection = psycopg2.connect(database=self.db_setting['database'],
                                           user=self.db_setting['user'],
                                           password=self.db_setting['password'],
                                           host=self.db_setting['host'],
                                           port=self.db_setting['port'])


    def spider_closed(self, spider):
        spider.connection.close()

, затем я активировал это расширение в settings.py

EXTENSIONS = {
    'ProjectName.extensions.DBExtension': 400
}

, и теперь у вас есть доступ к этому соединению в # Spider spider_opened () с self.connection и может загружать информацию из базы данных до начала сканирования. Я не знаю, есть ли более оптимальный способ обойти это, но сейчас это сработает для меня.

...