mirror of https://github.com/scrapy/scrapy.git
- Introduction of class BaseAdaptor
- Contrib Adaptors - location_str moved from decobot to scrapy - Added setting DEFAULT_DATA_ENCODING --HG-- extra : convert_revision : svn%3Ab85faa78-f9eb-468e-a121-7cced6da292c%40161
This commit is contained in:
parent
3a018cadff
commit
8e72e4e60e
|
|
@ -0,0 +1,79 @@
|
|||
"""
|
||||
Adaptors for item adaptation pipe.
|
||||
"""
|
||||
|
||||
from scrapy.item.models import BaseAdaptor
|
||||
from scrapy.utils.python import flatten, unique
|
||||
from scrapy.xpath import XPathSelector
|
||||
from scrapy.utils.misc import unquote_html, location_str
|
||||
|
||||
class ExtendedAdaptor(BaseAdaptor):
|
||||
|
||||
def do(self, function, a, *args, **kwargs):
|
||||
"""Execute a function of the pipeline examining kwargs for possible
|
||||
pre/post functions. Also prints a lot of useful debugging info."""
|
||||
|
||||
debug = kwargs.get('debug')
|
||||
fname = function.__name__
|
||||
f = kwargs.get('pre_%s' % fname)
|
||||
if f and a:
|
||||
if debug:
|
||||
print " pre_%s | input >" % fname, a
|
||||
a = f(a)
|
||||
if debug:
|
||||
print " pre_%s | output >" % fname, a
|
||||
|
||||
if debug:
|
||||
print repr(kwargs)
|
||||
print " %07s | input >" % fname, location_str(a)
|
||||
a = function(a, *args, **kwargs)
|
||||
if debug:
|
||||
print " %07s | output>" % fname, a
|
||||
|
||||
f = kwargs.get('post_%s' % fname)
|
||||
if f and a:
|
||||
if debug:
|
||||
print " post_%s | input >" % fname, a
|
||||
a = f(a)
|
||||
if debug:
|
||||
print " post_%s | output >" % fname, a
|
||||
return a
|
||||
|
||||
class ExtractAdaptor(ExtendedAdaptor):
|
||||
|
||||
def function(self, item, attrname, location, **pipeargs):
|
||||
return self.do(self._extract, location, **pipeargs)
|
||||
|
||||
def _extract(self, location, **kwargs):
|
||||
"""Extract a list of strings from the location passed.
|
||||
Receives a list of XPathSelectors or an XPathSelector,
|
||||
or a list of strings or a string.
|
||||
|
||||
Return a list of strings extracted.
|
||||
|
||||
This function *always* returns a list.
|
||||
"""
|
||||
if not location:
|
||||
return []
|
||||
if isinstance(location, (list, tuple)):
|
||||
strings = flatten([self._extract(o, **kwargs) for o in location])
|
||||
if kwargs.get('remove_dupes', False):
|
||||
strings = unique(strings)
|
||||
if kwargs.get('first', False):
|
||||
return strings[:1]
|
||||
else:
|
||||
return strings
|
||||
# XPathSelector
|
||||
elif isinstance(location, XPathSelector):
|
||||
strings = [location.extract()]
|
||||
# Strings
|
||||
elif isinstance(location, unicode):
|
||||
strings = [unquote_html(location, keep_reserved=True)]
|
||||
elif isinstance(location, str):
|
||||
encoding = kwargs.get("encoding", settings.get('DEFAULT_DATA_ENCODING'))
|
||||
strings = [unquote_html(unicode(location, encoding), keep_reserved=True)]
|
||||
else:
|
||||
raise TypeError, "unsupported location type: %s" % type(location)
|
||||
|
||||
return strings
|
||||
|
||||
|
|
@ -1,3 +1,19 @@
|
|||
class BaseAdaptor:
|
||||
def function(self, item, attrname, value, **pipeargs):
|
||||
raise NotImplemented
|
||||
|
||||
#default adaptors
|
||||
class ExtractAdaptor(BaseAdaptor):
|
||||
def function(self, item, attrname, value, **pipeargs):
|
||||
if hasattr(value, 'extract'):
|
||||
value = value.extract()
|
||||
return value
|
||||
|
||||
class AssignAdaptor(BaseAdaptor):
|
||||
def function(self, item, attrname, value, **pipeargs):
|
||||
if not hasattr(item, attrname):
|
||||
setattr(item, attrname, value)
|
||||
|
||||
class ScrapedItem(object):
|
||||
"""
|
||||
This is the base class for all scraped items.
|
||||
|
|
@ -6,11 +22,12 @@ class ScrapedItem(object):
|
|||
* guid (unique global indentifier)
|
||||
* url (URL where that item was scraped from)
|
||||
"""
|
||||
adaptors_pipe = [ExtractAdaptor(), AssignAdaptor()]
|
||||
|
||||
def set_adaptors_pipe(adaptors_pipes):
|
||||
ScrapedItem.adaptors_pipes = adaptors_pipes
|
||||
|
||||
def assign(self, name, value):
|
||||
"""Assign an attribute. Can receive a Selector in value which will
|
||||
extract its data """
|
||||
def attribute(self, name, value, **pipeargs):
|
||||
|
||||
if hasattr(value, 'extract'):
|
||||
value = value.extract()
|
||||
setattr(self, name, value)
|
||||
for adaptor in ScrapedItem.adaptors_pipe:
|
||||
value = adaptor.function(self, name, value, **pipeargs)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import __project_name__
|
|||
BOT_NAME = 'scrapy-bot'
|
||||
BOT_VERSION = '1.0'
|
||||
|
||||
DEFAULT_DATA_ENCODING = 'ISO-8859-1'
|
||||
|
||||
COMMANDS_MODULE = '__project_name__.commands'
|
||||
COMMANDS_SETTINGS_MODULE = '__project_name__.conf.commands'
|
||||
SPIDER_MODULES = ['__project_name__.spiders']
|
||||
|
|
|
|||
|
|
@ -202,4 +202,12 @@ def extract_regex(regex, text, encoding):
|
|||
else:
|
||||
return [unquote_html(unicode(s, encoding), keep_reserved=True) for s in strings]
|
||||
|
||||
_regex_type = type(re.compile("", 0))
|
||||
|
||||
def location_str(location):
|
||||
"""Return a human friendly representation of a parser location"""
|
||||
|
||||
if isinstance(location, _regex_type):
|
||||
return "(regex) " + location.pattern
|
||||
else:
|
||||
return location
|
||||
|
|
|
|||
Loading…
Reference in New Issue