Skip to content

Commit c8ff59b

Browse files
authored
Merge pull request #107 from scrapy/add-attrs
Add attributes dict accessor
2 parents 5323b83 + ee042d1 commit c8ff59b

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

parsel/selector.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,16 @@ def extract_first(self, default=None):
140140
return default
141141
get = extract_first
142142

143+
@property
144+
def attrib(self):
145+
"""Return the attributes dictionary for the first element.
146+
If the list is empty, return an empty dict.
147+
"""
148+
for x in self:
149+
return x.attrib
150+
else:
151+
return {}
152+
143153

144154
class Selector(object):
145155
"""
@@ -330,6 +340,12 @@ def remove_namespaces(self):
330340
# remove namespace declarations
331341
etree.cleanup_namespaces(self.root)
332342

343+
@property
344+
def attrib(self):
345+
"""Return the attributes dictionary for underlying element.
346+
"""
347+
return dict(self.root.attrib)
348+
333349
def __bool__(self):
334350
"""
335351
Return ``True`` if there is any real content selected or ``False``

tests/test_selector.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,34 @@ def test_simple_selection_with_variables_escape_friendly(self):
101101
lng=lt)],
102102
[u'a'])
103103

104+
def test_accessing_attributes(self):
105+
body = u"""
106+
<html lang="en" version="1.0">
107+
<body>
108+
<ul id="some-list" class="list-cls" class="list-cls">
109+
<li class="item-cls" id="list-item-1">
110+
<li class="item-cls active" id="list-item-2">
111+
<li class="item-cls" id="list-item-3">
112+
</ul>
113+
</body>
114+
</html>
115+
"""
116+
sel = self.sscls(text=body)
117+
self.assertEquals({'lang': 'en', 'version': '1.0'}, sel.attrib)
118+
self.assertEquals({'id': 'some-list', 'class': 'list-cls'}, sel.css('ul')[0].attrib)
119+
120+
# for a SelectorList, bring the attributes of first-element only
121+
self.assertEquals({'id': 'some-list', 'class': 'list-cls'}, sel.css('ul').attrib)
122+
self.assertEquals({'class': 'item-cls', 'id': 'list-item-1'}, sel.css('li').attrib)
123+
self.assertEquals({}, sel.css('body').attrib)
124+
self.assertEquals({}, sel.css('non-existing-element').attrib)
125+
126+
self.assertEquals(
127+
[{'class': 'item-cls', 'id': 'list-item-1'},
128+
{'class': 'item-cls active', 'id': 'list-item-2'},
129+
{'class': 'item-cls', 'id': 'list-item-3'}],
130+
[e.attrib for e in sel.css('li')])
131+
104132
def test_representation_slice(self):
105133
body = u"<p><input name='{}' value='\xa9'/></p>".format(50 * 'b')
106134
sel = self.sscls(text=body)

0 commit comments

Comments
 (0)