2017-03-02 4 views
0

CrawlSpiderを使用してサイトをクロールし、内部リンクを通過し、外部リンクの内容(元のドメインとは異なるドメインのリンク)をスクレイプするScrapyスクレイパーを作成しています。Scrapy CrawlSpiderのstart_urlsに基づく動的ルール?

私は2つのルールで管理しましたが、クロール対象のサイトのドメインに基づいています。これを複数のWebサイトで実行したい場合は、私が現在実行している「start_url」がわからないため、ルールが適切に変更できないため、問題が発生します。

は、ここで私はこれまでのところ、それは1つのウェブサイトのために働くと私はウェブサイトのリストにそれを適用するかどうかはわかりません思い付いたものです:

class HomepagesSpider(CrawlSpider): 
    name = 'homepages' 

    homepage = 'http://www.somesite.com' 

    start_urls = [homepage] 

    # strip http and www 
    domain = homepage.replace('http://', '').replace('https://', '').replace('www.', '') 
    domain = domain[:-1] if domain[-1] == '/' else domain 

    rules = (
     Rule(LinkExtractor(allow_domains=(domain), deny_domains=()), callback='parse_internal', follow=True), 
     Rule(LinkExtractor(allow_domains=(), deny_domains=(domain)), callback='parse_external', follow=False), 
    ) 

    def parse_internal(self, response): 

     # log internal page... 

    def parse_external(self, response): 

     # parse external page... 

これはおそらくちょうど渡すことで行うことができますstart_urlをスクレイパーを呼び出す際に引数として使用しますが、スクレーパー自体でプログラムで行う方法を探しています。

アイデア? ありがとう!

サイモン。

答えて

1

私はvery similar questionを発見し、それがすぐにscrapyではサポートされていないことから、この問題のための回避策を開発するために受け入れ答えに提示2番目のオプションを使用しました。

私は、入力としてURLを取得し、そのためのルールを作成する機能を作成しました:私は、その後CrawlSpiderの機能の一部をオーバーライド

def rules_for_url(self, url): 

    domain = Tools.get_domain(url) 

    rules = (
     Rule(LinkExtractor(allow_domains=(domain), deny_domains=()), callback='parse_internal', follow=True), 
     Rule(LinkExtractor(allow_domains=(), deny_domains=(domain)), callback='parse_external', follow=False), 
    ) 

    return rules 

を。

  1. Iは、キーが別のウェブサイトのドメインであり、値は(rules_for_urlを使用して)、そのドメインのルールである辞書に_rulesを変え。 _rulesの人口は、私はその後、_rulesを使用しての新しい方法をサポートするために_requests_to_follow_response_downloadedで適切な変更を行い_compile_rules

  2. で行われます。

_rules = {} 

def _requests_to_follow(self, response): 
    if not isinstance(response, HtmlResponse): 
     return 
    seen = set() 

    domain = Tools.get_domain(response.url) 
    for n, rule in enumerate(self._rules[domain]): 
     links = [lnk for lnk in rule.link_extractor.extract_links(response) 
       if lnk not in seen] 
     if links and rule.process_links: 
      links = rule.process_links(links) 
     for link in links: 
      seen.add(link) 
      r = self._build_request(domain + ';' + str(n), link) 
      yield rule.process_request(r) 

def _response_downloaded(self, response): 

    meta_rule = response.meta['rule'].split(';') 
    domain = meta_rule[0] 
    rule_n = int(meta_rule[1]) 

    rule = self._rules[domain][rule_n] 
    return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow) 

def _compile_rules(self): 
    def get_method(method): 
     if callable(method): 
      return method 
     elif isinstance(method, six.string_types): 
      return getattr(self, method, None) 

    for url in self.start_urls: 
     url_rules = self.rules_for_url(url) 
     domain = Tools.get_domain(url) 
     self._rules[domain] = [copy.copy(r) for r in url_rules] 
     for rule in self._rules[domain]: 
      rule.callback = get_method(rule.callback) 
      rule.process_links = get_method(rule.process_links) 
      rule.process_request = get_method(rule.process_request) 

本来の機能hereを参照してください。

これで、スパイダーはstart_urlsの各URLを調べ、そのURLに固有の一連のルールを作成するだけです。次に、クロールするウェブサイトごとに適切なルールを使用します。

これは、今後この問題を抱える人に役立ちます。

サイモン。

0

start_urlsにすべてのウェブサイトのリンクを繰り返し、allowed_domainsおよびdeny_domainsの配列を設定してください。ルールを定義します。

start_urls = ["www.website1.com", "www.website2.com", "www.website3.com", "www.website4.com"] 

allow_domains = [] 
deny_domains = [] 

for link in start_urls 

    # strip http and www 
    domain = link.replace('http://', '').replace('https://', '').replace('www.', '') 
    domain = domain[:-1] if domain[-1] == '/' else domain 

    allow_domains.extend([domain]) 
    deny_domains.extend([domain]) 


rules = (
    Rule(LinkExtractor(allow_domains=allow_domains, deny_domains=()), callback='parse_internal', follow=True), 
    Rule(LinkExtractor(allow_domains=(), deny_domains=deny_domains), callback='parse_external', follow=False), 
) 
+0

いいえ、外部リンクの内容を掻きました。内部リンクは削られず、ウェブサイト上のすべての外部リンクを見つけるためにクロールされるだけです。 – Simon

+0

@Simon次に、 'parse_internal'でセレクタをデバッグする必要があります。正しくない可能性があります – Umair

+0

どのように間違っていますか?私はあなたが質問の段落を逃したかもしれないと思います。私は、コードが動作しているという質問に書いていますが、私はこれを複数のstart_urlsに適用する方法を探しています。 – Simon

関連する問題