Merge pull request #363 from taikano/sitemap_alternate

also fetch alternate URLs from sitemaps, see #360
This commit is contained in:
Daniel Graña 2013-09-26 09:15:02 -07:00
commit 265910aae6
4 changed files with 71 additions and 4 deletions

View File

@ -560,6 +560,25 @@ SitemapSpider
By default, all sitemaps are followed.
.. attribute:: sitemap_alternate_links
Specifies if alternate links for one ``url`` should be followed. These
are links for the same website in another language passed within
the same ``url`` block.
For example::
<url>
<loc>http://example.com/</loc>
<xhtml:link rel="alternate" hreflang="de" href="http://example.com/de"/>
</url>
With ``sitemap_alternate_links`` set, this would retrieve both URLs. With
``sitemap_alternate_links`` disabled, only ``http://example.com/`` would be
retrieved.
Default is ``sitemap_alternate_links`` disabled.
SitemapSpider examples
~~~~~~~~~~~~~~~~~~~~~~

View File

@ -11,6 +11,7 @@ class SitemapSpider(BaseSpider):
sitemap_urls = ()
sitemap_rules = [('', 'parse')]
sitemap_follow = ['']
sitemap_alternate_links = False
def __init__(self, *a, **kw):
super(SitemapSpider, self).__init__(*a, **kw)
@ -37,7 +38,7 @@ class SitemapSpider(BaseSpider):
s = Sitemap(body)
if s.type == 'sitemapindex':
for loc in iterloc(s):
for loc in iterloc(s, 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':
@ -65,6 +66,11 @@ def regex(x):
return re.compile(x)
return x
def iterloc(it):
def iterloc(it, alt=False):
for d in it:
yield d['loc']
# Also consider alternate URLs (xhtml:link rel="alternate")
if alt and 'alternate' in d:
for l in d['alternate']:
yield l

View File

@ -159,6 +159,42 @@ Disallow: /forum/active/
{'lastmod': '2013-07-15', 'loc': 'http://www.example.com/sitemap3.xml'},
])
def test_comment(self):
s = Sitemap("""<?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/</loc>
<!-- this is a comment on which the parser might raise an exception if implemented incorrectly -->
</url>
</urlset>""")
self.assertEqual(list(s), [
{'loc': 'http://www.example.com/'}
])
def test_alternate(self):
s = Sitemap("""<?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>
<xhtml:link rel="alternate" hreflang="de"
href="http://www.example.com/deutsch/"/>
<xhtml:link rel="alternate" hreflang="de-ch"
href="http://www.example.com/schweiz-deutsch/"/>
<xhtml:link rel="alternate" hreflang="en"
href="http://www.example.com/english/"/>
<xhtml:link rel="alternate" hreflang="en"/><!-- wrong tag without href -->
</url>
</urlset>""")
self.assertEqual(list(s), [
{'loc': 'http://www.example.com/english/',
'alternate': ['http://www.example.com/deutsch/', 'http://www.example.com/schweiz-deutsch/', 'http://www.example.com/english/']
}
])
if __name__ == '__main__':
unittest.main()

View File

@ -12,7 +12,7 @@ class Sitemap(object):
(type=sitemapindex) files"""
def __init__(self, xmltext):
xmlp = lxml.etree.XMLParser(recover=True)
xmlp = lxml.etree.XMLParser(recover=True, remove_comments=True)
self._root = lxml.etree.fromstring(xmltext, parser=xmlp)
rt = self._root.tag
self.type = self._root.tag.split('}', 1)[1] if '}' in rt else rt
@ -23,7 +23,13 @@ class Sitemap(object):
for el in elem.getchildren():
tag = el.tag
name = tag.split('}', 1)[1] if '}' in tag else tag
d[name] = el.text.strip() if el.text else ''
if name == 'link':
if 'href' in el.attrib:
d.setdefault('alternate', []).append(el.get('href'))
else:
d[name] = el.text.strip() if el.text else ''
if 'loc' in d:
yield d