2016-11-21 25 views
5

Tôi hiện đang xây dựng một ứng dụng web có nghĩa là để hiển thị dữ liệu được thu thập bởi một con nhện bịp nhặt. Người dùng đưa ra yêu cầu, con nhện thu thập dữ liệu trang web, sau đó trả lại dữ liệu cho ứng dụng để được nhắc. Tôi muốn lấy dữ liệu trực tiếp từ scraper, mà không cần dựa vào tệp .csv hoặc .json trung gian. Một cái gì đó như:Làm cách nào để lưu dữ liệu từ trình thu thập dữ liệu vào một biến?

from scrapy.crawler import CrawlerProcess 
from scraper.spiders import MySpider 

url = 'www.example.com' 
spider = MySpider() 
crawler = CrawlerProcess() 
crawler.crawl(spider, start_urls=[url]) 
crawler.start() 
data = crawler.data # this bit 

Trả lời

6

Điều này không dễ dàng vì Scrapy không chặn và hoạt động trong vòng lặp sự kiện; nó sử dụng vòng lặp sự kiện Xoắn và vòng lặp sự kiện Xoắn không thể khởi động lại được, vì vậy bạn không thể viết crawler.start(); data = crawler.data - sau khi quá trình crawler.start() chạy mãi mãi, gọi lại cuộc gọi đã đăng ký cho đến khi nó bị giết hoặc kết thúc.

Những câu trả lời có thể có liên quan:

Nếu bạn sử dụng một vòng lặp sự kiện trong ứng dụng của bạn (ví dụ như bạn có một máy chủ web Twisted hoặc Tornado) sau đó nó là có thể lấy dữ liệu từ thu thập thông tin mà không lưu trữ dữ liệu vào đĩa. Ý tưởng là để nghe tín hiệu item_scraped. Tôi đang sử dụng helper sau để làm cho nó đẹp hơn:

import collections 

from twisted.internet.defer import Deferred 
from scrapy.crawler import Crawler 
from scrapy import signals 

def scrape_items(crawler_runner, crawler_or_spidercls, *args, **kwargs): 
    """ 
    Start a crawl and return an object (ItemCursor instance) 
    which allows to retrieve scraped items and wait for items 
    to become available. 

    Example: 

    .. code-block:: python 

     @inlineCallbacks 
     def f(): 
      runner = CrawlerRunner() 
      async_items = scrape_items(runner, my_spider) 
      while (yield async_items.fetch_next): 
       item = async_items.next_item() 
       # ... 
      # ... 

    This convoluted way to write a loop should become unnecessary 
    in Python 3.5 because of ``async for``. 
    """ 
    crawler = crawler_runner.create_crawler(crawler_or_spidercls)  
    d = crawler_runner.crawl(crawler, *args, **kwargs) 
    return ItemCursor(d, crawler) 


class ItemCursor(object): 
    def __init__(self, crawl_d, crawler): 
     self.crawl_d = crawl_d 
     self.crawler = crawler 

     crawler.signals.connect(self._on_item_scraped, signals.item_scraped) 

     crawl_d.addCallback(self._on_finished) 
     crawl_d.addErrback(self._on_error) 

     self.closed = False 
     self._items_available = Deferred() 
     self._items = collections.deque() 

    def _on_item_scraped(self, item): 
     self._items.append(item) 
     self._items_available.callback(True) 
     self._items_available = Deferred() 

    def _on_finished(self, result): 
     self.closed = True 
     self._items_available.callback(False) 

    def _on_error(self, failure): 
     self.closed = True 
     self._items_available.errback(failure) 

    @property 
    def fetch_next(self): 
     """ 
     A Deferred used with ``inlineCallbacks`` or ``gen.coroutine`` to 
     asynchronously retrieve the next item, waiting for an item to be 
     crawled if necessary. Resolves to ``False`` if the crawl is finished, 
     otherwise :meth:`next_item` is guaranteed to return an item 
     (a dict or a scrapy.Item instance). 
     """ 
     if self.closed: 
      # crawl is finished 
      d = Deferred() 
      d.callback(False) 
      return d 

     if self._items: 
      # result is ready 
      d = Deferred() 
      d.callback(True) 
      return d 

     # We're active, but item is not ready yet. Return a Deferred which 
     # resolves to True if item is scraped or to False if crawl is stopped. 
     return self._items_available 

    def next_item(self): 
     """Get a document from the most recently fetched batch, or ``None``. 
     See :attr:`fetch_next`. 
     """ 
     if not self._items: 
      return None 
     return self._items.popleft() 

API được lấy cảm hứng từ motor, một tài xế MongoDB cho các khuôn khổ async. Sử dụng scrape_items bạn có thể lấy các mục từ các cuộc gọi lại bị xoắn hoặc lốc xoáy ngay khi chúng được cạo, theo cách tương tự như cách bạn tìm nạp các mục từ một truy vấn MongoDB.

Các vấn đề liên quan