I've come across a case where BeautifulSoup is concatenating text together--typically, I do not see this problem with other sites' navigation...
In [96]: nav_menu = """
<ul class="joomla-nav" id="topmenu">
<li id="current" class="selected item101"><a href="/" >Etusivu</a></li><li class="parent item107"><a href="/yritysesittely" >Yritys</a><ul><li class="item753"><a href="/yritys/yritysesittely" >Yritysesittely</a></li><li class="item755"><span class="separator">Kuvagalleria</span>
</li><li class="item754"><a href="/yritys/projektiesittely" >Projektiesittely</a></li></ul></li><li class="parent item108"><a class="tuotteetlinkki" href="/tuotteet" >Tuotteet</a><ul><li class="parent item317"><a href="/" >Rakentaminen</a><ul><li class="item110"><a href="/tuotteet/2012-02-17-10-36-23/mestaripihatto" >Mestaripihatto</a></li><li class="item111"><a href="/tuotteet/2012-02-17-10-36-23/rakennukset-ja-suunnittelu" >Rakentaminen ja suunnittelu</a></li><li class="item132"><a href="/tuotteet/2012-02-17-10-36-23/betonielementit" >Betonielementit</a></li><li class="item831"><a href="/tuotteet/2012-02-17-10-36-23/kattorakenteet-2" >Kattorakenteet</a></li><li class="item806"><a href="/tuotteet/2012-02-17-10-36-23/mestarikasvattamo" >Mestarikasvattamo</a></li><li class="item135"><a href="/tuotteet/2012-02-17-10-36-23/betoniritilat" >Betoniritilät</a></li></ul></li><li class="parent item318"><a href="#" >Pihattokalusteet ja -laitteet</a><ul><li class="item140"><a href="/tuotteet/2012-02-17-10-38-33/lypsy-ja-maidonkasittely" >GEA lypsy ja maidonkäsittely</a></li><li class="item270"><a href="/tuotteet/2012-02-17-10-38-33/pihattokalusteet" >GEA pihattokalusteet</a></li><li class="item145"><a href="/tuotteet/2012-02-17-10-38-33/ruokintalaitteet" >GEA ruokinta</a></li><li class="item146"><a href="/tuotteet/2012-02-17-10-38-33/lannanpoisto" >GEA lannanpoistolaitteet</a></li><li class="item147"><a href="/tuotteet/2012-02-17-10-38-33/varaosat-ja-tarvikkeet" >Varaosat ja tarvikkeet</a></li><li class="item141"><a href="/tuotteet/2012-02-17-10-38-33/merivirta-kalusteet" >Merivirta - kalusteet</a></li><li class="item785"><a href="/tuotteet/2012-02-17-10-38-33/2012-08-27-11-06-48" >Nautojen hyvinvointi</a></li></ul></li><li class="parent item814"><a href="#" >Karjatalous</a><ul><li class="item148"><a href="/tuotteet/2012-02-17-10-38-34/ilmanvaihto" >Ilmanvaihto</a></li><li class="item149"><a href="/tuotteet/2012-02-17-10-38-34/irtorehusiilot" >Irtorehusiilot</a></li><li class="item820"><a href="/tuotteet/2012-02-17-10-38-34/valaistus" >Valaistus</a></li><li class="item821"><a href="/tuotteet/2012-02-17-10-38-34/lietesaeilioen-verkkoaita" >Lietesäiliön verkkoaita</a></li></ul></li><li class="parent item320"><a href="/" >Lannankäsittely </a><ul><li class="item114"><a href="/tuotteet/2012-02-17-10-42-54/flygt-lietepumput" >Flygt-lietepumput</a></li></ul></li></ul></li><li class="item109"><a href="/jaelkimarkkinointilomake" >Jälkimarkkinointi</a></li><li class="item115"><a href="/yhteystiedot" >Yhteystiedot</a></li></ul>
"""
In [97]: nav_content = BeautifulSoup(nav_menu, "html.parser")
In [98]: nav_content.getText()
Out[98]: '\n\nEtusivuYritysYritysesittelyKuvagalleria\nProjektiesittelyTuotteetRakentaminenMestaripihattoRakentaminen ja suunnitteluBetonielementitKattorakenteetMestarikasvattamoBetoniritilätPihattokalusteet ja -laitteetGEA lypsy ja maidonkäsittelyGEA pihattokalusteetGEA ruokintaGEA lannanpoistolaitteetVaraosat ja tarvikkeetMerivirta - kalusteetNautojen hyvinvointiKarjatalousIlmanvaihtoIrtorehusiilotValaistusLietesäiliön verkkoaitaLannankäsittely Flygt-lietepumputJälkimarkkinointiYhteystiedot\n'
EDIT: Before commenting, please take note that the function getText()
returns a concatenated string: 'EtusivuYritysYritysesittely' and so on. However, these should be separate words: 'Etusivu Yritys Yritysesittely'; the code below correctly splits each word.
Per the post Python Beautifulsoup get_text() not getting all text, I also switched the parser to lxml
, but got similar results.
I've found the method outlined at BeautifulSoup Grab Visible Webpage Text to be a decent work around:
In [100]: def visible(element):
...: if element.parent.name in ['style', 'script', '[document]', 'head', 'title', 'meta']:
...: return False
...: elif isinstance(element,bs4.element.Comment):
...: return False
...: return True
...:
In [101]: visible_texts = list(filter(visible, nav_content.findAll(text=True)))
In [102]: ' '.join(visible_texts)
Out[102]: '\n Etusivu Yritys Yritysesittely Kuvagalleria \n Projektiesittely Tuotteet Rakentaminen Mestaripihatto Rakentaminen ja suunnittelu Betonielementit Kattorakenteet Mestarikasvattamo Betoniritilät Pihattokalusteet ja -laitteet GEA lypsy ja maidonkäsittely GEA pihattokalusteet GEA ruokinta GEA lannanpoistolaitteet Varaosat ja tarvikkeet Merivirta - kalusteet Nautojen hyvinvointi Karjatalous Ilmanvaihto Irtorehusiilot Valaistus Lietesäiliön verkkoaita Lannankäsittely Flygt-lietepumput Jälkimarkkinointi Yhteystiedot'
but am really struggling to figure out the difference. Of course I've read the documentation, but still haven't figured out how soup.findAll(text=True)
returns different results. For a moment I wondered if this behavior is due to the fact that the nav items are in Finnish (strings are weird!), but after translating the text to English it was clear that's not the issue. So signs point to the markup being malformed, but I'd really like to understand why before I commit to swapping out the code...any clarity is much appreciated.