Аналогичная проблема, я хочу сделать несколько проверок (включая вызовы БД) в пауке для первых нескольких элементов и прекратить сканирование, если проверки пройдены (я думаю, что если есть только несколько запросов, мы можем сделать их, используя блокировка соединения дб).
Одна мысль пришла мне в голову: если паук scrapy хорош в выполнении http-запросов к сайтам, которые мы чистим, давайте делать асинхронные db-запросы, используя тот же механизм. Это должно быть легко реализовать для баз данных, имеющих REST API, таких какasticsearch.
Вот что я сделал для AWS S3:
from types import MethodType
import botocore.session
import treq
from scrapy import Request
class BotocoreRequest(Exception):
def __init__(self, request, *args, **kwargs):
super(BotocoreRequest, self).__init__(*args, **kwargs)
self.method = request.method
# https://github.com/twisted/treq/issues/185
self.url = request.url.replace('https://', 'http://')
self.headers = dict(request.headers)
self.body = request.body and request.body.read()
def _send_request(self, request_dict, operation_model):
request = self.create_request(request_dict, operation_model)
raise BotocoreRequest(request=request)
class ScrapyAWSClient(object):
def __init__(self, service, access_key, secret_key, region, timeout=30):
session = botocore.session.get_session()
session.set_credentials(
access_key=access_key,
secret_key=secret_key
)
self.client = session.create_client(service, region_name=region)
endpoint = self.client._endpoint
endpoint._send_request = MethodType(_send_request, endpoint)
self.timeout = timeout
def request(self, method, callback, meta, **kwargs):
try:
getattr(self.client, method)(**kwargs)
except BotocoreRequest as e:
return Request(
method=e.method,
url=e.url,
body=e.body,
headers=e.headers,
meta=meta,
callback=callback,
dont_filter=True
)
Паук:
class MySpider(Spider):
def __init__(self, *args, **kwargs):
super(MySpider, self).__init__(*args, **kwargs)
self.client = ScrapyAWSClient(
service='s3',
access_key='',
secret_key='',
region='your-region'
)
def parse(self, response):
...
yield self.client.request(
method='get_object',
Bucket='my-s3-bucket',
Key='my-key',
callback=self.my_parser,
meta={
'handle_httpstatus_list': [200, 403]
}
)