151 votes

Texte de la page Web visible de BeautifulSoup Grab

Fondamentalement, je veux utiliser BeautifulSoup à saisir strictement le texte visible sur une page web... Par exemple, cette page internet est de mon cas de test http://www.nytimes.com/2009/12/21/us/21storm.html .. Et en fait je veux juste obtenir le corps du texte (article) et peut-être même un peu les noms des onglets ici et là. Cependant, après avoir essayé cette suggestion http://stackoverflow.com/questions/1752662/beautifulsoup-easy-way-to-to-obtain-html-free-contents > qui renvoie beaucoup de balises html et des commentaires qui ne sont pas nécessaires.. je ne peux pas comprendre ce que sont les bons arguments pour findAll (http://www.crummy.com/software/BeautifulSoup/documentation.html#arg-limit) que j'ai besoin de faire ce dont j'ai besoin...

Alors, comment dois-je trouver tout texte visible à l'exclusion des scripts/commentaires/css/ordure...etc.. ??

298voto

jbochi Points 12280

Essaye ça:

 html = urllib.urlopen('http://www.nytimes.com/2009/12/21/us/21storm.html').read()
soup = BeautifulSoup.BeautifulSoup(html)
texts = soup.findAll(text=True)

def visible(element):
    if element.parent.name in ['style', 'script', '[document]', 'head', 'title']:
        return False
    elif re.match('<!--.*-->', str(element)):
        return False
    return True

visible_texts = filter(visible, texts)
 

40voto

nmgeek Points 31

La réponse approuvée de @jbochi ne fonctionne pas pour moi. L'appel à la fonction str () déclenche une exception car il ne peut pas coder les caractères non ascii de l'élément BeautifulSoup. Voici un moyen plus succinct de filtrer la page Web exemple en texte visible.

 html = open('21storm.html').read()
soup = BeautifulSoup(html)
[s.extract() for s in soup(['style', 'script', '[document]', 'head', 'title'])]
visible_text = soup.getText()
 

37voto

user2004922 Points 90
import urllib
from bs4 import BeautifulSoup

url = "https://www.yahoo.com"
html = urllib.urlopen(url).read()
soup = BeautifulSoup(html)

# kill all script and style elements
for script in soup(["script", "style"]):
    script.extract()    # rip it out

# get text
text = soup.get_text()

# break into lines and remove leading and trailing space on each
lines = (line.strip() for line in text.splitlines())
# break multi-headlines into a line each
chunks = (phrase.strip() for line in lines for phrase in line.split("  "))
# drop blank lines
text = '\n'.join(chunk for chunk in chunks if chunk)

print(text.encode('utf-8'))

11voto

Paul Points 1382

Je suis complètement en respect à l'aide de Magnifiques Soupe pour obtenir des rendus de contenu, mais il peut ne pas être l'outil idéal pour acquérir le rendu du contenu sur une page.

J'ai eu un problème similaire pour obtenir de rendu de contenu, ou le contenu visible dans un navigateur type. En particulier, j'ai eu beaucoup de peut-être, les cas atypiques de travailler avec un exemple simple ci-dessous. Dans ce cas, le non affichables balise est imbriquée dans une balise style, et n'est pas visible dans la plupart des navigateurs que j'ai vérifié. D'autres variantes existent, tels que la définition d'une classe de la balise affichage de réglage à aucun. Ensuite, à l'aide de cette classe pour la div.

<html>
  <title>  Title here</title>

  <body>

    lots of text here <p> <br>
    <h1> even headings </h1>

    <style type="text/css"> 
        <div > this will not be visible </div> 
    </style>


  </body>

</html>

Une solution posté ci-dessus est:

html = Utilities.ReadFile('simple.html')
soup = BeautifulSoup.BeautifulSoup(html)
texts = soup.findAll(text=True)
visible_texts = filter(visible, texts)
print(visible_texts)


[u'\n', u'\n', u'\n\n        lots of text here ', u' ', u'\n', u' even headings ', u'\n', u' this will not be visible ', u'\n', u'\n']

Cette solution a certainement des applications dans de nombreux cas et fait le travail très bien en général, mais dans le code html affiché ci-dessus, il conserve le texte qui n'est pas rendu. Après recherche DONC un couple de solutions est venu ici BeautifulSoup get_text de ne pas supprimer toutes les balises et JavaScript et voici le Rendu HTML en texte brut à l'aide de Python

J'ai essayé les deux solutions suivantes: html2text et nltk.clean_html et a été surpris par le timing ainsi, les résultats de la pensée qu'ils justifiaient une réponse pour la postérité. Bien sûr, les vitesses dépendent fortement du contenu des données...

Une réponse de @Helge a propos de l'utilisation de nltk de toutes choses.

import nltk

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

Il a vraiment bien travaillé pour renvoyer une chaîne de rendu html. Cette nltk module a été plus rapide que même html2text, mais peut-être html2text est plus robuste.

betterHTML = html.decode(errors='ignore')
%timeit html2text.html2text(betterHTML)
%3.09 ms per loop

2voto

Ewan Todd Points 5201

Le titre est à l'intérieur d'un <nyt_headline> balise imbriquée à l'intérieur d'un <h1> tag et un <div> balise avec l'id "article".

soup.findAll('nyt_headline', limit=1)

Devrait fonctionner.

Le corps de l'article est à l'intérieur d'un <nyt_text> balise imbriquée à l'intérieur d'un <div> balise avec l'id "articleBody". À l'intérieur de l' <nyt_text> élément, le texte lui-même est contenu dans <p> tags. Les Images ne sont pas à l'intérieur de ceux - <p> tags. Il est difficile pour moi d'expérimenter avec la syntaxe, mais je m'attends à un travail gratter à ressembler à quelque chose comme ça.

text = soup.findAll('nyt_text', limit=1)[0]
text.findAll('p')

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X