2013-02-02 19 views
6

Tôi có một vấn đề như thế này:Sử dụng middleware để ngăn chặn scrapy từ các trang web đúp thăm

how to filter duplicate requests based on url in scrapy

Vì vậy, tôi không muốn có một trang web để được thu thập thông nhiều hơn một lần. Tôi đã điều chỉnh phần mềm trung gian và viết một bản in để kiểm tra xem nó có phân loại chính xác các trang web đã xem hay không. Nó có.

Tuy nhiên việc phân tích cú pháp dường như được thực thi nhiều lần vì json-File tôi nhận chứa các mục nhập kép.

from scrapy.contrib.spiders import CrawlSpider, Rule 
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor 
from scrapy.selector import HtmlXPathSelector 
from scrapy.item import Item 

from crawlspider.items import KickstarterItem 

from HTMLParser import HTMLParser 

### code for stripping off HTML tags: 
class MLStripper(HTMLParser): 
    def __init__(self): 
     self.reset() 
     self.fed = [] 
    def handle_data(self, d): 
     self.fed.append(d) 
    def get_data(self): 
     return str(''.join(self.fed)) 

def strip_tags(html): 
    s = MLStripper() 
    s.feed(html) 
    return s.get_data() 
### 

items = [] 

class MySpider(CrawlSpider): 
    name = 'kickstarter' 
    allowed_domains = ['kickstarter.com'] 
    start_urls = ['http://www.kickstarter.com'] 

    rules = (
     # Extract links matching 'category.php' (but not matching 'subsection.php') 
     # and follow links from them (since no callback means follow=True by default). 
     Rule(SgmlLinkExtractor(allow=('discover/categories/comics',))), 

     # Extract links matching 'item.php' and parse them with the spider's method parse_item 
     Rule(SgmlLinkExtractor(allow=('projects/',)), callback='parse_item'), 
    ) 

    def parse_item(self, response): 
     self.log('Hi, this is an item page! %s' % response.url) 

     hxs = HtmlXPathSelector(response) 
     item = KickstarterItem() 

     item['date'] = hxs.select('//*[@id="about"]/div[2]/ul/li[1]/text()').extract() 
     item['projname'] = hxs.select('//*[@id="title"]/a').extract() 
     item['projname'] = strip_tags(str(item['projname'])) 

     item['projauthor'] = hxs.select('//*[@id="name"]') 
     item['projauthor'] = item['projauthor'].select('string()').extract()[0] 

     item['backers'] = hxs.select('//*[@id="backers_count"]/data').extract() 
     item['backers'] = strip_tags(str(item['backers'])) 

     item['collmoney'] = hxs.select('//*[@id="pledged"]/data').extract() 
     item['collmoney'] = strip_tags(str(item['collmoney'])) 

     item['goalmoney'] = hxs.select('//*[@id="stats"]/h5[2]/text()').extract() 
     items.append(item) 
     return items 

My items.py trông như thế:

# Define here the models for your scraped items 
# 
# See documentation in: 
# http://doc.scrapy.org/topics/items.html 

from scrapy.item import Item, Field 

class KickstarterItem(Item): 
    # define the fields for your item here like: 
    date = Field() 
    projname = Field() 
    projauthor = Field() 
    backers = Field() 
    collmoney = Field() 
    goalmoney = Field() 
    pass 

middleware của tôi trông như thế này:

import os 

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

class CustomFilter(RFPDupeFilter): 
def __getid(self, url): 
    mm = url.split("/")[4] #extracts project-id (is a number) from project-URL 
    print "_____________", mm 
    return mm 

def request_seen(self, request): 
    fp = self.__getid(request.url) 
    self.fingerprints.add(fp) 
    if fp in self.fingerprints and fp.isdigit(): # .isdigit() checks wether fp comes from a project ID 
     print "______fp is a number (therefore a project-id) and has been encountered before______" 
     return True 
    if self.file: 
     self.file.write(fp + os.linesep) 

tôi đã thêm dòng này để settings.py:

DUPEFILTER_CLASS = 'crawlspider.duplicate_filter.CustomFilter' 

Tôi gọi kịch bản bằng cách sử dụng "thu thập thông tin kstarter -o items.json -t json ". Sau đó, tôi thấy các câu lệnh in chính xác từ mã phần mềm trung gian. Bất kỳ nhận xét nào về lý do tại sao json chứa nhiều mục nhập chứa cùng một dữ liệu?

+0

Bạn có thể đăng tất cả mã của bạn không? Nó sẽ làm cho nó dễ dàng hơn để theo dõi các bản sao. :) – Talvalin

+0

@Talvalin Tôi đã thêm một số mã vào bài đăng gốc của mình. Cảm ơn bạn đã giúp đỡ. – Damian

+0

Bất kỳ lý do cụ thể nào tại sao bạn không sử dụng phương thức mặc định cho mục đích này vì đã có [dupefilter] (https://scrapy.readthedocs.org/en/latest/topics/settings.html?highlight=settings#dupefilter- lớp) đã triển khai và hoạt động AFAIK. – DrColossos

Trả lời

0

Bây giờ đây là những ba sửa đổi mà loại bỏ các bản sao:

tôi thêm này để settings.py: ITEM_PIPELINES = ['crawlspider.pipelines.DuplicatesPipeline',]

để cho scrapy biết rằng tôi đã thêm một chức năng DuplicatesPipeline trong pipelines.py:

from scrapy import signals 
from scrapy.exceptions import DropItem 

class DuplicatesPipeline(object): 

    def __init__(self): 
     self.ids_seen = set() 

    def process_item(self, item, spider): 
     if item['projname'] in self.ids_seen: 
      raise DropItem("Duplicate item found: %s" % item) 
     else: 
      self.ids_seen.add(item['projname']) 
      return item 

Bạn không cần phải điều chỉnh spider và không sử dụng công cụ dupefilter/middleware mà tôi đã đăng trước đây.

Nhưng tôi có cảm giác rằng giải pháp của tôi không làm giảm giao tiếp khi đối tượng mục phải được tạo trước tiên trước khi được đánh giá và có thể bị giảm. Nhưng tôi ổn với điều đó.

(Giải pháp được tìm thấy bởi người hỏi, được chuyển thành câu trả lời)

+1

có vẻ như bạn vẫn sẽ xóa tất cả các trang trùng lặp. Bạn chỉ lọc các mục trước khi xuất kết quả – Temak

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