BeautifulSoup Захватить Видимый Текст Веб-Страницы
в принципе, я хочу использовать BeautifulSoup, чтобы захватить строго видимый текст на странице. Например, этот сайт мой тест. И я в основном хочу просто получить основной текст (статью) и, возможно, даже несколько имен вкладок здесь и там. Я пробовал предложение в этом и что возвращает много <script>
теги и HTML-комментарии, которые я не хочу. Я не могу понять аргументы, которые мне нужны для функции findAll()
in чтобы просто получить видимые тексты на веб-странице.
Итак, как я должен найти весь видимый текст, исключая скрипты, комментарии, css и т. д.?
8 ответов:
попробуйте это:
from bs4 import BeautifulSoup from bs4.element import Comment import urllib.request def tag_visible(element): if element.parent.name in ['style', 'script', 'head', 'title', 'meta', '[document]']: return False if isinstance(element, Comment): return False return True def text_from_html(body): soup = BeautifulSoup(body, 'html.parser') texts = soup.findAll(text=True) visible_texts = filter(tag_visible, texts) return u" ".join(t.strip() for t in visible_texts) html = urllib.request.urlopen('http://www.nytimes.com/2009/12/21/us/21storm.html').read() print(text_from_html(html))
утвержденный ответ от @jbochi не работает для меня. Вызов функции str () вызывает исключение, поскольку он не может кодировать символы, отличные от ascii, в элементе BeautifulSoup. Вот более краткий способ фильтрации примера веб-страницы в видимый текст.
html = open('21storm.html').read() soup = BeautifulSoup(html) [s.extract() for s in soup(['style', 'script', '[document]', 'head', 'title'])] visible_text = soup.getText()
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'))
Я полностью уважаю использование красивого супа для получения визуализированного контента, но это может быть не идеальный пакет для получения визуализированного контента на странице.
у меня была аналогичная проблема, чтобы получить визуализированный контент или видимый контент в обычном браузере. В частности, у меня было много, возможно, нетипичных случаев для работы с таким простым примером ниже. В этом случае не отображаемый тег вложен в тег стиля и не виден во многих браузерах, которые я проверил. Другой существуют различные варианты, такие как определение отображения параметра тега класса в none. Затем с помощью этого класса для 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>
одно решение написал выше:
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']
это решение, безусловно, имеет приложения во многих случаях и делает работу довольно хорошо в целом, но в html, опубликованном выше, он сохраняет текст, который не отображается. После поиска так что пара решений пришла сюда BeautifulSoup get_text не удаляет все теги и JavaScript и здесь визуализация HTML в обычный текст с помощью Python
Я пробовал оба эти решения: html2text и nltk.clean_html и был удивлен результатами синхронизации, поэтому думал, что они гарантируют ответ для потомков. Конечно, скорость сильно зависит от содержания данных...
один ответ здесь от @Helge был об использовании nltk всех вещей.
import nltk %timeit nltk.clean_html(html) was returning 153 us per loop
он работал очень хорошо, чтобы вернуть строку с визуализированным html. Этот модуль nltk был быстрее чем даже html2text, хотя, возможно, html2text является более надежным.
betterHTML = html.decode(errors='ignore') %timeit html2text.html2text(betterHTML) %3.09 ms per loop
С помощью BeautifulSoup самый простой способ с меньшим количеством кода, чтобы просто получить строки, без пустых строк и дурь.
tag = <Parent_Tag_that_contains_the_data> soup = BeautifulSoup(tag, 'html.parser') for i in soup.stripped_strings: print repr(i)
название находится внутри
<nyt_headline>
тег, который вложен внутри<h1>
тег и<div>
тег с идентификатором "article".soup.findAll('nyt_headline', limit=1)
должны работать.
тело статьи находится внутри
<nyt_text>
тег, который вложен внутри<div>
тег с идентификатором "articleBody". Внутри<nyt_text>
элемент, сам текст находится внутри<p>
теги. Изображения не находятся внутри этих<p>
теги. Мне сложно экспериментировать с синтаксисом, но я ожидаю работы скрести, чтобы выглядеть примерно так.text = soup.findAll('nyt_text', limit=1)[0] text.findAll('p')
В то время как я бы полностью предложил использовать beautiful-soup в целом, если кто-то хочет отобразить видимые части искаженного html (например, где у вас есть только сегмент или строка веб-страницы) по какой-либо причине, следующее удалит содержимое между
<
и>
теги:import re ## only use with malformed html - this is not efficient def display_visible_html_using_re(text): return(re.sub("(\<.*?\>)", "",text))
Если вы заботитесь о производительности, вот еще один более эффективный способ:
import re INVISIBLE_ELEMS = ('style', 'script', 'head', 'title') RE_SPACES = re.compile(r'\s{3,}') def visible_texts(soup): """ get visible text from a document """ text = ' '.join([ s for s in soup.strings if s.parent.name not in INVISIBLE_ELEMS ]) # collapse multiple spaces to two spaces. return RE_SPACES.sub(' ', text)
soup.strings
является итератором, и он возвращаетNavigableString
Так что вы можете проверить имя тега родителя непосредственно, не проходя через несколько циклов.