2012-09-23 27 views
35

Tôi đang viết trình thu thập thông tin cho một trang web sử dụng mẩu tin lưu niệm với CrawlSpider.cách lọc các yêu cầu trùng lặp dựa trên url trong scrapy

Phế liệu cung cấp bộ lọc yêu cầu trùng lặp được tích hợp sẵn để lọc các yêu cầu trùng lặp dựa trên các url. Ngoài ra, tôi có thể lọc các yêu cầu sử dụng quy tắc thành viên của CrawlSpider.

Những gì tôi muốn làm là để lọc các yêu cầu như:

http:://www.abc.com/p/xyz.html?id=1234&refer=5678 

Nếu tôi đã đến thăm

http:://www.abc.com/p/xyz.html?id=1234&refer=4567 

NOTE: refer is a parameter that doesn't affect the response I get, so I don't care if the value of that parameter changes.

Bây giờ, nếu tôi có một bộ mà tích tụ tất cả id Tôi có thể bỏ qua nó trong hàm gọi lại parse_item (đó là chức năng gọi lại của tôi) để đạt được chức năng này.

Nhưng điều đó có nghĩa là tôi vẫn ít nhất tìm nạp trang đó, khi tôi không cần.

Vì vậy, cách mà tôi có thể nói rõ rằng không nên gửi yêu cầu cụ thể dựa trên url?

Trả lời

36

Bạn có thể viết middleware tùy chỉnh để loại bỏ trùng lặp và thêm nó vào các thiết lập

import os 

from scrapy.dupefilter import RFPDupeFilter 
from scrapy.utils.request import request_fingerprint 

class CustomFilter(RFPDupeFilter): 
"""A dupe filter that considers specific ids in the url""" 

    def __getid(self, url): 
     mm = url.split("&refer")[0] #or something like that 
     return mm 

    def request_seen(self, request): 
     fp = self.__getid(request.url) 
     if fp in self.fingerprints: 
      return True 
     self.fingerprints.add(fp) 
     if self.file: 
      self.file.write(fp + os.linesep) 

Sau đó, bạn cần phải thiết lập các DUPFILTER_CLASS đúng trong settings.py

DUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter' 

Nó sẽ làm việc sau khi

rằng
+0

chính xác những gì tôi muốn, Thx. – thinker007

+0

Tôi đặt mã của bạn trong một tập tin trong thư mục nhện, nhưng tôi đã nhận lỗi này 'dupefilter = dupefilter_cls.from_settings (cài đặt) ngoại lệ. AttributeError: 'module' đối tượng không có thuộc tính 'from_settin gs'' –

+0

Thanks, This works , nhưng làm thế nào để tôi truy cập đối tượng 'spider' từ lớp tùy biến của tôi? – wolfgang

9

Theo chỉ dẫn của ytomar, tôi đã viết bộ lọc này lọc hoàn toàn dựa trên các URL đã được xem bằng cách kiểm tra bộ nhớ trong. Tôi là một Noob Python vì vậy hãy để tôi biết nếu tôi hơi say một cái gì đó lên, nhưng có vẻ như để làm việc tất cả các bên phải:

from scrapy.dupefilter import RFPDupeFilter 

class SeenURLFilter(RFPDupeFilter): 
    """A dupe filter that considers the URL""" 

    def __init__(self, path=None): 
     self.urls_seen = set() 
     RFPDupeFilter.__init__(self, path) 

    def request_seen(self, request): 
     if request.url in self.urls_seen: 
      return True 
     else: 
      self.urls_seen.add(request.url) 

Như ytomar đề cập, hãy chắc chắn để thêm DUPEFILTER_CLASS liên tục để settings.py:

DUPEFILTER_CLASS = 'scraper.custom_filters.SeenURLFilter' 
+0

Tôi nên đặt tệp pelase ở đâu? –

+0

@WilliamKinaan 'custom_filters.py' là nơi tôi đặt nó, trong cùng thư mục với' settings.py'. Tuy nhiên, cuối cùng tôi chỉ sử dụng bộ lọc URL mặc định của scrapy vì nó đủ tốt cho tôi. Đây là một bài tập trong việc học cách viết một bộ lọc tùy chỉnh. Tôi đã không xem xét việc thực hiện nội bộ, nhưng đã nghe nói nó sử dụng một [bộ lọc hoa] (http://en.wikipedia.org/wiki/Bloom_filter) cho hiệu suất tra cứu cao hơn (với chi phí có khả năng truy cập lại * một số * URL). –

+0

Cảm ơn nhận xét của bạn. Ngoài ra, hãy làm gì 'bộ lọc URL mặc định của scrapy'? Ngoài ra, bạn có thể đăng tài liệu chính thức của nó không? Cảm ơn trước –

2

https://github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py

Tệp này có thể giúp bạn. Tệp này tạo cơ sở dữ liệu của khóa tìm nạp delta đơn nhất từ ​​url, người dùng chuyển vào một scrapy.Reqeust (meta = {'deltafetch_key': uniqe_url_key}). Điều này cho phép bạn tránh các yêu cầu trùng lặp mà bạn đã truy cập trong quá khứ.

Một thực hiện MongoDB mẫu sử dụng deltafetch.py ​​

 if isinstance(r, Request): 
      key = self._get_key(r) 
      key = key+spider.name 

      if self.db['your_collection_to_store_deltafetch_key'].find_one({"_id":key}): 
       spider.log("Ignoring already visited: %s" % r, level=log.INFO) 
       continue 
     elif isinstance(r, BaseItem): 

      key = self._get_key(response.request) 
      key = key+spider.name 
      try: 
       self.db['your_collection_to_store_deltafetch_key'].insert({"_id":key,"time":datetime.now()}) 
      except: 
       spider.log("Ignoring already visited: %s" % key, level=log.ERROR) 
     yield r 

ví dụ. id = 345 scrapy.Request (url, meta = {deltafetch_key: 345}, callback = parse)

1

Đây là cơ sở bộ lọc tùy chỉnh của tôi trên mẩu tin lưu niệm 0,24.6.

Trong bộ lọc này, bộ lọc chỉ quan tâm đến id trong url.ví dụ

http://www.example.com/products/cat1/1000.html?p=1 http://www.example.com/products/cat2/1000.html?p=2

được coi là cùng url. Nhưng

http://www.example.com/products/cat2/all.html

sẽ không.

import re 
import os 
from scrapy.dupefilter import RFPDupeFilter 


class MyCustomURLFilter(RFPDupeFilter): 

    def _get_id(self, url): 
     m = re.search(r'(\d+)\.html', url) 
     return None if m is None else m.group(1) 

    def request_fingerprint(self, request): 
     style_id = self._get_id(request.url) 
     return style_id 
+1

Tuyệt vời, nhưng bạn có gợi ý để làm điều đó thông qua một spider để nhện cơ sở? – wolfgang

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