BeautifulSoup get text ne supprime pas toutes les balises et JavaScript

j'essaie d'utiliser BeautifulSoup pour obtenir du texte à partir de pages web.

ci-dessous est un script que j'ai écrit pour le faire. Il prend deux arguments, le premier est le fichier HTML ou XML d'entrée, le deuxième fichier de sortie.

import sys
from bs4 import BeautifulSoup

def stripTags(s): return BeautifulSoup(s).get_text()

def stripTagsFromFile(inFile, outFile):
    open(outFile, 'w').write(stripTags(open(inFile).read()).encode("utf-8"))

def main(argv):
    if len(sys.argv) <> 3:
        print 'Usage:tt', sys.argv[0], 'input.html output.txt'
        return 1
    stripTagsFromFile(sys.argv[1], sys.argv[2])
    return 0

if __name__ == "__main__":
    sys.exit(main(sys.argv))

malheureusement, pour de nombreuses pages web, par exemple: http://www.greatjobsinteaching.co.uk/career/134112/Education-Manager-Location J'obtiens quelque chose comme ceci (Je ne montre que quelques premières lignes):

html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    Education Manager  Job In London With  Caleeda | Great Jobs In Teaching

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-15255540-21']);
_gaq.push(['_trackPageview']);
_gaq.push(['_trackPageLoadTime']);

y a-t-il un problème avec mon script? J'ai essayé de passer 'xml' comme second argument pour embellir le constructeur de Soup, ainsi que 'html5lib' et 'lxml', mais ça n'aide pas. Existe-t-il une alternative à BeautifulSoup qui fonctionnerait mieux pour cette tâche? Tout ce que je veux est d'extraire le texte qui sera rendu dans un navigateur pour cette page web.

Toute aide sera très appréciée.

7
demandé sur piokuc 2012-05-10 01:31:49

3 réponses

nltk clean_html() est assez bonne à ce!

en supposant que vous avez déjà votre html stocké dans une variable html comme

html = urllib.urlopen(address).read()

alors il suffit d'utiliser

import nltk
clean_text = nltk.clean_html(html)

mise à JOUR

Soutien pour clean_html et clean_url sera abandonné pour les futures versions de nltk. S'il vous plaît utiliser BeautifulSoup pour l'instant...il est très regrettable.

un exemple sur la façon de réaliser ceci est sur cette page:

BeatifulSoup4 get_text a toujours javascript

14
répondu elgehelge 2017-05-23 12:06:45

Voici une approche qui est basée sur la réponse ici: BeautifulSoup Grab Visible page Web texte par jbochi. Cette approche permet des commentaires intégrés dans des éléments contenant du texte de page, et fait un peu pour nettoyer la sortie en enlevant des lignes, en consolidant l'espace, etc.

html = urllib.urlopen(address).read()
soup = BeautifulSoup.BeautifulSoup(html)
texts = soup.findAll(text=True)

def visible_text(element):
    if element.parent.name in ['style', 'script', '[document]', 'head', 'title']:
        return ''
    result = re.sub('<!--.*-->|\r|\n', '', str(element), flags=re.DOTALL)
    result = re.sub('\s{2,}|&nbsp;', ' ', result)
    return result

visible_elements = [visible_text(elem) for elem in texts]
visible_text = ''.join(visible_elements)
print(visible_text)
1
répondu Dan Garant 2017-05-23 12:00:40

C'était le problème que j'ai. aucune solution ne semblait être en mesure de retourner le texte (le texte qui serait effectivement rendu dans le broswer web). D'autres solutions ont mentionné que BS n'est pas idéal pour le rendu et que html2text était une bonne approche. J'ai essayé html2text et nltk.clean_html et a été surpris par les résultats du timing donc pensé qu'ils justifiaient une réponse pour la postérité. Bien sûr, la vitesse delta peut fortement dépendre du contenu des données...

une réponse ici de @Helge était d'utiliser nltk de toutes choses.

import nltk

%timeit nltk.clean_html(html)
was returning 153 us per loop

cela fonctionnait vraiment bien pour retourner une chaîne de caractères Avec rendu html. Ce module nltk était plus rapide que même html2text, bien que html2text soit peut-être plus robuste.

betterHTML = html.decode(errors='ignore')
%timeit html2text.html2text(betterHTML)
%3.09 ms per loop
1
répondu Paul 2013-11-05 17:48:52