2

Python でいくつかのリンクとメタ タグを選択するために、scrapy フレームワークを使用してクローラーを作成しました。次に、開始 URL をクロールし、データを JSON エンコード形式でファイルに書き込みます。問題は、クローラーが 2 回または 3 回実行される場合です。同じ開始 URL を使用すると、ファイル内のデータが重複します。これを回避するために、スクレイピーでダウンローダー ミドルウェアを使用しました

私がしたことは、上記のコードをスクレイピー プロジェクト内のファイルにコピー アンド ペーストし、次の行を追加して settings.py ファイルで有効にしたことです。

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

ここで、「a11ypi.removeDuplicates.IgnoreVisitedItems」はクラスパス名です。最後に、items.py ファイルに移動して変更し、次のフィールドを含めました。

visit_id = Field()  
visit_status = Field()

しかし、これは機能せず、クローラーは同じ結果を生成し、2 回実行するとファイルに追加します。

次のように、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  

何をすべきかを親切に提案してください。

4

1 に答える 1

1

スニペットがそのまま書かれている理由を理解しようとします。

 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

FILTER_VISITED2 行目で、実際には、ミドルウェアがリクエストをドロップするために呼び出される Request.meta 内のキーが必要であることに注意してください。アクセスしたすべての 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 sqlite db にスパイダー コンテキストを保存するためにコードの一部が変更されたため、0.14 以降で機能するかどうかはわかりません。

于 2012-01-16T06:54:19.527 に答える