|
1 |
| -from cssselect import GenericTranslator, HTMLTranslator |
2 |
| -from cssselect.xpath import _unicode_safe_getattr, XPathExpr, ExpressionError |
3 |
| -from cssselect.parser import FunctionalPseudoElement |
4 |
| - |
5 |
| - |
6 |
| -class ScrapyXPathExpr(XPathExpr): |
7 |
| - |
8 |
| - textnode = False |
9 |
| - attribute = None |
10 |
| - |
11 |
| - @classmethod |
12 |
| - def from_xpath(cls, xpath, textnode=False, attribute=None): |
13 |
| - x = cls(path=xpath.path, element=xpath.element, condition=xpath.condition) |
14 |
| - x.textnode = textnode |
15 |
| - x.attribute = attribute |
16 |
| - return x |
17 |
| - |
18 |
| - def __str__(self): |
19 |
| - path = super(ScrapyXPathExpr, self).__str__() |
20 |
| - if self.textnode: |
21 |
| - if path == '*': |
22 |
| - path = 'text()' |
23 |
| - elif path.endswith('::*/*'): |
24 |
| - path = path[:-3] + 'text()' |
25 |
| - else: |
26 |
| - path += '/text()' |
27 |
| - |
28 |
| - if self.attribute is not None: |
29 |
| - if path.endswith('::*/*'): |
30 |
| - path = path[:-2] |
31 |
| - path += '/@%s' % self.attribute |
32 |
| - |
33 |
| - return path |
34 |
| - |
35 |
| - def join(self, combiner, other): |
36 |
| - super(ScrapyXPathExpr, self).join(combiner, other) |
37 |
| - self.textnode = other.textnode |
38 |
| - self.attribute = other.attribute |
39 |
| - return self |
40 |
| - |
41 |
| - |
42 |
| -class TranslatorMixin(object): |
43 |
| - |
44 |
| - def xpath_element(self, selector): |
45 |
| - xpath = super(TranslatorMixin, self).xpath_element(selector) |
46 |
| - return ScrapyXPathExpr.from_xpath(xpath) |
47 |
| - |
48 |
| - def xpath_pseudo_element(self, xpath, pseudo_element): |
49 |
| - if isinstance(pseudo_element, FunctionalPseudoElement): |
50 |
| - method = 'xpath_%s_functional_pseudo_element' % ( |
51 |
| - pseudo_element.name.replace('-', '_')) |
52 |
| - method = _unicode_safe_getattr(self, method, None) |
53 |
| - if not method: |
54 |
| - raise ExpressionError( |
55 |
| - "The functional pseudo-element ::%s() is unknown" |
56 |
| - % pseudo_element.name) |
57 |
| - xpath = method(xpath, pseudo_element) |
58 |
| - else: |
59 |
| - method = 'xpath_%s_simple_pseudo_element' % ( |
60 |
| - pseudo_element.replace('-', '_')) |
61 |
| - method = _unicode_safe_getattr(self, method, None) |
62 |
| - if not method: |
63 |
| - raise ExpressionError( |
64 |
| - "The pseudo-element ::%s is unknown" |
65 |
| - % pseudo_element) |
66 |
| - xpath = method(xpath) |
67 |
| - return xpath |
68 |
| - |
69 |
| - def xpath_attr_functional_pseudo_element(self, xpath, function): |
70 |
| - if function.argument_types() not in (['STRING'], ['IDENT']): |
71 |
| - raise ExpressionError( |
72 |
| - "Expected a single string or ident for ::attr(), got %r" |
73 |
| - % function.arguments) |
74 |
| - return ScrapyXPathExpr.from_xpath(xpath, |
75 |
| - attribute=function.arguments[0].value) |
76 |
| - |
77 |
| - def xpath_text_simple_pseudo_element(self, xpath): |
78 |
| - """Support selecting text nodes using ::text pseudo-element""" |
79 |
| - return ScrapyXPathExpr.from_xpath(xpath, textnode=True) |
80 |
| - |
81 |
| - |
82 |
| -class ScrapyGenericTranslator(TranslatorMixin, GenericTranslator): |
83 |
| - pass |
84 |
| - |
85 |
| - |
86 |
| -class ScrapyHTMLTranslator(TranslatorMixin, HTMLTranslator): |
87 |
| - pass |
88 |
| - |
| 1 | +from parsel.csstranslator import ( |
| 2 | + ScrapyXPathExpr, |
| 3 | + TranslatorMixin, |
| 4 | + ScrapyGenericTranslator, |
| 5 | + ScrapyHTMLTranslator |
| 6 | +) |
0 commit comments