Как избежать дублирования в гусеничном шасси - PullRequest
2 голосов
/ 05 апреля 2011

Я написал сканер, использующий платформу scrapy в python, чтобы выбрать некоторые ссылки и метатеги. Затем он сканирует стартовые URL-адреса и записывает данные в формате в кодировке JSON в файл. Проблема заключается в том, что при запуске сканера дваили три раза с одним и тем же запуском URL-адресов данные в файле дублируются. Чтобы избежать этого, я использовал промежуточное программное обеспечение загрузчика в scrapy, которое выглядит так: http://snippets.scrapy.org/snippets/1/

То, что я сделал, было скопировать и вставить вышеуказанный код вфайл в моем проекте scrapy, и я включил его в файл settings.py, добавив следующую строку:

SPIDER_MIDDLEWARES = {'a11ypi.removeDuplicates.IgnoreVisitedItems':560} 

, где "a11ypi.removeDuplicates.IgnoreVisitedItems" - это имя пути к классу, и, наконец, я вошел иизменил мой файл items.py и включил следующие поля

visit_id = Field()  
visit_status = Field()

Но это не работает, и все же сканер выдает тот же результат, добавляя его в файл при запуске дважды

Я сделалзапись в файл в моем файле pipelines.py выглядит следующим образом:

import json 

class AYpiPipeline(object):  
    def __init__(self):  
    self.file = open("a11ypi_dict.json","ab+")


   # this method is called to process an item after it has been scraped.


    def process_item(self, item, spider):
    d = {}  

    i = 0
    # Here we are iterating over the scraped items and creating a dictionary of dictionaries.
    try:
        while i<len(item["foruri"]):
        d.setdefault(item["foruri"][i],{}).setdefault(item["rec"][i],{})[item["foruri_id"][i]] = item['thisurl'] + ":" +item["thisid"][i]
        i+=1
    except IndexError:
        print "Index out of range"

    json.dump(d,self.file)
        return item

И мой код паука выглядит следующим образом:

from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.selector import HtmlXPathSelector
from a11ypi.items import AYpiItem

class AYpiSpider(CrawlSpider):
    name = "a11y.in"
    allowed_domains = ["a11y.in"]

    # This is the list of seed URLs to begin crawling with.
    start_urls = ["http://www.a11y.in/a11ypi/idea/fire-hi.html"]

    # This is the callback method, which is used for scraping specific data
    def parse(self,response):
    temp = []
    hxs = HtmlXPathSelector(response)
    item = AYpiItem()
    wholeforuri = hxs.select("//@foruri").extract()            # XPath to extract the foruri, which contains both the URL and id in foruri
    for i in wholeforuri:
        temp.append(i.rpartition(":"))

    item["foruri"] = [i[0] for i in temp]     # This contains the URL in foruri
    item["foruri_id"] = [i.split(":")[-1] for i in wholeforuri]  # This contains the id in foruri
    item['thisurl'] = response.url                                  
    item["thisid"] = hxs.select("//@foruri/../@id").extract()
    item["rec"] = hxs.select("//@foruri/../@rec").extract()
    return item  

Пожалуйста, предложите, что делать.

1 Ответ

1 голос
/ 16 января 2012

попытайтесь понять, почему фрагмент написан так, как он есть:

 if isinstance(x, Request):
            if self.FILTER_VISITED in x.meta:
                visit_id = self._visited_id(x)
                if visit_id in visited_ids:
                    log.msg("Ignoring already visited: %s" % x.url,
                            level=log.INFO, spider=spider)
                    visited = True

Обратите внимание, что в строке 2 вам фактически требуется ключ в Request.meta с именем FILTER_VISITED, чтобы промежуточное программное обеспечение пропалозапрос.Причина правильная, потому что каждый URL, который вы посетили, будет пропущен, и у вас не будет URL для перехода, если вы этого не сделаете.Итак, FILTER_VISITED на самом деле позволяет вам выбрать, какие шаблоны URL вы хотите пропустить.Если вы хотите, чтобы ссылки извлекались с определенным правилом, пропустите, просто выполните

Rule(SgmlLinkExtractor(allow=('url_regex1', 'url_regex2' )),  callback='my_callback', process_request = setVisitFilter)

def setVisitFilter(request):
   request.meta['filter_visited'] = True
   return request

PS. Я не знаю, работает ли он для 0.14 и выше, так как часть кода изменилась для хранения контекста паука в базе данных sqlite.

...