mirror of https://github.com/scrapy/scrapy.git
Merge pull request #3512 from victor-torres/sitemap_filter
[MRG+1] Add sitemap_filter function to SitemapSpider class
This commit is contained in:
commit
094dde6fdb
|
|
@ -680,6 +680,50 @@ SitemapSpider
|
|||
|
||||
Default is ``sitemap_alternate_links`` disabled.
|
||||
|
||||
.. method:: sitemap_filter(entries)
|
||||
|
||||
This is a filter funtion that could be overridden to select sitemap entries
|
||||
based on their attributes.
|
||||
|
||||
For example::
|
||||
|
||||
<url>
|
||||
<loc>http://example.com/</loc>
|
||||
<lastmod>2005-01-01</lastmod>
|
||||
</url>
|
||||
|
||||
We can define a ``sitemap_filter`` function to filter ``entries`` by date::
|
||||
|
||||
from datetime import datetime
|
||||
from scrapy.spiders import SitemapSpider
|
||||
|
||||
class FilteredSitemapSpider(SitemapSpider):
|
||||
name = 'filtered_sitemap_spider'
|
||||
allowed_domains = ['example.com']
|
||||
sitemap_urls = ['http://example.com/sitemap.xml']
|
||||
|
||||
def sitemap_filter(self, entries):
|
||||
for entry in entries:
|
||||
date_time = datetime.strptime(entry['lastmod'], '%Y-%m-%d')
|
||||
if date_time.year >= 2005:
|
||||
yield entry
|
||||
|
||||
This would retrieve only ``entries`` modified on 2005 and the following
|
||||
years.
|
||||
|
||||
Entries are dict objects extracted from the sitemap document.
|
||||
Usually, the key is the tag name and the value is the text inside it.
|
||||
|
||||
It's important to notice that:
|
||||
|
||||
- as the loc attribute is required, entries without this tag are discarded
|
||||
- alternate links are stored in a list with the key ``alternate``
|
||||
(see ``sitemap_alternate_links``)
|
||||
- namespaces are removed, so lxml tags named as ``{namespace}tagname`` become only ``tagname``
|
||||
|
||||
If you omit this method, all entries found in sitemaps will be
|
||||
processed, observing other attributes and their settings.
|
||||
|
||||
|
||||
SitemapSpider examples
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@ class SitemapSpider(Spider):
|
|||
for url in self.sitemap_urls:
|
||||
yield Request(url, self._parse_sitemap)
|
||||
|
||||
def sitemap_filter(self, entries):
|
||||
"""This method can be used to filter sitemap entries by their
|
||||
attributes, for example, you can filter locs with lastmod greater
|
||||
than a given date (see docs).
|
||||
"""
|
||||
for entry in entries:
|
||||
yield entry
|
||||
|
||||
def _parse_sitemap(self, response):
|
||||
if response.url.endswith('/robots.txt'):
|
||||
for url in sitemap_urls_from_robots(response.text, base_url=response.url):
|
||||
|
|
@ -43,12 +51,14 @@ class SitemapSpider(Spider):
|
|||
return
|
||||
|
||||
s = Sitemap(body)
|
||||
it = self.sitemap_filter(s)
|
||||
|
||||
if s.type == 'sitemapindex':
|
||||
for loc in iterloc(s, self.sitemap_alternate_links):
|
||||
for loc in iterloc(it, self.sitemap_alternate_links):
|
||||
if any(x.search(loc) for x in self._follow):
|
||||
yield Request(loc, callback=self._parse_sitemap)
|
||||
elif s.type == 'urlset':
|
||||
for loc in iterloc(s, self.sitemap_alternate_links):
|
||||
for loc in iterloc(it, self.sitemap_alternate_links):
|
||||
for r, c in self._cbs:
|
||||
if r.search(loc):
|
||||
yield Request(loc, callback=c)
|
||||
|
|
|
|||
|
|
@ -375,6 +375,104 @@ Sitemap: /sitemap-relative-url.xml
|
|||
'http://www.example.com/schweiz-deutsch/',
|
||||
'http://www.example.com/italiano/'])
|
||||
|
||||
def test_sitemap_filter(self):
|
||||
sitemap = b"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<url>
|
||||
<loc>http://www.example.com/english/</loc>
|
||||
<lastmod>2010-01-01</lastmod>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://www.example.com/portuguese/</loc>
|
||||
<lastmod>2005-01-01</lastmod>
|
||||
</url>
|
||||
</urlset>"""
|
||||
|
||||
class FilteredSitemapSpider(self.spider_class):
|
||||
def sitemap_filter(self, entries):
|
||||
from datetime import datetime
|
||||
for entry in entries:
|
||||
date_time = datetime.strptime(entry['lastmod'], '%Y-%m-%d')
|
||||
if date_time.year > 2008:
|
||||
yield entry
|
||||
|
||||
r = TextResponse(url="http://www.example.com/sitemap.xml", body=sitemap)
|
||||
spider = self.spider_class("example.com")
|
||||
self.assertEqual([req.url for req in spider._parse_sitemap(r)],
|
||||
['http://www.example.com/english/',
|
||||
'http://www.example.com/portuguese/'])
|
||||
|
||||
spider = FilteredSitemapSpider("example.com")
|
||||
self.assertEqual([req.url for req in spider._parse_sitemap(r)],
|
||||
['http://www.example.com/english/'])
|
||||
|
||||
def test_sitemap_filter_with_alternate_links(self):
|
||||
sitemap = b"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<url>
|
||||
<loc>http://www.example.com/english/article_1/</loc>
|
||||
<lastmod>2010-01-01</lastmod>
|
||||
<xhtml:link rel="alternate" hreflang="de"
|
||||
href="http://www.example.com/deutsch/article_1/"/>
|
||||
</url>
|
||||
<url>
|
||||
<loc>http://www.example.com/english/article_2/</loc>
|
||||
<lastmod>2015-01-01</lastmod>
|
||||
</url>
|
||||
</urlset>"""
|
||||
|
||||
class FilteredSitemapSpider(self.spider_class):
|
||||
def sitemap_filter(self, entries):
|
||||
for entry in entries:
|
||||
alternate_links = entry.get('alternate', tuple())
|
||||
for link in alternate_links:
|
||||
if '/deutsch/' in link:
|
||||
entry['loc'] = link
|
||||
yield entry
|
||||
|
||||
r = TextResponse(url="http://www.example.com/sitemap.xml", body=sitemap)
|
||||
spider = self.spider_class("example.com")
|
||||
self.assertEqual([req.url for req in spider._parse_sitemap(r)],
|
||||
['http://www.example.com/english/article_1/',
|
||||
'http://www.example.com/english/article_2/'])
|
||||
|
||||
spider = FilteredSitemapSpider("example.com")
|
||||
self.assertEqual([req.url for req in spider._parse_sitemap(r)],
|
||||
['http://www.example.com/deutsch/article_1/'])
|
||||
|
||||
def test_sitemapindex_filter(self):
|
||||
sitemap = b"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<sitemap>
|
||||
<loc>http://www.example.com/sitemap1.xml</loc>
|
||||
<lastmod>2004-01-01T20:00:00+00:00</lastmod>
|
||||
</sitemap>
|
||||
<sitemap>
|
||||
<loc>http://www.example.com/sitemap2.xml</loc>
|
||||
<lastmod>2005-01-01</lastmod>
|
||||
</sitemap>
|
||||
</sitemapindex>"""
|
||||
|
||||
class FilteredSitemapSpider(self.spider_class):
|
||||
def sitemap_filter(self, entries):
|
||||
from datetime import datetime
|
||||
for entry in entries:
|
||||
date_time = datetime.strptime(entry['lastmod'].split('T')[0], '%Y-%m-%d')
|
||||
if date_time.year > 2004:
|
||||
yield entry
|
||||
|
||||
r = TextResponse(url="http://www.example.com/sitemap.xml", body=sitemap)
|
||||
spider = self.spider_class("example.com")
|
||||
self.assertEqual([req.url for req in spider._parse_sitemap(r)],
|
||||
['http://www.example.com/sitemap1.xml',
|
||||
'http://www.example.com/sitemap2.xml'])
|
||||
|
||||
spider = FilteredSitemapSpider("example.com")
|
||||
self.assertEqual([req.url for req in spider._parse_sitemap(r)],
|
||||
['http://www.example.com/sitemap2.xml'])
|
||||
|
||||
|
||||
class DeprecationTest(unittest.TestCase):
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue