views:

546

answers:

3

Can I combine these two blocks into one:

Edit: Any other method than combining loops like Yacoby did in the answer.

for tag in soup.findAll(['script', 'form']):
    tag.extract()

for tag in soup.findAll(id="footer"):
    tag.extract()

Also can I multiple blocks into one:

for tag in soup.findAll(id="footer"):
    tag.extract()

for tag in soup.findAll(id="content"):
    tag.extract()

for tag in soup.findAll(id="links"):
    tag.extract()

or may be there is some lambda expression where I can check whether in array, or any other simpler method.

Also how do I find tags with attribute class, as class is reserved keyword:

EDIT: this part is solved by the soup.findAll(attrs={'class': 'noprint'}):

for tag in soup.findAll(class="noprint"):
    tag.extract()
+4  A: 

I don't know if BeautifulSoup can do it more elegantly, but you could merge the two loops like so:

for tag in soup.findAll(['script', 'form']) + soup.findAll(id="footer"):
    tag.extract()

You can find classes like so (Documentation):

for tag in soup.findAll(attrs={'class': 'noprint'}):
    tag.extract()
Yacoby
Its working good, but doesn't look clean combining long loops ...+...+...+...+...+...+...+...Is there any other better method.
Priyank Bolia
A: 

The answer to the second part of your question is right there in the documentation:

Searching by CSS class

The attrs argument would be a pretty obscure feature were it not for one thing: CSS. It's very useful to search for a tag that has a certain CSS class, but the name of the CSS attribute, class, is also a Python reserved word.

You could search by CSS class with soup.find("tagName", { "class" : "cssClass" }), but that's a lot of code for such a common operation. Instead, you can pass a string for attrs instead of a dictionary. The string will be used to restrict the CSS class.

from BeautifulSoup import BeautifulSoup
soup = BeautifulSoup("""Bob's <b>Bold</b> Barbeque Sauce now available in 
                   <b class="hickory">Hickory</b> and <b class="lime">Lime</a>""")

soup.find("b", { "class" : "lime" })
# <b class="lime">Lime</b>

soup.find("b", "hickory")
# <b class="hickory">Hickory</b>
hop
uh... pardon me? why the downvote?
hop
+4  A: 

You can pass functions to .findall() like this:

soup.findAll(lambda tag: tag.name in ['script', 'form'] or tag['id'] == footer)

But you might be better off by first building a list of tags and then iterating over it:

tags = soup.findAll(['script', 'form'])
tags.extend(soup.findAll(id="footer"))

for tag in tags:
    tag.extract()

If you want to filter for several ids, you can use:

for tag in soup.findAll(lambda tag: tag.has_key('id') and
                                    tag['id'] in ['footer', 'content', 'links']):
    tag.extract()

A more specific approach would be to assign a lambda to the id parameter:

for tag in soup.findAll(id=lambda value: value in ['footer', 'content', 'links']):
    tag.extract()
hop
I am getting errors: SyntaxError: invalid syntax
Priyank Bolia
SyntaxError? Strange... you should get a TypeError.
hop
that fixed the TypeError
hop
for tag in soup.findAll(lambda tag: tag['id'] in ['footer', 'content', 'links']) does not work. KeyError: 'id' I am using Py2.6, it that helps.
Priyank Bolia
This works though: for tag in soup.findAll(id=lambda(value): value and value in ['catlinks', 'siteSub', 'contentSub'])
Priyank Bolia
i pasted the wrong version, sorry. this correction guards against tags that don't have the id attribute.
hop
your version works too, of course, but i wanted to show a more general approach
hop