renamed x method of selectors to select

This commit is contained in:
Ismael Carnales 2009-08-17 15:58:06 -03:00
parent 59e0a83ad4
commit 48b40bd620
17 changed files with 168 additions and 130 deletions

View File

@ -132,9 +132,9 @@ Finally, here's the spider code::
torrent = ScrapedItem()
torrent.url = response.url
torrent.name = x.x("//h1/text()").extract()
torrent.description = x.x("//div[@id='description']").extract()
torrent.size = x.x("//div[@id='info-left']/p[2]/text()[2]").extract()
torrent.name = x.select("//h1/text()").extract()
torrent.description = x.select("//div[@id='description']").extract()
torrent.size = x.select("//div[@id='info-left']/p[2]/text()[2]").extract()
return [torrent]

View File

@ -264,19 +264,19 @@ The shell also instantiates two selectors, one for HTML (in the ``hxs``
variable) and one for XML (in the ``xxs`` variable)with this response. So let's
try them::
In [1]: hxs.x('/html/head/title')
In [1]: hxs.select('/html/head/title')
Out[1]: [<HtmlXPathSelector (title) xpath=/html/head/title>]
In [2]: hxs.x('/html/head/title').extract()
In [2]: hxs.select('/html/head/title').extract()
Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>']
In [3]: hxs.x('/html/head/title/text()')
In [3]: hxs.select('/html/head/title/text()')
Out[3]: [<HtmlXPathSelector (text) xpath=/html/head/title/text()>]
In [4]: hxs.x('/html/head/title/text()').extract()
In [4]: hxs.select('/html/head/title/text()').extract()
Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books']
In [5]: hxs.x('/html/head/title/text()').re('(\w+):')
In [5]: hxs.select('/html/head/title/text()').re('(\w+):')
Out[5]: [u'Computers', u'Programming', u'Languages', u'Python']
Extracting the data
@ -296,29 +296,29 @@ is inside a ``<ul>`` element, in fact the *second* ``<ul>`` element.
So we can select each ``<li>`` element belonging to the sites list with this
code::
hxs.x('//ul[2]/li')
hxs.select('//ul[2]/li')
And from them, the sites descriptions::
hxs.x('//ul[2]/li/text()').extract()
hxs.select('//ul[2]/li/text()').extract()
The sites titles::
hxs.x('//ul[2]/li/a/text()').extract()
hxs.select('//ul[2]/li/a/text()').extract()
And the sites links::
hxs.x('//ul[2]/li/a/@href').extract()
hxs.select('//ul[2]/li/a/@href').extract()
As we said before, each ``x()`` call returns a list of selectors, so we can
concatenate further ``x()`` calls to dig deeper into a node. We are going to use
As we said before, each ``select()`` call returns a list of selectors, so we can
concatenate further ``select()`` calls to dig deeper into a node. We are going to use
that property here, so::
sites = hxs.x('//ul[2]/li')
sites = hxs.select('//ul[2]/li')
for site in sites:
title = site.x('a/text()').extract()
link = site.x('a/@href').extract()
desc = site.x('text()').extract()
title = site.select('a/text()').extract()
link = site.select('a/@href').extract()
desc = site.select('text()').extract()
print title, link, desc
.. note::
@ -342,11 +342,11 @@ Let's add this code to our spider::
def parse(self, response):
hxs = HtmlXPathSelector(response)
sites = hxs.x('//ul[2]/li')
sites = hxs.select('//ul[2]/li')
for site in sites:
title = site.x('a/text()').extract()
link = site.x('a/@href').extract()
desc = site.x('text()').extract()
title = site.select('a/text()').extract()
link = site.select('a/@href').extract()
desc = site.select('text()').extract()
print title, link, desc
return []
@ -375,13 +375,13 @@ should be like this::
def parse(self, response):
hxs = HtmlXPathSelector(response)
sites = hxs.x('//ul[2]/li')
sites = hxs.select('//ul[2]/li')
items = []
for site in sites:
item = DmozItem()
item.title = site.x('a/text()').extract()
item.link = site.x('a/@href').extract()
item.desc = site.x('text()').extract()
item.title = site.select('a/text()').extract()
item.link = site.select('a/@href').extract()
item.desc = site.select('text()').extract()
items.append(item)
return items

View File

@ -31,7 +31,7 @@ XPathSelector objects
XPathSelector Methods
---------------------
.. method:: XPathSelector.x(xpath)
.. method:: XPathSelector.select(xpath)
Apply the given XPath relative to this XPathSelector and return a list
of :class:`XPathSelector` objects (ie. a :class:`XPathSelectorList`) with
@ -84,7 +84,7 @@ XPathSelectorList objects
XPathSelectorList Methods
-------------------------
.. method:: XPathSelectorList.x(xpath)
.. method:: XPathSelectorList.select(xpath)
Call the :meth:`XPathSelector.re` method for all :class:`XPathSelector`
objects in this list and return their results flattened, as new
@ -136,27 +136,27 @@ instanced with a :class:`~scrapy.http.Response` object like this::
1. Select all ``<h1>`` elements from a HTML response body, returning a list of
:class:`XPathSelector` objects (ie. a :class:`XPathSelectorList` object)::
x.x("//h1")
x.select("//h1")
2. Extract the text of all ``<h1>`` elements from a HTML response body,
returning a list of unicode strings::
x.x("//h1").extract() # this includes the h1 tag
x.x("//h1/text()").extract() # this excludes the h1 tag
x.select("//h1").extract() # this includes the h1 tag
x.select("//h1/text()").extract() # this excludes the h1 tag
3. Iterate over all ``<p>`` tags and print their class attribute::
for node in x.x("//p"):
... print node.x("@href")
for node in x.select("//p"):
... print node.select("@href")
4. Extract textual data from all ``<p>`` tags without entities, as a list of
unicode strings::
x.x("//p/text()").extract_unquoted()
x.select("//p/text()").extract_unquoted()
# the following line is wrong. extract_unquoted() should only be used
# with textual XPathSelectors
x.x("//p").extract_unquoted() # it may work but output is unpredictable
x.select("//p").extract_unquoted() # it may work but output is unpredictable
XmlXPathSelector objects
========================
@ -178,12 +178,12 @@ instanced with a :class:`~scrapy.http.Response` object like this::
1. Select all ``<product>`` elements from a XML response body, returning a list of
:class:`XPathSelector` objects (ie. a :class:`XPathSelectorList` object)::
x.x("//h1")
x.select("//h1")
2. Extract all prices from a `Google Base XML feed`_ which requires registering
a namespace::
x.register_namespace("g", "http://base.google.com/ns/1.0")
x.x("//g:price").extract()
x.select("//g:price").extract()
.. _Google Base XML feed: http://base.google.com/support/bin/answer.py?hl=en&answer=59461

View File

@ -189,9 +189,9 @@ Let's now take a look at an example CrawlSpider with rules::
hxs = HtmlXPathSelector(response)
item = ScrapedItem()
item.id = hxs.x('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
item.name = hxs.x('//td[@id="item_name"]/text()').extract()
item.description = hxs.x('//td[@id="item_description"]/text()').extract()
item.id = hxs.select('//td[@id="item_id"]/text()').re(r'ID: (\d+)')
item.name = hxs.select('//td[@id="item_name"]/text()').extract()
item.description = hxs.select('//td[@id="item_description"]/text()').extract()
return [item]
SPIDER = MySpider()
@ -307,9 +307,9 @@ These spiders are pretty easy to use, let's have at one example::
log.msg('Hi, this is a <%s> node!: %s' % (self.itertag, ''.join(node.extract())))
item = ScrapedItem()
item.id = node.x('@id').extract()
item.name = node.x('name').extract()
item.description = node.x('description').extract()
item.id = node.select('@id').extract()
item.name = node.select('name').extract()
item.description = node.select('description').extract()
return item
SPIDER = MySpider()

View File

@ -144,13 +144,13 @@ Finally, we can write our ``parse_category()`` method::
hxs = HtmlXPathSelector(response)
# The path to website links in directory page
links = hxs.x('//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font')
links = hxs.select('//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font')
for link in links:
item = ScrapedItem()
item.name = link.x('a/text()').extract()
item.url = link.x('a/@href').extract()
item.description = link.x('font[2]/text()').extract()
item.name = link.select('a/text()').extract()
item.url = link.select('a/@href').extract()
item.description = link.select('font[2]/text()').extract()
yield item

View File

@ -98,31 +98,31 @@ So, by looking at the :ref:`HTML code <topics-selectors-htmlcode>` of that page
let's construct an XPath (using an HTML selector) for selecting the text inside
the title tag::
>>> hxs.x('//title/text()')
>>> hxs.select('//title/text()')
[<HtmlXPathSelector (text) xpath=//title/text()>]
As you can see, the x() method returns a XPathSelectorList, which is a list of
As you can see, the select() method returns a XPathSelectorList, which is a list of
new selectors. This API can be used quickly for extracting nested data.
To actually extract the textual data you must call the selector ``extract()``
method, as follows::
>>> hxs.x('//title/text()').extract()
>>> hxs.select('//title/text()').extract()
[u'Example website']
Now we're going to get the base URL and some image links::
>>> hxs.x('//base/@href').extract()
>>> hxs.select('//base/@href').extract()
[u'http://example.com/']
>>> hxs.x('//a[contains(@href, "image")]/@href').extract()
>>> hxs.select('//a[contains(@href, "image")]/@href').extract()
[u'image1.html',
u'image2.html',
u'image3.html',
u'image4.html',
u'image5.html']
>>> hxs.x('//a[contains(@href, "image")]/img/@src').extract()
>>> hxs.select('//a[contains(@href, "image")]/img/@src').extract()
[u'image1_thumb.jpg',
u'image2_thumb.jpg',
u'image3_thumb.jpg',
@ -134,14 +134,14 @@ Using selectors with regular expressions
----------------------------------------
Selectors also have a ``re()`` method for extracting data using regular
expressions. However, unlike using the ``x()`` method, the ``re()`` method does
not return a list of :class:`~scrapy.xpath.XPathSelector` objects, so you can't
construct nested ``.re()`` calls.
expressions. However, unlike using the ``select()`` method, the ``re()`` method
does not return a list of :class:`~scrapy.xpath.XPathSelector` objects, so you
can't construct nested ``.re()`` calls.
Here's an example used to extract images names from the :ref:`HTML code
<topics-selectors-htmlcode>` above::
>>> hxs.x('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
>>> hxs.select('//a[contains(@href, "image")]/text()').re(r'Name:\s*(.*)')
[u'My image 1',
u'My image 2',
u'My image 3',
@ -153,10 +153,10 @@ Here's an example used to extract images names from the :ref:`HTML code
Nesting selectors
-----------------
The ``x()`` selector method returns a list of selectors, so you can call the
``x()`` for those selectors too. Here's an example::
The ``select()`` selector method returns a list of selectors, so you can call the
``select()`` for those selectors too. Here's an example::
>>> links = hxs.x('//a[contains(@href, "image")]')
>>> links = hxs.select('//a[contains(@href, "image")]')
>>> links.extract()
[u'<a href="image1.html">Name: My image 1 <br><img src="image1_thumb.jpg"></a>',
u'<a href="image2.html">Name: My image 2 <br><img src="image2_thumb.jpg"></a>',
@ -165,7 +165,7 @@ The ``x()`` selector method returns a list of selectors, so you can call the
u'<a href="image5.html">Name: My image 5 <br><img src="image5_thumb.jpg"></a>']
>>> for index, link in enumerate(links):
args = (index, link.x('@href').extract(), link.x('img/@src').extract())
args = (index, link.select('@href').extract(), link.select('img/@src').extract())
print 'Link number %d points to url %s and image %s' % args
Link number 0 points to url [u'image1.html'] and image [u'image1_thumb.jpg']
@ -186,23 +186,23 @@ to the ``XPathSelector`` you're calling it from.
For example, suppose you want to extract all ``<p>`` elements inside ``<div>``
elements. First you get would get all ``<div>`` elements::
>>> divs = hxs.x('//div')
>>> divs = hxs.select('//div')
At first, you may be tempted to use the following approach, which is wrong, as
it actually extracts all ``<p>`` elements from the document, not only those
inside ``<div>`` elements::
>>> for p in divs.x('//p') # this is wrong - gets all <p> from the whole document
>>> for p in divs.select('//p') # this is wrong - gets all <p> from the whole document
>>> print p.extract()
This is the proper way to do it (note the dot prefixing the ``.//p`` XPath)::
>>> for p in divs.x('.//p') # extracts all <p> inside
>>> for p in divs.select('.//p') # extracts all <p> inside
>>> print p.extract()
Another common case would be to extract all direct ``<p>`` children::
>>> for p in divs.x('p')
>>> for p in divs.select('p')
>>> print p.extract()
For more details about relative XPaths see the `Location Paths`_ section in the

View File

@ -137,7 +137,7 @@ shell works.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.
In [1]: hxs.x("//h2/text()").extract()[2]
In [1]: hxs.select("//h2/text()").extract()[2]
Out[1]: u'Welcome to Scrapy'
In [2]: get http://slashdot.org
@ -156,10 +156,10 @@ shell works.
scrapehelp: Prints this help.
------------------------------------------------------------
In [3]: hxs.x("//h2/text()").extract()
In [3]: hxs.select("//h2/text()").extract()
Out[3]: [u'News for nerds, stuff that matters']
In [3]: hxs.x("//h2/text()").extract()
In [3]: hxs.select("//h2/text()").extract()
Out[3]: [u'News for nerds, stuff that matters']
In [4]: request.method = "POST"

View File

@ -20,14 +20,14 @@ class GoogleDirectorySpider(CrawlSpider):
hxs = HtmlXPathSelector(response)
# The path to website links in directory page
links = hxs.x('//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font')
links = hxs.select('//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font')
for link in links:
item = GoogledirItem()
item.name = link.x('a/text()').extract()
item.url = link.x('a/@href').extract()
item.description = link.x('font[2]/text()').extract()
item.name = link.select('a/text()').extract()
item.url = link.select('a/@href').extract()
item.description = link.select('font[2]/text()').extract()
yield item
SPIDER = GoogleDirectorySpider()

View File

@ -35,14 +35,15 @@ class HTMLImageLinkExtractor(object):
if selector.xmlNode.type == 'element':
if selector.xmlNode.name == 'img':
_add_link(selector.x('@src'), selector.x('@alt') or selector.x('@title'))
_add_link(selector.select('@src'), selector.select('@alt') or \
selector.select('@title'))
else:
children = selector.x('child::*')
children = selector.select('child::*')
if len(children):
for child in children:
ret.extend(self.extract_from_selector(child, parent=selector))
elif selector.xmlNode.name == 'a' and not parent:
_add_link(selector.x('@href'), selector.x('@title'))
_add_link(selector.select('@href'), selector.select('@title'))
else:
_add_link(selector)
@ -50,13 +51,13 @@ class HTMLImageLinkExtractor(object):
def extract_links(self, response):
xs = HtmlXPathSelector(response)
base_url = xs.x('//base/@href').extract()
base_url = xs.select('//base/@href').extract()
base_url = unicode_to_str(base_url[0]) if base_url else unicode_to_str(response.url)
links = []
for location in self.locations:
if isinstance(location, basestring):
selectors = xs.x(location)
selectors = xs.select(location)
elif isinstance(location, (XPathSelectorList, HtmlXPathSelector)):
selectors = [location] if isinstance(location, HtmlXPathSelector) else location
else:

View File

@ -93,7 +93,8 @@ class SgmlLinkExtractor(BaseSgmlLinkExtractor):
def extract_links(self, response):
if self.restrict_xpaths:
hxs = HtmlXPathSelector(response)
html_slice = ''.join(''.join(html_fragm for html_fragm in hxs.x(xpath_expr).extract()) for xpath_expr in self.restrict_xpaths)
html_slice = ''.join(''.join(html_fragm for html_fragm in hxs.select(xpath_expr).extract()) \
for xpath_expr in self.restrict_xpaths)
links = self._extract_links(html_slice, response.url, response.encoding)
else:
links = BaseSgmlLinkExtractor.extract_links(self, response)

View File

@ -88,6 +88,6 @@ class XPathItemLoader(ItemLoader):
self.replace_value(field_name, self._get_values(field_name, xpath, re))
def _get_values(self, field_name, xpath, re):
x = self.selector.x(xpath)
x = self.selector.select(xpath)
return x.re(re) if re else x.extract()

View File

@ -74,11 +74,11 @@ class XMLFeedSpider(InitSpider):
elif self.iterator == 'xml':
selector = XmlXPathSelector(response)
self._register_namespaces(selector)
nodes = selector.x('//%s' % self.itertag)
nodes = selector.select('//%s' % self.itertag)
elif self.iterator == 'html':
selector = HtmlXPathSelector(response)
self._register_namespaces(selector)
nodes = selector.x('//%s' % self.itertag)
nodes = selector.select('//%s' % self.itertag)
else:
raise NotSupported('Unsupported node iterator')

View File

@ -26,7 +26,7 @@ class UtilsIteratorsTestCase(unittest.TestCase):
response = XmlResponse(url="http://example.com", body=body)
attrs = []
for x in xmliter(response, 'product'):
attrs.append((x.x("@id").extract(), x.x("name/text()").extract(), x.x("./type/text()").extract()))
attrs.append((x.select("@id").extract(), x.select("name/text()").extract(), x.select("./type/text()").extract()))
self.assertEqual(attrs,
[(['001'], ['Name 1'], ['Type 1']), (['002'], ['Name 2'], ['Type 2'])])
@ -34,7 +34,7 @@ class UtilsIteratorsTestCase(unittest.TestCase):
def test_xmliter_text(self):
body = u"""<?xml version="1.0" encoding="UTF-8"?><products><product>one</product><product>two</product></products>"""
self.assertEqual([x.x("text()").extract() for x in xmliter(body, 'product')],
self.assertEqual([x.select("text()").extract() for x in xmliter(body, 'product')],
[[u'one'], [u'two']])
def test_xmliter_namespaces(self):
@ -61,15 +61,15 @@ class UtilsIteratorsTestCase(unittest.TestCase):
node = my_iter.next()
node.register_namespace('g', 'http://base.google.com/ns/1.0')
self.assertEqual(node.x('title/text()').extract(), ['Item 1'])
self.assertEqual(node.x('description/text()').extract(), ['This is item 1'])
self.assertEqual(node.x('link/text()').extract(), ['http://www.mydummycompany.com/items/1'])
self.assertEqual(node.x('g:image_link/text()').extract(), ['http://www.mydummycompany.com/images/item1.jpg'])
self.assertEqual(node.x('g:id/text()').extract(), ['ITEM_1'])
self.assertEqual(node.x('g:price/text()').extract(), ['400'])
self.assertEqual(node.x('image_link/text()').extract(), [])
self.assertEqual(node.x('id/text()').extract(), [])
self.assertEqual(node.x('price/text()').extract(), [])
self.assertEqual(node.select('title/text()').extract(), ['Item 1'])
self.assertEqual(node.select('description/text()').extract(), ['This is item 1'])
self.assertEqual(node.select('link/text()').extract(), ['http://www.mydummycompany.com/items/1'])
self.assertEqual(node.select('g:image_link/text()').extract(), ['http://www.mydummycompany.com/images/item1.jpg'])
self.assertEqual(node.select('g:id/text()').extract(), ['ITEM_1'])
self.assertEqual(node.select('g:price/text()').extract(), ['400'])
self.assertEqual(node.select('image_link/text()').extract(), [])
self.assertEqual(node.select('id/text()').extract(), [])
self.assertEqual(node.select('price/text()').extract(), [])
def test_xmliter_exception(self):
body = u"""<?xml version="1.0" encoding="UTF-8"?><products><product>one</product><product>two</product></products>"""

View File

@ -17,31 +17,31 @@ class XPathSelectorTestCase(unittest.TestCase):
response = TextResponse(url="http://example.com", body=body)
xpath = HtmlXPathSelector(response)
xl = xpath.x('//input')
xl = xpath.select('//input')
self.assertEqual(2, len(xl))
for x in xl:
assert isinstance(x, HtmlXPathSelector)
self.assertEqual(xpath.x('//input').extract(),
[x.extract() for x in xpath.x('//input')])
self.assertEqual(xpath.select('//input').extract(),
[x.extract() for x in xpath.select('//input')])
self.assertEqual([x.extract() for x in xpath.x("//input[@name='a']/@name")],
self.assertEqual([x.extract() for x in xpath.select("//input[@name='a']/@name")],
[u'a'])
self.assertEqual([x.extract() for x in xpath.x("number(concat(//input[@name='a']/@value, //input[@name='b']/@value))")],
self.assertEqual([x.extract() for x in xpath.select("number(concat(//input[@name='a']/@value, //input[@name='b']/@value))")],
[u'12.0'])
self.assertEqual(xpath.x("concat('xpath', 'rules')").extract(),
self.assertEqual(xpath.select("concat('xpath', 'rules')").extract(),
[u'xpathrules'])
self.assertEqual([x.extract() for x in xpath.x("concat(//input[@name='a']/@value, //input[@name='b']/@value)")],
self.assertEqual([x.extract() for x in xpath.select("concat(//input[@name='a']/@value, //input[@name='b']/@value)")],
[u'12'])
@libxml2debug
def test_selector_same_type(self):
"""Test XPathSelector returning the same type in x() method"""
text = '<p>test<p>'
assert isinstance(XmlXPathSelector(text=text).x("//p")[0],
assert isinstance(XmlXPathSelector(text=text).select("//p")[0],
XmlXPathSelector)
assert isinstance(HtmlXPathSelector(text=text).x("//p")[0],
assert isinstance(HtmlXPathSelector(text=text).select("//p")[0],
HtmlXPathSelector)
@libxml2debug
@ -51,10 +51,10 @@ class XPathSelectorTestCase(unittest.TestCase):
# some text which is parsed differently by XML and HTML flavors
text = '<div><img src="a.jpg"><p>Hello</div>'
self.assertEqual(XmlXPathSelector(text=text).x("//div").extract(),
self.assertEqual(XmlXPathSelector(text=text).select("//div").extract(),
[u'<div><img src="a.jpg"><p>Hello</p></img></div>'])
self.assertEqual(HtmlXPathSelector(text=text).x("//div").extract(),
self.assertEqual(HtmlXPathSelector(text=text).select("//div").extract(),
[u'<div><img src="a.jpg"><p>Hello</p></div>'])
@libxml2debug
@ -76,14 +76,14 @@ class XPathSelectorTestCase(unittest.TestCase):
response = HtmlResponse(url="http://example.com", body=body)
x = HtmlXPathSelector(response)
divtwo = x.x('//div[@class="two"]')
self.assertEqual(divtwo.x("//li").extract(),
divtwo = x.select('//div[@class="two"]')
self.assertEqual(divtwo.select("//li").extract(),
["<li>one</li>", "<li>two</li>", "<li>four</li>", "<li>five</li>", "<li>six</li>"])
self.assertEqual(divtwo.x("./ul/li").extract(),
self.assertEqual(divtwo.select("./ul/li").extract(),
["<li>four</li>", "<li>five</li>", "<li>six</li>"])
self.assertEqual(divtwo.x(".//li").extract(),
self.assertEqual(divtwo.select(".//li").extract(),
["<li>four</li>", "<li>five</li>", "<li>six</li>"])
self.assertEqual(divtwo.x("./li").extract(),
self.assertEqual(divtwo.select("./li").extract(),
[])
@libxml2debug
@ -103,9 +103,9 @@ class XPathSelectorTestCase(unittest.TestCase):
x = HtmlXPathSelector(response)
name_re = re.compile("Name: (\w+)")
self.assertEqual(x.x("//ul/li").re(name_re),
self.assertEqual(x.select("//ul/li").re(name_re),
["John", "Paul"])
self.assertEqual(x.x("//ul/li").re("Age: (\d+)"),
self.assertEqual(x.select("//ul/li").re("Age: (\d+)"),
["10", "20"])
@libxml2debug
@ -119,7 +119,7 @@ class XPathSelectorTestCase(unittest.TestCase):
u'<root>lala</root>')
xxs = XmlXPathSelector(text='<root>lala</root>')
self.assertEqual(xxs.x('.').extract(),
self.assertEqual(xxs.select('.').extract(),
[u'<root>lala</root>'])
@ -136,7 +136,7 @@ class XPathSelectorTestCase(unittest.TestCase):
x = XmlXPathSelector(response)
x.register_namespace("somens", "http://scrapy.org")
self.assertEqual(x.x("//somens:a").extract(),
self.assertEqual(x.select("//somens:a").extract(),
['<somens:a id="foo"/>'])
@ -157,12 +157,12 @@ class XPathSelectorTestCase(unittest.TestCase):
x.register_namespace("xmlns", "http://webservices.amazon.com/AWSECommerceService/2005-10-05")
x.register_namespace("p", "http://www.scrapy.org/product")
x.register_namespace("b", "http://somens.com")
self.assertEqual(len(x.x("//xmlns:TestTag")), 1)
self.assertEqual(x.x("//b:Operation/text()").extract()[0], 'hello')
self.assertEqual(x.x("//xmlns:TestTag/@b:att").extract()[0], 'value')
self.assertEqual(x.x("//p:SecondTestTag/xmlns:price/text()").extract()[0], '90')
self.assertEqual(x.x("//p:SecondTestTag").x("./xmlns:price/text()")[0].extract(), '90')
self.assertEqual(x.x("//p:SecondTestTag/xmlns:material").extract()[0], '<material/>')
self.assertEqual(len(x.select("//xmlns:TestTag")), 1)
self.assertEqual(x.select("//b:Operation/text()").extract()[0], 'hello')
self.assertEqual(x.select("//xmlns:TestTag/@b:att").extract()[0], 'value')
self.assertEqual(x.select("//p:SecondTestTag/xmlns:price/text()").extract()[0], '90')
self.assertEqual(x.select("//p:SecondTestTag").select("./xmlns:price/text()")[0].extract(), '90')
self.assertEqual(x.select("//p:SecondTestTag/xmlns:material").extract()[0], '<material/>')
@libxml2debug
def test_selector_invalid_xpath(self):
@ -170,7 +170,7 @@ class XPathSelectorTestCase(unittest.TestCase):
x = HtmlXPathSelector(response)
xpath = "//test[@foo='bar]"
try:
x.x(xpath)
x.select(xpath)
except ValueError, e:
assert xpath in str(e), "Exception message does not contain invalid xpath"
except Exception:
@ -195,7 +195,7 @@ class XPathSelectorTestCase(unittest.TestCase):
headers = {'Content-Type': ['text/html; charset=utf-8']}
response = HtmlResponse(url="http://example.com", headers=headers, body=html_utf8)
x = HtmlXPathSelector(response)
self.assertEquals(x.x("//span[@id='blank']/text()").extract(),
self.assertEquals(x.select("//span[@id='blank']/text()").extract(),
[u'\xa3'])
@libxml2debug
@ -223,13 +223,13 @@ class XPathSelectorTestCase(unittest.TestCase):
self.assertEqual(xxs.extract_unquoted(), u'')
self.assertEqual(xxs.x('/root').extract_unquoted(), [u''])
self.assertEqual(xxs.x('/root/text()').extract_unquoted(), [
self.assertEqual(xxs.select('/root').extract_unquoted(), [u''])
self.assertEqual(xxs.select('/root/text()').extract_unquoted(), [
u'\n lala\n ',
u'\n pff\n'])
self.assertEqual(xxs.x('//*').extract_unquoted(), [u'', u'', u''])
self.assertEqual(xxs.x('//text()').extract_unquoted(), [
self.assertEqual(xxs.select('//*').extract_unquoted(), [u'', u'', u''])
self.assertEqual(xxs.select('//text()').extract_unquoted(), [
u'\n lala\n ',
u'\n blabla&more',
u'a',

24
scrapy/utils/decorator.py Normal file
View File

@ -0,0 +1,24 @@
import warnings
def deprecated(use_instead=None):
"""This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
when the function is used."""
def wraps(func):
def new_func(*args, **kwargs):
message = "Call to deprecated function %s." % func.__name__
if use_instead:
message += " Use %s instead." % use_instead
warnings.warn_explicit(
message,
category=DeprecationWarning,
filename=func.func_code.co_filename,
lineno=func.func_code.co_firstlineno + 1
)
return func(*args, **kwargs)
return new_func
return wraps

View File

@ -27,7 +27,7 @@ def xmliter(obj, nodename):
r = re.compile(r"<%s[\s>].*?</%s>" % (nodename, nodename), re.DOTALL)
for match in r.finditer(text):
nodetext = header_start + match.group() + header_end
yield XmlXPathSelector(text=nodetext).x('//' + nodename)[0]
yield XmlXPathSelector(text=nodetext).select('//' + nodename)[0]
def csviter(obj, delimiter=None, headers=None, encoding=None):
""" Returns an iterator of dictionaries from the given csv object

View File

@ -11,6 +11,7 @@ from scrapy.xpath.factories import xmlDoc_from_html, xmlDoc_from_xml
from scrapy.xpath.document import Libxml2Document
from scrapy.utils.python import flatten, unicode_to_str
from scrapy.utils.misc import extract_regex
from scrapy.utils.decorator import deprecated
class XPathSelector(object):
@ -29,7 +30,7 @@ class XPathSelector(object):
self.expr = expr
self.response = response
def x(self, xpath):
def select(self, xpath):
"""Perform the given XPath query on the current XPathSelector and
return a XPathSelectorList of the result"""
if hasattr(self.xmlNode, 'xpathEval'):
@ -47,7 +48,14 @@ class XPathSelector(object):
expr=xpath, response=self.response)])
else:
return XPathSelectorList([])
__call__ = x
@deprecated(use_instead='XPathSelector.select')
def __call__(self, xpath):
return self.select(xpath)
@deprecated(use_instead='XPathSelector.select')
def x(self, xpath):
return self.select(xpath)
def re(self, regex):
"""Return a list of unicode strings by applying the regex over all
@ -77,7 +85,7 @@ class XPathSelector(object):
def extract_unquoted(self):
"""Get unescaped contents from the text node (no entities, no CDATA)"""
if self.x('self::text()'):
if self.select('self::text()'):
return unicode(self.xmlNode.getContent(), 'utf-8', errors='ignore')
else:
return u''
@ -106,10 +114,14 @@ class XPathSelectorList(list):
def __getslice__(self, i, j):
return XPathSelectorList(list.__getslice__(self, i, j))
def x(self, xpath):
def select(self, xpath):
"""Perform the given XPath query on each XPathSelector of the list and
return a new (flattened) XPathSelectorList of the results"""
return XPathSelectorList(flatten([x.x(xpath) for x in self]))
return XPathSelectorList(flatten([x.select(xpath) for x in self]))
@deprecated(use_instead='XPathSelectorList.select')
def x(self, xpath):
return self.select(xpath)
def re(self, regex):
"""Perform the re() method on each XPathSelector of the list, and