سؤال

وأساسا، أريد أن استخدام BeautifulSoup لانتزاع بدقة <م> النص المرئي على صفحة ويب. على سبيل المثال، صفحة الويب هذه عبارة حالتي الاختبار. وأريد أساسا إلى هناك فقط الحصول على النص الأساسي (المادة) وربما عدد قليل من الأسماء التبويب هنا و. لقد حاولت على اقتراح في هذا SO السؤال أن عودة الكثير من علامات <script> والتعليقات أتش تي أم أل التي لا أريد. أنا لا يمكن معرفة الحجج ولست بحاجة لوظيفة findAll() من أجل مجرد الحصول على نصوص واضحة على صفحة ويب.

وهكذا، وكيف ينبغي أن تجد كل النص المرئي باستثناء مخطوطات، تعليقات، المغلق الخ.؟

هل كانت مفيدة؟

المحلول

وجرب هذا:

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 لا يعمل بالنسبة لي. استدعاء دالة شارع () تثير استثناء لأنه لا يمكن ترميز الأحرف غير 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'))

وأنا أحترم تماما باستخدام حساء جميل للحصول على المحتويات المقدمة، ولكن قد لا يكون حزمة مثالية لاكتساب المحتويات المقدمة على الصفحة.

كان

ولدي مشكلة مماثلة للحصول على المحتويات المقدمة، أو المحتوى المرئي في متصفح نموذجي. وعلى وجه الخصوص كان لي العديد من الحالات ربما شاذة للعمل مع مثل هذا المثال البسيط أدناه. في هذه الحالة هو تداخل علامة غير للعرض في علامة الأسلوب، وغير مرئية في كثير من المتصفحات التي راجعت. توجد اختلافات أخرى مثل تحديد فئة بطاقة شاشة الإعداد للا شيء. ثم استخدام هذه الفئة للشعبة.

<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']

وهذا الحل له بالتأكيد تطبيقات في كثير من الحالات ويقوم بهذه المهمة بشكل جيد جدا بشكل عام ولكن في أتش تي أم أل نشر فوقه يحتفظ النص الذي لا يتم تقديمها. بعد البحث SO جاءت بضع الحلول هنا BeautifulSoup get_text لا تجريد جميع العلامات وجافا سكريبت و هنا HTML المعادين إلى نص عادي باستخدام بيثون

وحاولت كل من هذه الحلول: html2text وnltk.clean_html وفوجئ نتائج توقيت لذلك يعتقد أنهم يبرر جوابا للأجيال القادمة. بطبيعة الحال، فإن سرعات تعتمد بدرجة كبيرة على محتويات البيانات ...

وكانت إحدى الإجابات هنا منHelge حول استخدام NLTK من كل شيء.

import nltk

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

وانها عملت بشكل جيد حقا لإرجاع سلسلة مع أتش تي أم أل المقدمة. وكانت هذه الوحدة 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)

إذا كنت تهتم الأداء، وهنا بطريقة أكثر كفاءة آخر:

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 بحيث يمكنك التحقق من الوالدين اسم العلامة مباشرة، دون المرور عبر حلقات متعددة.

والعنوان هو داخل علامة <nyt_headline> التي تداخل داخل علامة <h1> وعلامة <div> بالمعرف "المادة".

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')

وحين، وأود أن تماما أقترح استخدام-حساء جميلة بشكل عام، إذا كان هناك من يبحث لعرض الأجزاء الظاهرة من أتش تي أم أل تالف (على سبيل المثال حيث لديك لمجرد شريحة أو سطر من صفحات الإنترنت) لأي سبب،، فإن ما يلي إزالة المحتوى بين العلامات < و>:

import re   ## only use with malformed html - this is not efficient
def display_visible_html_using_re(text):             
    return(re.sub("(\<.*?\>)", "",text))
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top