Beautiful Soup adding multiple tags to words in paragraph

Viewed 83

I am trying to add a ruby tag for every word in a paragraph. The html doc looks somthing like this

<div class = "bodyTxt">
 <p>Lorem ipsum dolor sit amet, no postea maiorum sadipscing quo, ad illum percipitur 
    inciderint usu. Rebum vidisse apeirian an vel. Vis nostro iudicabit instructior ex, ne eos 
    facer iudicabit. Nec ludus ridens facete ea, ad vix populo adversarium, te mel meis malis 
    mundi.
 </p>
 <p>Putant omittam no qui, ei sed esse saperet. Te alii unum ignota has, vix ei maiestatis 
    expetendis. Et error iracundia argumentum vim, mel maiestatis delicatissimi ex. Sit altera 
    vivendo ad, vis dolorem consetetur et, fabulas admodum sadipscing te est. Sit et senserit 
    consequuntur interpretaris, et sale ornatus consequat has, modus aeque omittantur has te.
 </p>
</div>

and after I want it to look like this

  <div class = "bodyTxt">
 <p><ruby>Lorem</ruby> <ruby>ipsum </ruby><ruby>dolor</ruby> <ruby>sit</ruby> 
    <ruby>amet</ruby>,<ruby>no</ruby> <ruby>postea</ruby> <ruby>maiorum</ruby> 
    <ruby>sadipscing/<ruby> <ruby>quo</ruby>, 
    <ruby>ad</ruby> <ruby>illum</ruby> <ruby>percipitur<ruby> 
 </p>
 <p><ruby>Putant</ruby> <ruby>omittam</ruby> <ruby>no</ruby> <ruby>qui</ruby>, <ruby>ei</ruby> 
    <ruby>sed</ruby> <ruby>esse</ruby> <ruby>saperet</ruby>
</div>

What i tried to do is first get the text from the bodyText class then just add the tags but problem is it is only adding the tags at the begging and end of each paragraph

 for textSection in bodyText.stripped_strings:
    RubyTag = soup.new_tag('ruby')
    RubyTag.string = textSection
    textSection.replace_with(RubyTag)

I also tried iterating through the paragraphs and just getting every word and adding the tags like so

for textSection in bodyText.stripped_strings:
  for word in textSection:
    RubyTag = soup.new_tag('ruby')
    RubyTag.string = word
    textSection.replace_with(RubyTag)

but this throws an error AttributeError: 'str' object has no attribute 'replace_with'

1 Answers

Looking at the documentation one way might be to leverage new_tag() and decompose(). As you want to treat punctuation also within separate tags then regex can be used to generate the content for each new ruby tag. I used the regex from @user3850.

Create a new p tag, during a loop, and append your ruby tags, you can then decompose() the original p tag.

from bs4 import BeautifulSoup as bs
import re

html = '''<div class = "bodyTxt">
 <p>Lorem ipsum dolor sit amet, no postea maiorum sadipscing quo, ad illum percipitur 
    inciderint usu. Rebum vidisse apeirian an vel. Vis nostro iudicabit instructior ex, ne eos 
    facer iudicabit. Nec ludus ridens facete ea, ad vix populo adversarium, te mel meis malis 
    mundi.
 </p>
 <p>Putant omittam no qui, ei sed esse saperet. Te alii unum ignota has, vix ei maiestatis 
    expetendis. Et error iracundia argumentum vim, mel maiestatis delicatissimi ex. Sit altera 
    vivendo ad, vis dolorem consetetur et, fabulas admodum sadipscing te est. Sit et senserit 
    consequuntur interpretaris, et sale ornatus consequat has, modus aeque omittantur has te.
 </p>
</div>'''

soup = bs(html, 'lxml')

for t in soup.select('.bodyTxt > p'):
    
    parent = soup.new_tag('p')
    t.insert_after(parent)
    
    for i in [j for j in re.findall(r"[\w]+|[^\s\w]", t.text)]:
        new_tag = soup.new_tag('ruby')
        new_tag.string = i
        parent.append(new_tag)
    t.decompose()
print(soup.prettify())
Related