18

Question

How do I remove class attributes from html using python and lxml?

Example

I have:

<p class="DumbClass">Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>

I want:

<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>

What I've tried so far

I've checked out lxml.html.clean.Cleaner however, it does not have a method to strip out class attributes. You can set safe_attrs_only=True however, this does not remove the class attribute.

Significant searching has turned up nothing workable. I think the fact that class is used in both html and python further muddies search results. Many of the results also seem to deal strictly with xml as well.

I'm open to other python modules that offer humane interfaces as well.

Thanks much.


Solution

Thanks to @Dan Roberts answer below, I came up with the following solution. Presented for folks arriving here in the future trying to solve the same problem.

import lxml.html

# Our html string we want to remove the class attribute from
html_string = '<p class="DumbClass">Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>'

# Parse the html
html = lxml.html.fromstring(html_string)

# Print out our "Before"
print lxml.html.tostring(html)

# .xpath below gives us a list of all elements that have a class attribute
# xpath syntax explained:
# // = select all tags that match our expression regardless of location in doc
# * = match any tag
# [@class] = match all class attributes
for tag in html.xpath('//*[@class]'):
    # For each element with a class attribute, remove that class attribute
    tag.attrib.pop('class')

# Print out our "After"
print lxml.html.tostring(html)
Jeff
  • 3,879
  • 3
  • 26
  • 28
  • 2
    Thanks. I figure if folks are nice enough to help me, I gotta pay it forward and make it easy for them and others in the future :) – Jeff Apr 06 '12 at 16:09
  • 2
    `clean=re.sub('class=".*?"','', html)` - couldn't resist – polvoazul Apr 03 '16 at 06:23

3 Answers3

17

I can't test this at the moment but this appears to be the general idea

for tag in node.xpath('//*[@class]'):
    tag.attrib.pop('class')
Dan Roberts
  • 4,664
  • 3
  • 34
  • 43
  • 3
    Thanks Dan. Your code worked. I added my solution based on your suggestion here as an addendum to my question for others. – Jeff Apr 06 '12 at 15:55
3

lxml.html.clean.Cleaner does work, but needs proper configuration.

import lxml.html
from lxml.html import clean

html_string = '<p id="test" class="DumbClass">Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>'
tree = html.fromstring(html_string)

cleaner = html.clean.Cleaner()
cleaner.safe_attrs_only = True
cleaner.safe_attrs=frozenset(['id'])
cleaned = cleaner.clean_html(tree)
print(html.tostring(cleaned))

Result in :

b'<p id="test">Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>'
0

For lxml elment, the .attrib object contains the dict of attributes, you can just del it as you like.

Below is just a simple example to show how to replace an attribute name in html.

Given html:

<div><img src="http://www.example.com/logo.png"></div>

Code:

from lxml.html import fromstring
from lxml.html import _transform_result

html = "<div><img src=\"http://www.example.com/logo.png\"></div>"
doc = fromstring(html)
for el in doc.iter('img'):
    if "src" in el.attrib:
        el.set('data-src', el.get('src'))
        del el.attrib["src"]
print _transform_result(type(html), doc)

Result:

<div><img data-src="http://www.example.com/logo.png"></div>
hahakubile
  • 6,978
  • 4
  • 28
  • 18