ScrapyでのRulesの理解

20125 ワード

          :      ,    ,             ,           ,         ,        。       +       ,       (link extractor)       。  scrapy    ,          ,     

1.
rules = (Rule(SgmlLinkExtractor(allow=('category/20/index_\d+\.html'), restrict_xpaths=("//div[@class='left']"))),
        Rule(SgmlLinkExtractor(allow=('a/\d+/\d+\.html'), restrict_xpaths=("//div[@class='left']")), callback='parse_item'),
    )

説明:Ruleは、抽出リンクを定義するルールです.上の2つのルールは、リストページの各ページングページと詳細ページに対応しています.キーはrestrict_を介してxpathは、次に登るリンクを抽出するためにページの特定の部分だけを限定する.2.follow用途第一:これは私が豆弁の新刊書を這い出すルールrules=(Rule(LinkExtractor(allow=(r’^https://book.douban.com/subject/[0-9]*/’),),callback=’parse_item',follow=False),)、このルールの下では定義されたstart_を登るだけです.urlsのルールと一致するリンク.followをTrueに変更すると爬虫類がstart_urlsが這い出すページでは、ルールに合ったurlを探して、全局が這い出すまでループします.第二:ruleはcallbackの有無にかかわらず、同じ_parse_response関数は処理しますが、followとcallbackがあるかどうかを判断します.
3.CrawlSpiderの詳細
前に書く
ScrapyベースのSpiderでは、Spiderクラスについて簡単に説明します.Spiderは基本的に多くのことをすることができますが、もしあなたが知乎や簡書全駅に登りたいなら、もっと強い武器が必要かもしれません.CrawlSpiderはSpiderに基づいているが,全局的に這い出すために生まれたと言える.
簡単な説明
CrawlSpiderは、特定のルールを持つWebサイトでよく使われる爬虫類で、Spiderに基づいていくつかの独特な属性を持っています.
rules:ターゲットWebサイトに一致し、干渉を排除するためのRuleオブジェクトの集合です.start_url:開始応答を取得するには、Item、Requestのいずれかを返す必要があります.rulesはRuleオブジェクトの集合なので、ここでもRuleを紹介します.いくつかのパラメータがあります:link_extractor、callback=None、cb_kwargs=None、follow=None、process_links=None、process_request=Noneのlink_extractorは、自分で定義することも、既存のLinkExtractorクラスを使用することもできます.主なパラメータは次のとおりです.
allow:カッコ内の「正規表現」を満たす値が抽出され、空の場合はすべて一致します.deny:この正規表現(または正規表現リスト)と一致しないURLは必ず抽出されません.allow_domains:抽出されるリンクのdomains.deny_domains:リンクが抽出されないdomains.restrict_xpaths:xpath式を使用して、allowと共同でリンクをフィルタします.もう一つ似たようなrestrict_cssの次は公式に提供された例で、ソースコードの観点からよくある問題を解読します.
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MySpider(CrawlSpider):
    name = 'example.com'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.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(LinkExtractor(allow=('category\.php', ), deny=('subsection\.php', ))),

        # Extract links matching 'item.php' and parse them with the spider's method parse_item
        Rule(LinkExtractor(allow=('item\.php', )), callback='parse_item'),
    )

    def parse_item(self, response):
        self.logger.info('Hi, this is an item page! %s', response.url)
        item = scrapy.Item()
        item['id'] = response.xpath('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
        item['name'] = response.xpath('//td[@id="item_name"]/text()').extract()
        item['description'] = response.xpath('//td[@id="item_description"]/text()').extract()
        return item

質問:CrawlSpiderはどのように動作していますか?
CrawlSpiderはSpiderを継承しているので、Spiderのすべての関数があります.まずはstart_requests対start_urlsの各urlは、parseによって受信されるリクエスト(make_requests_from_url)を開始する.Spider内のparseは定義する必要がありますが、CrawlSpiderはparseを定義して応答を解析します(self._parse_response(response,self.parse_start_url,cb_kwargs={},follow=True)parse_responseはcallback,follow,selfの有無に基づいている.follow_linksは異なる操作を実行します
 def _parse_response(self, response, callback, cb_kwargs, follow=True):
    ##     callback,    callback            reques item
        if callback:
            cb_res = callback(response, **cb_kwargs) or ()
            cb_res = self.process_results(response, cb_res)
            for requests_or_item in iterate_spider_output(cb_res):
                yield requests_or_item
    ##       follow, _requests_to_follow            link。
        if follow and self._follow_links:
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

そのうち_requests_to_followはまたlink_を取得しますextractor(これは私たちが転送したLinkExtractor)解析ページで得られたlink(link_extractor.extract_links(response))は、urlを加工し(process_links、カスタマイズが必要)、該当するlinkに対してRequestを開始します.使用するprocess_リクエスト(カスタマイズが必要)処理応答.
質問:CrawlSpiderはrulesをどのように取得しますか?
CrawlSpiderクラスはinitメソッドで呼び出されます.compile_rulesメソッドは、rules内の各Ruleを浅いコピーしてコールバック(callback)、処理するリンク(process_links)、および処理する処理要求(process_request)を取得します.
 def _compile_rules(self):
        def get_method(method):
            if callable(method):
                return method
            elif isinstance(method, six.string_types):
                return getattr(self, method, None)

        self._rules = [copy.copy(r) for r in self.rules]
        for rule in self._rules:
            rule.callback = get_method(rule.callback)
            rule.process_links = get_method(rule.process_links)
            rule.process_request = get_method(rule.process_request)

では、Ruleはどのように定義されているのでしょうか.
class Rule(object):

        def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):
            self.link_extractor = link_extractor
            self.callback = callback
            self.cb_kwargs = cb_kwargs or {}
            self.process_links = process_links
            self.process_request = process_request
            if follow is None:
                self.follow = False if callback else True
            else:
                self.follow = follow

だからLinkExtractorはlink_に伝わりますextractor.
callbackがあるのは指定された関数で処理され、callbackがないのはどの関数で処理されますか?
上の説明から分かるようにparse_responseはcallbackの(応答)responsを処理します.cb_res=callback(response,**cb_kwargs)or()そして_requests_to_followはself.response_downloadedはcallbackに渡され、ページに一致するurlに対してリクエストを開始する.r = Request(url=link.url, callback=self._response_downloaded)
CrawlSpiderでのシミュレーションの登録方法
CrawlSpiderはSpiderと同じようにstart_を使うのでrequestsはAndrewからリクエストを開始しましたLiu大神が参考にしたコードは、上陸をシミュレートする方法を説明しています.
##     start_requests,callback 
def start_requests(self):
    return [Request("http://www.zhihu.com/#signin", meta = {'cookiejar' : 1}, callback = self.post_login)]
def post_login(self, response):
    print 'Preparing login'
    #                    _xsrf     ,         
    xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]
    print xsrf
    #FormRequeset.from_response Scrapy       ,   post  
    #     ,    after_login    
    return [FormRequest.from_response(response,   #"http://www.zhihu.com/login",
                        meta = {'cookiejar' : response.meta['cookiejar']},
                        headers = self.headers,
                        formdata = {
                        '_xsrf': xsrf,
                        'email': '[email protected]',
                        'password': '321324jia'
                        },
                        callback = self.after_login,
                        dont_filter = True
                        )]
#make_requests_from_url   parse,    CrawlSpider parse     
def after_login(self, response) :
    for url in self.start_urls :
        yield self.make_requests_from_url(url)

最後にScrapyを貼ります.spiders.CrawlSpiderのソースコードを確認します.
"""
This modules implements the CrawlSpider which is the recommended spider to use
for scraping typical web sites that requires crawling pages.

See documentation in docs/topics/spiders.rst
"""

import copy
import six

from scrapy.http import Request, HtmlResponse
from scrapy.utils.spider import iterate_spider_output
from scrapy.spiders import Spider


def identity(x):
    return x


class Rule(object):

    def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity):
        self.link_extractor = link_extractor
        self.callback = callback
        self.cb_kwargs = cb_kwargs or {}
        self.process_links = process_links
        self.process_request = process_request
        if follow is None:
            self.follow = False if callback else True
        else:
            self.follow = follow


class CrawlSpider(Spider):

    rules = ()

    def __init__(self, *a, **kw):
        super(CrawlSpider, self).__init__(*a, **kw)
        self._compile_rules()

    def parse(self, response):
        return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True)

    def parse_start_url(self, response):
        return []

    def process_results(self, response, results):
        return results

    def _requests_to_follow(self, response):
        if not isinstance(response, HtmlResponse):
            return
        seen = set()
        for n, rule in enumerate(self._rules):
            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 = Request(url=link.url, callback=self._response_downloaded)
                r.meta.update(rule=n, link_text=link.text)
                yield rule.process_request(r)

    def _response_downloaded(self, response):
        rule = self._rules[response.meta['rule']]
        return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow)

    def _parse_response(self, response, callback, cb_kwargs, follow=True):
        if callback:
            cb_res = callback(response, **cb_kwargs) or ()
            cb_res = self.process_results(response, cb_res)
            for requests_or_item in iterate_spider_output(cb_res):
                yield requests_or_item

        if follow and self._follow_links:
            for request_or_item in self._requests_to_follow(response):
                yield request_or_item

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

        self._rules = [copy.copy(r) for r in self.rules]
        for rule in self._rules:
            rule.callback = get_method(rule.callback)
            rule.process_links = get_method(rule.process_links)
            rule.process_request = get_method(rule.process_request)

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(CrawlSpider, cls).from_crawler(crawler, *args, **kwargs)
        spider._follow_links = crawler.settings.getbool(
            'CRAWLSPIDER_FOLLOW_LINKS', True)
        return spider

    def set_crawler(self, crawler):
        super(CrawlSpider, self).set_crawler(crawler)
        self._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True)

内容は簡単な本から来て、いくつか分からないことがあって、後で理解します