3

XPathSelectorCSS3セレクターをサポートするためにScrapyとパッチをサブクラス化しようとしています。

XPathSelectorこのように定義されます:

class XPathSelector(object_ref):
    __slots__ = ['doc', 'xmlNode', 'expr', '__weakref__']

    def __init__(self, response=None, text=None, node=None, parent=None, expr=None):
        if parent is not None:
            self.doc = parent.doc
        ...

サブクラス化XPathSelectorしてオーバーライドします__init__

class CSSSelector(XPathSelector):
    def __init__(self, *args, **kwargs):
        translator = kwargs.get('translator', 'html').lower()

        if 'translator' in kwargs:
            del kwargs['translator']

        super(XPathSelector, self).__init__(*args, **kwargs)

を使おうとするCSSSelectorと、、、AttributeErrorのエラーが発生docxmlNodeますexpr。それらのスロットを手動で追加しCSSSelectorても役に立ちません。

__slot__クラスをsでサブクラス化する適切な方法は何ですか?


私の完全なコードはここにあります:

"""
Extends `XPathSelector` to allow CSS3 selectors via the `cssselect` library.
"""

from cssselect import HTMLTranslator, GenericTranslator
from scrapy.selector import XPathSelector, XPathSelectorList

__all__ = ['CSSSelector', 'CSSSelectorList']

class CSSSelector(XPathSelector):
    __slots__ = ['doc', 'xmlNode', 'expr', 'translator']

    def __init__(self, *args, **kwargs):
        translator = kwargs.get('translator', 'html').lower()

        if 'translator' in kwargs:
            del kwargs['translator']

        super(CSSSelector, self).__init__(*args, **kwargs)

        if translator == 'html':
            self.translator = HTMLTranslator()
        elif translator == 'xhtml':
            self.translator = HTMLTranslator(xhtml=True)
        elif translator == 'xml':
            self.translator = GenericTranslator()
        else:
            raise ValueError("Invalid translator: %s. Valid translators are 'html' (default), 'xhtml' and 'xml'." % translator)

    def _select_xpath(self, xpath):
        if hasattr(self.xmlNode, 'xpathEval'):
            self.doc.xpathContext.setContextNode(self.xmlNode)
            xpath = unicode_to_str(xpath, 'utf-8')

            try:
                xpath_result = self.doc.xpathContext.xpathEval(xpath)
            except libxml2.xpathError:
                raise ValueError("Invalid XPath: %s" % xpath)

            if hasattr(xpath_result, '__iter__'):
                return CSSSelectorList([self.__class__(node=node, parent=self, expr=xpath) for node in xpath_result])
            else:
                return CSSSelectorList([self.__class__(node=xpath_result, parent=self, expr=xpath)])
        else:
            return CSSSelectorList([])

    def select(self, selector):
        xpath = self.translator.css_to_xpath(selector)

        return self._select_xpath(xpath)

    def attribute(self, name):
        return self._select_xpath('self::@' + name)

    def text(self):
        return self._select_xpath('self::text()')

class CSSSelectorList(XPathSelectorList):
    def attribute(self, name):
        return [x.attribute(name) for x in self]

    def text(self, name):
        return [x.text() for x in self]

クラスをうまく初期化できます:

>>> css_selector = CSSSelector(response)

しかし、私はAttributeErrorいたるところにsを取得します:

>>> css_selector.select('title')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-150-d21b0f17d4cc> in <module>()
----> 1 css_selector.select('title')

<ipython-input-147-c855c7eaf9fa> in select(self, selector)
     57 
     58 
---> 59         return self._select_xpath(xpath)
     60 
     61 

<ipython-input-147-c855c7eaf9fa> in _select_xpath(self, xpath)
     34 
     35     def _select_xpath(self, xpath):
---> 36         if hasattr(self.xmlNode, 'xpathEval'):
     37             self.doc.xpathContext.setContextNode(self.xmlNode)
     38             xpath = unicode_to_str(xpath, 'utf-8')

AttributeError: xmlNode
4

1 に答える 1

13

を使用しても問題はありません__slots____init__問題はXPathSelector、サブクラスからを呼び出さないことです。

代わりにsuper(XPathSelector, self)あるべきですsuper(CSSSelector, self)

class CSSSelector(XPathSelector):
    def __init__(self, *args, **kwargs):
        # ...
        super(CSSSelector, self).__init__(*args, **kwargs)

Pythonのsuperに関する良いトピックを参照してください:__ init __()メソッドを使用したPython super()の理解

UPD。

価値があるのは、クラスをで拡張する場合__slots__、通常はサブクラスも追加する必要があります__slots__。少なくとも空のクラスです。そうしないと、インスタンスごとの辞書が作成され__slots__、基本クラスが事実上役に立たなくなります。Pythonリファレンスから:

宣言のアクションは、__slots__それが定義されているクラスに限定されます。その結果、サブクラス__dict__も定義しない限り、サブクラスにはが含まれます(追加のスロット__slots__の名前のみが含まれている必要があります)。

于 2013-01-06T22:47:12.870 に答える