2013-02-02 9 views
6

Mam problem tak:Korzystanie middleware, aby zapobiec scrapy z podwójnymi odwiedzenie stron internetowych

how to filter duplicate requests based on url in scrapy

Więc nie ma na stronie internetowej mają być przeszukiwane więcej niż jeden raz. Zaadaptowałem oprogramowanie pośrednie i napisałem polecenie drukowania, aby sprawdzić, czy poprawnie klasyfikuje on już widziane strony internetowe. To robi.

Mimo to parsowanie wydaje się być wykonywane wiele razy, ponieważ plik json, który otrzymuję, zawiera podwójne wpisy.

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 wygląda tak:

# 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 

Moja middleware wygląda następująco:

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) 

Dodałem tę linię do settings.py:

DUPEFILTER_CLASS = 'crawlspider.duplicate_filter.CustomFilter' 

Wywołuję skrypt za pomocą "scrapy crawl kic kstarter -o items.json -t json ". Następnie widzę poprawne instrukcje drukowania z kodu oprogramowania pośredniego. Wszelkie uwagi na temat tego, dlaczego json zawiera wiele wpisów zawierających te same dane?

+0

Czy mógłbyś opublikować swój kod pająka, proszę? Ułatwi to śledzenie duplikatów. :) – Talvalin

+0

@Talvalin Dodałem kod do mojego pierwotnego wpisu. Dzięki za pomoc. – Damian

+0

Każdy konkretny powód, dla którego nie używasz domyślnej metody scrapy, ponieważ istnieje już [dupefiltr] (https://scrapy.readthedocs.org/en/latest/topics/settings.html?highlight=settings#dupefilter- klasa) zaimplementowana i aktywna AFAIK. – DrColossos

Odpowiedz

0

Więc teraz są trzy modyfikacje, które usuwa duplikaty:

I dodali do settings.py: ITEM_PIPELINES = ['crawlspider.pipelines.DuplicatesPipeline',]

pozwolić scrapy wiedzieć, że dodałem DuplicatesPipeline funkcji w 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 

Nie trzeba dostosowywać pająka i nie używać wcześniej dodanych elementów dupefiltera/oprogramowania pośredniego.

Ale mam wrażenie, że moje rozwiązanie nie zmniejsza komunikacji, ponieważ obiekt-obiekt musi zostać utworzony najpierw, zanim zostanie oceniony i ewentualnie usunięty. Ale jestem z tym w porządku.

(Rozwiązanie znalezione przez pytającego, przeniesione do odpowiedzi)

+1

wygląda na to, że nadal będziesz wyrzucać wszystkie zduplikowane strony. Filtrujesz tylko elementy przed wydrukowaniem wyników – Temak

Powiązane problemy