2012-03-17 4 views
2

Preambule는 :Scrapy : 스파이더 미들웨어의 비동기 데이터베이스 요청?

나는 데이터베이스에 그 결과를 저장하는 거미가있다. 그런 다음 시간과 원격 웹 서버 리소스를 절약하기 위해 이미 데이터베이스에있는 항목을 요청하지 않기로했습니다. 워드 프로세서를 읽으면서 나는 커스텀 스파이더 미들웨어가 내가 가진 최선의 선택이라고 판단했다.

class SkipDupeMiddleware(object): 
    process_spider_output(response, result, spider): 
     for r in result: 
      if isinstance(r, Request) and item_in_database(r.url): 
       log.msg('Skip %s' % r.url) 
      else: 
       yield r 

여기서 item_in_database은 db를 쿼리합니다.

위대한 기능으로 많은 시간을 절약 할 수 있습니다.

이제 진짜 문제는 :

나중에 나는 비 차단 응용 프로그램에서 차단 데이터베이스 요청을 사용하는 것은 좋은 생각이 아니다 읽어 보시기 바랍니다. 난 항상 까지 "올바른 일을"그리고 난 adbapi에서 파이프 라인를 사용하는 조리법을 발견 adbapi

내 모든 DB 요청을 포장하기로 결정하지만, 그 미들웨어 레벨을 할 수 있습니까? 미들웨어는 BaseItem, Request 또는 None을 반환 할 예정이지만 adbapitwistedDeferred을 반환하며 나중에 Request 또는 None을 반환합니다.

그리고 지금은 붙어 있습니다.

+0

이 문제가 이미 내가 아는 다른 경우에 파이프 라인을 사용하여 해결된다. db lag 문제가 계속 발생하면 동적 로컬 색인을 작성할 수 있습니다. 동적 색인은 구문 분석이 끝나면 업데이트 할 수 있으므로 서버에 메모리 문제가 없습니다. 미들웨어는 조용한 DB 데이터 가용성에 의해서도 영향을받습니다. – Kruser

답변

1

AFAIK,

치료법은 대부분 동기식입니다. 페이지 다운로드 만 비동기식으로 수행되므로 요청에 콜백이있는 것입니다.

파이프 라인과 미들웨어는 동기식입니다.

+0

사실, 파이프 라인 메소드와 요청 콜백 모두 비동기적일 수 있고 지연을 반환 할 수 있습니다. –

2

process_item() 파이프 라인에서 지연을 반환 할 수 있습니다.

+0

나는 파이프 라인에 대해 알고, 질문은 middlewares에 관한 것이었다. – dmzkrsk

1

기본적으로 치료는 중복 필터 (enalbedby)를 사용하여 크롤링에서 duplicaterequest를 수행하지 않습니다. 설정 매개 변수 DUPEFILTER_CLAS는 사용할 필터를 결정합니다. 기본값은 'scrapy.dupefilter.RFPDupeFilter'입니다. 사실 지금은 선택 사항입니다. 영구 기능을 원하면 JOBDIR을 설정해야합니다. 그런 다음 치료는 액세스 된 URL을 저장하고 다음 실행시 해당 URL을 필터의 dict에로드합니다.

당신은 여기에 몇 가지 팁을 얻을 수 있습니다 : http://groups.google.com/group/scrapy-users/browse_thread/thread/56546e9fab7030f3

0

유사 문제, 나는 몇 가지 검사를 수행 할 첫 번째 몇 가지 항목에 대한 거미 (DB 호출 포함)와 검사가 통과하는 경우 (크롤링 중지 난 단지 몇 가지 요청이 있다면, 우리는 그들을 차단 DB 연결을 사용하여 할 수 있다고 생각).

생각이 떠올랐다. 스파이더 스파이더가 우리가 긁는 사이트에 대한 HTTP 요청을 잘 수행한다면, 같은 메커니즘을 사용하여 비동기 db 요청을 해보자. elasticsearch와 같은 REST API를 가진 데이터베이스를 구현하는 것이 쉬워야합니다.이것은 내가 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] 
      } 
     )