2017-02-13 1 views
0

私はmeta属性にクロールされたパスを記録しようとしている更新されますScrapyのrequest.metaが誤っ

import scrapy 
from scrapy.linkextractors import LinkExtractor 

class ExampleSpider(scrapy.Spider): 
    name = "example" 
    allowed_domains = ["www.iana.org"] 
    start_urls = ['http://www.iana.org/'] 
    request_path_css = dict(
     main_menu = r'#home-panel-domains > h2', 
     domain_names = r'#main_right > p', 
    ) 

    def links(self, response, restrict_css=None): 
     lex = LinkExtractor(
      allow_domains=self.allowed_domains, 
      restrict_css=restrict_css) 
     return lex.extract_links(response) 

    def requests(self, response, css, cb, append=True): 
     links = [link for link in self.links(response, css)] 
     for link in links: 
      request = scrapy.Request(
       url=link.url, 
       callback=cb) 
      if append: 
       request.meta['req_path'] = response.meta['req_path'] 
       request.meta['req_path'].append(dict(txt=link.text, url=link.url)) 
      else: 
       request.meta['req_path'] = [dict(txt=link.text, url=link.url)] 
      yield request 

    def parse(self, response): 
     #self.logger.warn('## Request path: %s', response.meta['req_path']) 
     css = self.request_path_css['main_menu'] 
     return self.requests(response, css, self.domain_names, False) 

    def domain_names(self, response): 
     #self.logger.warn('## Request path: %s', response.meta['req_path']) 
     css = self.request_path_css['domain_names'] 
     return self.requests(response, css, self.domain_names_parser) 

    def domain_names_parser(self, response): 
     self.logger.warn('## Request path: %s', response.meta['req_path']) 

出力:

$ scrapy crawl -L WARN example 
2017-02-13 11:06:37 [example] WARNING: ## Request path: [{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/root', 'txt': 'The DNS Root Zone'}, {'url': 'http://www.iana.org/domains/int', 'txt': '.INT'}, {'url': 'http://www.iana.org/domains/arpa', 'txt': '.ARPA'}, {'url': 'http://www.iana.org/domains/idn-tables', 'txt': 'IDN Practices Repository'}, {'url': 'http://www.iana.org/dnssec', 'txt': 'Root Key Signing Key'}, {'url': 'http://www.iana.org/domains/special', 'txt': 'Special Purpose Domains'}] 
2017-02-13 11:06:37 [example] WARNING: ## Request path: [{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/root', 'txt': 'The DNS Root Zone'}, {'url': 'http://www.iana.org/domains/int', 'txt': '.INT'}, {'url': 'http://www.iana.org/domains/arpa', 'txt': '.ARPA'}, {'url': 'http://www.iana.org/domains/idn-tables', 'txt': 'IDN Practices Repository'}, {'url': 'http://www.iana.org/dnssec', 'txt': 'Root Key Signing Key'}, {'url': 'http://www.iana.org/domains/special', 'txt': 'Special Purpose Domains'}] 
2017-02-13 11:06:37 [example] WARNING: ## Request path: [{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/root', 'txt': 'The DNS Root Zone'}, {'url': 'http://www.iana.org/domains/int', 'txt': '.INT'}, {'url': 'http://www.iana.org/domains/arpa', 'txt': '.ARPA'}, {'url': 'http://www.iana.org/domains/idn-tables', 'txt': 'IDN Practices Repository'}, {'url': 'http://www.iana.org/dnssec', 'txt': 'Root Key Signing Key'}, {'url': 'http://www.iana.org/domains/special', 'txt': 'Special Purpose Domains'}] 
2017-02-13 11:06:37 [example] WARNING: ## Request path: [{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/root', 'txt': 'The DNS Root Zone'}, {'url': 'http://www.iana.org/domains/int', 'txt': '.INT'}, {'url': 'http://www.iana.org/domains/arpa', 'txt': '.ARPA'}, {'url': 'http://www.iana.org/domains/idn-tables', 'txt': 'IDN Practices Repository'}, {'url': 'http://www.iana.org/dnssec', 'txt': 'Root Key Signing Key'}, {'url': 'http://www.iana.org/domains/special', 'txt': 'Special Purpose Domains'}] 
2017-02-13 11:06:37 [example] WARNING: ## Request path: [{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/root', 'txt': 'The DNS Root Zone'}, {'url': 'http://www.iana.org/domains/int', 'txt': '.INT'}, {'url': 'http://www.iana.org/domains/arpa', 'txt': '.ARPA'}, {'url': 'http://www.iana.org/domains/idn-tables', 'txt': 'IDN Practices Repository'}, {'url': 'http://www.iana.org/dnssec', 'txt': 'Root Key Signing Key'}, {'url': 'http://www.iana.org/domains/special', 'txt': 'Special Purpose Domains'}] 
2017-02-13 11:06:38 [example] WARNING: ## Request path: [{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/root', 'txt': 'The DNS Root Zone'}, {'url': 'http://www.iana.org/domains/int', 'txt': '.INT'}, {'url': 'http://www.iana.org/domains/arpa', 'txt': '.ARPA'}, {'url': 'http://www.iana.org/domains/idn-tables', 'txt': 'IDN Practices Repository'}, {'url': 'http://www.iana.org/dnssec', 'txt': 'Root Key Signing Key'}, {'url': 'http://www.iana.org/domains/special', 'txt': 'Special Purpose Domains'}] 

これは私が望むように私は、期待したものではありませんしかし最後のURLがresponse.meta['req_path'][1]にあるようにするには、最後のページからのすべてのURL何らかの形でリストにアクセスしてください。言い換えれば

は、予想される出力があるような:あなたはhttp://www.iana.org/domainsを解析し、(それがデフォルトだから)append=Trueself.requests()を呼び出して、あなたの2番目の要求の後

[{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/root', 'txt': 'The DNS Root Zone'}] 
[{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/int', 'txt': '.INT'}] 
[{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/arpa', 'txt': '.ARPA'}] 
[{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/idn-tables', 'txt': 'IDN Practices Repository'}] 
[{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/dnssec', 'txt': 'Root Key Signing Key'}] 
[{'url': 'http://www.iana.org/domains', 'txt': 'Domain Names'}, {'url': 'http://www.iana.org/domains/special', 'txt': 'Special Purpose Domains'}] 

答えて

0

、この行:

request.meta['req_path'] = response.meta['req_path'] 

をコピーしません。リスト代わりに、元のリストへの参照を取得します。その後、(元のリストに!)追加し、次の行に:次のループ反復で

request.meta['req_path'].append(dict(txt=link.text, url=link.url)) 

、あなたは再び非常に同じ元のリストへの参照(今はすでに2つのエントリを持っていること)を取得し、追加しますそれに再び、等々。

あなたがしたいことは、すべてのリクエストに対して新しいリストを作成することです。

request.meta['req_path'] = response.meta['req_path'] + [dict(txt=link.text, url=link.url)] 
:あなたはこれを行うことにより、ラインを救うことができる

request.meta['req_path'] = response.meta['req_path'].copy() 

か:あなたは、最初の行に.copy()を追加することによって、例えば、これを行うことができます