سؤال

أرغب في استخراج النص من ملف HTML باستخدام Python.أريد بشكل أساسي نفس الإخراج الذي سأحصل عليه إذا قمت بنسخ النص من المتصفح ولصقه في المفكرة.

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

تحديث html2text تبدو واعدة.فهو يتعامل مع كيانات HTML بشكل صحيح ويتجاهل JavaScript.ومع ذلك، فإنه لا ينتج نصًا عاديًا تمامًا؛إنه ينتج تخفيضًا والذي يجب بعد ذلك تحويله إلى نص عادي.يأتي بدون أمثلة أو وثائق، لكن الكود يبدو نظيفًا.


أسئلة ذات صلة:

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

المحلول

html2text هو برنامج Python الذي يقوم بعمل جيد في هذا.

نصائح أخرى

أفضل جزء من التعليمات البرمجية التي وجدتها لاستخراج النص دون الحصول على جافا سكريبت أو لا تريد الأشياء:

import urllib
from bs4 import BeautifulSoup

url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
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)

عليك فقط تثبيت QuactionSoup من قبل:

pip install beautifulsoup4

ملاحظة: NTLK لم يعد يدعم clean_html وظيفة

الإجابة الأصلية أدناه ، وبديل في أقسام التعليقات.


يستخدم NLTK

لقد أهدرت 4-5 ساعات في إصلاح المشكلات مع HTML2Text. لحسن الحظ يمكن أن أواجه NLTK.
إنه يعمل بطريقة سحرية.

import nltk   
from urllib import urlopen

url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"    
html = urlopen(url).read()    
raw = nltk.clean_html(html)  
print(raw)

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

from HTMLParser import HTMLParser
from re import sub
from sys import stderr
from traceback import print_exc

class _DeHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.__text = []

    def handle_data(self, data):
        text = data.strip()
        if len(text) > 0:
            text = sub('[ \t\r\n]+', ' ', text)
            self.__text.append(text + ' ')

    def handle_starttag(self, tag, attrs):
        if tag == 'p':
            self.__text.append('\n\n')
        elif tag == 'br':
            self.__text.append('\n')

    def handle_startendtag(self, tag, attrs):
        if tag == 'br':
            self.__text.append('\n\n')

    def text(self):
        return ''.join(self.__text).strip()


def dehtml(text):
    try:
        parser = _DeHTMLParser()
        parser.feed(text)
        parser.close()
        return parser.text()
    except:
        print_exc(file=stderr)
        return text


def main():
    text = r'''
        <html>
            <body>
                <b>Project:</b> DeHTML<br>
                <b>Description</b>:<br>
                This small script is intended to allow conversion from HTML markup to 
                plain text.
            </body>
        </html>
    '''
    print(dehtml(text))


if __name__ == '__main__':
    main()

فيما يلي نسخة من إجابة Xperroni التي اكتملت قليلاً. إنه يتخطى أقسام البرنامج النصي والأناقة ويترجم charrefs (على سبيل المثال ، ') وكيانات HTML (على سبيل المثال ، &).

ويشمل أيضًا محول عكسي من النص العادي إلى HTML.

"""
HTML <-> text conversions.
"""
from HTMLParser import HTMLParser, HTMLParseError
from htmlentitydefs import name2codepoint
import re

class _HTMLToText(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self._buf = []
        self.hide_output = False

    def handle_starttag(self, tag, attrs):
        if tag in ('p', 'br') and not self.hide_output:
            self._buf.append('\n')
        elif tag in ('script', 'style'):
            self.hide_output = True

    def handle_startendtag(self, tag, attrs):
        if tag == 'br':
            self._buf.append('\n')

    def handle_endtag(self, tag):
        if tag == 'p':
            self._buf.append('\n')
        elif tag in ('script', 'style'):
            self.hide_output = False

    def handle_data(self, text):
        if text and not self.hide_output:
            self._buf.append(re.sub(r'\s+', ' ', text))

    def handle_entityref(self, name):
        if name in name2codepoint and not self.hide_output:
            c = unichr(name2codepoint[name])
            self._buf.append(c)

    def handle_charref(self, name):
        if not self.hide_output:
            n = int(name[1:], 16) if name.startswith('x') else int(name)
            self._buf.append(unichr(n))

    def get_text(self):
        return re.sub(r' +', ' ', ''.join(self._buf))

def html_to_text(html):
    """
    Given a piece of HTML, return the plain text it contains.
    This handles entities and char refs, but not javascript and stylesheets.
    """
    parser = _HTMLToText()
    try:
        parser.feed(html)
        parser.close()
    except HTMLParseError:
        pass
    return parser.get_text()

def text_to_html(text):
    """
    Convert the given text to html, wrapping what looks like URLs with <a> tags,
    converting newlines to <br> tags and converting confusing chars into html
    entities.
    """
    def f(mo):
        t = mo.group()
        if len(t) == 1:
            return {'&':'&amp;', "'":'&#39;', '"':'&quot;', '<':'&lt;', '>':'&gt;'}.get(t)
        return '<a href="%s">%s</a>' % (t, t)
    return re.sub(r'https?://[^] ()"\';]+|[&\'"<>]', f, text)

يمكنك استخدام طريقة HTML2Text في مكتبة Stripogram أيضًا.

from stripogram import html2text
text = html2text(your_html_string)

لتثبيت stripogram Run Sudo easy_install stripogram

أعلم أن هناك الكثير من الإجابات بالفعل ، ولكن أكثر من غيرها أنيقة و بيثوني تم وصف الحل الذي وجدته ، جزئياً ، هنا.

from bs4 import BeautifulSoup

text = ''.join(BeautifulSoup(some_html_string, "html.parser").findAll(text=True))

تحديث

بناءً على تعليق فريزر ، إليك حل أكثر أناقة:

from bs4 import BeautifulSoup

clean_text = ''.join(BeautifulSoup(some_html_string, "html.parser").stripped_strings)

هناك مكتبة نمط لاستخراج البيانات.

http://www.clips.ua.ac.be/pages/pattern-web

يمكنك حتى تحديد العلامات التي يجب الاحتفاظ بها:

s = URL('http://www.clips.ua.ac.be').download()
s = plaintext(s, keep={'h1':[], 'h2':[], 'strong':[], 'a':['href']})
print s

ybarsing يقوم بعمل رائع. قُتل الويكي الغامق ، لذا يوجد موقع آخر حيث يوجد أمثلة على استخدام الخليط (مثال الرابط). أحد أسباب استثمار القليل من الوقت مع Pyparsing هو أنه كتب أيضًا دليلًا مختصرًا بشكل جيد جدًا منظمة O'Reilly غير مكلفة أيضًا.

بعد قولي هذا ، أستخدم BeautifulSoup كثيرًا وليس من الصعب التعامل مع مشكلات الكيانات ، يمكنك تحويلها قبل تشغيل BeautifulSoup.

حظا طيبا وفقك الله

هذا ليس بالضبط حل Python ، ولكنه سيقوم بتحويل النص الذي ستنشئه JavaScript في نص ، وأعتقد أنه مهم (على سبيل المثال google.com). تحتوي روابط المتصفح (وليس Lynx) على محرك JavaScript ، وسيقوم بتحويل المصدر إلى نص مع خيار -dump.

لذلك يمكنك أن تفعل شيئًا مثل:

fname = os.tmpnam()
fname.write(html_source)
proc = subprocess.Popen(['links', '-dump', fname], 
                        stdout=subprocess.PIPE,
                        stderr=open('/dev/null','w'))
text = proc.stdout.read()

بدلاً من وحدة HTMLParser ، تحقق من HTMLLIB. لديها واجهة مماثلة ، ولكنها تفعل المزيد من العمل من أجلك. (إنه قديم جدًا ، لذلك ليس من المفيد الكثير من حيث التخلص من JavaScript و CSS. يمكنك عمل فئة مشتقة ، ولكنها تضيف أساليبًا مثل Start_Script و End_style (انظر مستندات Python للحصول على التفاصيل) ، ولكنها صعبة للقيام بذلك بشكل موثوق من أجل HTML المشوه.) على أي حال ، إليك شيء بسيط يطبع النص العادي إلى وحدة التحكم

from htmllib import HTMLParser, HTMLParseError
from formatter import AbstractFormatter, DumbWriter
p = HTMLParser(AbstractFormatter(DumbWriter()))
try: p.feed('hello<br>there'); p.close() #calling close is not usually needed, but let's play it safe
except HTMLParseError: print ':(' #the html is badly malformed (or you found a bug)

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

import lxml.html as lh
from lxml.html.clean import clean_html

def lxml_to_text(html):
    doc = lh.fromstring(html)
    doc = clean_html(doc)
    return doc.text_content()

تثبيت html2text استخدام

PIP تثبيت HTML2Text

ومن بعد،

>>> import html2text
>>>
>>> h = html2text.HTML2Text()
>>> # Ignore converting links from HTML
>>> h.ignore_links = True
>>> print h.handle("<p>Hello, <a href='http://earth.google.com/'>world</a>!")
Hello, world!

حساء جميل يقوم بتحويل كيانات HTML. من المحتمل أن يكون أفضل رهان لك بالنظر إلى أن HTML غالبًا ما يكون عربات التي تجرها الدواب ومليئة بمشكلات ترميز Unicode و HTML. هذا هو الرمز الذي أستخدمه لتحويل HTML إلى نص RAW:

import BeautifulSoup
def getsoup(data, to_unicode=False):
    data = data.replace("&nbsp;", " ")
    # Fixes for bad markup I've seen in the wild.  Remove if not applicable.
    masssage_bad_comments = [
        (re.compile('<!-([^-])'), lambda match: '<!--' + match.group(1)),
        (re.compile('<!WWWAnswer T[=\w\d\s]*>'), lambda match: '<!--' + match.group(0) + '-->'),
    ]
    myNewMassage = copy.copy(BeautifulSoup.BeautifulSoup.MARKUP_MASSAGE)
    myNewMassage.extend(masssage_bad_comments)
    return BeautifulSoup.BeautifulSoup(data, markupMassage=myNewMassage,
        convertEntities=BeautifulSoup.BeautifulSoup.ALL_ENTITIES 
                    if to_unicode else None)

remove_html = lambda c: getsoup(c, to_unicode=True).getText(separator=u' ') if c else ""

أوصي بحزمة Python تسمى Goose-Extractor Goose ستحاول استخراج المعلومات التالية:

النص الرئيسي لمقال الصورة الرئيسية للمقالة أي أفلام YouTube/Vimeo مضمنة في مقالة الوصف الوصف

أكثر :https://pypi.python.org/pypi/Goose-extractor/

خيار آخر هو تشغيل HTML من خلال متصفح الويب القائم على النص وتفريغه. على سبيل المثال (باستخدام Lynx):

lynx -dump html_to_convert.html > converted_html.txt

يمكن القيام بذلك في نص Python على النحو التالي:

import subprocess

with open('converted_html.txt', 'w') as outputFile:
    subprocess.call(['lynx', '-dump', 'html_to_convert.html'], stdout=testFile)

لن يمنحك النص بالضبط من ملف HTML ، ولكن بناءً على حالة الاستخدام الخاصة بك ، قد يكون من الأفضل إخراج HTML2Text.

حل آخر غير بايثون: مكتب Libre:

soffice --headless --invisible --convert-to txt input1.html

السبب في أنني أفضل هذا على بدائل أخرى هو أن كل فقرة HTML يتم تحويلها إلى سطر نص واحد (بدون كسر خط) ، وهو ما كنت أبحث عنه. طرق أخرى تتطلب ما بعد المعالجة. لا ينتج Lynx ناتجًا رائعًا ، ولكن ليس بالضبط ما كنت أبحث عنه. علاوة على ذلك ، يمكن استخدام مكتب Libre للتحويل من جميع أنواع التنسيقات ...

لقد حاول أي شخص bleach.clean(html,tags=[],strip=True) مع تبييض؟ إنه يعمل بالنسبة لي.

أعلم أن هناك الكثير من الإجابات هنا بالفعل ولكن أعتقد Newspaper3k يستحق أيضا ذكر. كنت بحاجة مؤخرًا إلى إكمال مهمة مماثلة لاستخراج النص من مقالات على الويب ، وقد قامت هذه المكتبة بعمل ممتاز في تحقيق ذلك حتى الآن في اختباراتي. يتجاهل النص الموجود في عناصر القائمة وأشرطة جانبية وكذلك أي JavaScript يظهر على الصفحة كطلبات OP.

from newspaper import Article

article = Article(url)
article.download()
article.parse()
article.text

إذا كان لديك بالفعل ملفات HTML التي تم تنزيلها ، فيمكنك القيام بشيء مثل هذا:

article = Article('')
article.set_html(html)
article.parse()
article.text

حتى أنه يحتوي على عدد قليل من ميزات NLP لتلخيص مواضيع المقالات:

article.nlp()
article.summary

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

يمكن تشغيل Tika ك الخادم, ، هو تافهة لتشغيل / نشر في حاوية Docker ، ومن هناك يمكن الوصول إليها عبر روابط بيثون.

بطريقة بسيطة

import re

html_text = open('html_file.html').read()
text_filtered = re.sub(r'<(.*?)>', '', html_text)

يجد هذا الرمز جميع أجزاء HTML_Text بدأت بـ "<" وينتهي بـ ">" واستبدل كل شيء موجود بسلسلة فارغة

إجابة @ PeYoTIL باستخدام BeautifulSoup وإزالة محتوى الأسلوب والنص لم تنجح معي.لقد حاولت ذلك باستخدام decompose بدلاً من extract لكنها ما زالت لا تعمل.لذلك قمت بإنشاء ملف خاص بي والذي يقوم أيضًا بتنسيق النص باستخدام ملف <p> العلامات والاستبدال <a> العلامات مع الرابط href.تتواءم أيضًا مع الروابط الموجودة داخل النص.متواجد في هذا الجوهر مع مستند اختبار مضمن.

from bs4 import BeautifulSoup, NavigableString

def html_to_text(html):
    "Creates a formatted text email message as a string from a rendered html template (page)"
    soup = BeautifulSoup(html, 'html.parser')
    # Ignore anything in head
    body, text = soup.body, []
    for element in body.descendants:
        # We use type and not isinstance since comments, cdata, etc are subclasses that we don't want
        if type(element) == NavigableString:
            # We use the assumption that other tags can't be inside a script or style
            if element.parent.name in ('script', 'style'):
                continue

            # remove any multiple and leading/trailing whitespace
            string = ' '.join(element.string.split())
            if string:
                if element.parent.name == 'a':
                    a_tag = element.parent
                    # replace link text with the link
                    string = a_tag['href']
                    # concatenate with any non-empty immediately previous string
                    if (    type(a_tag.previous_sibling) == NavigableString and
                            a_tag.previous_sibling.string.strip() ):
                        text[-1] = text[-1] + ' ' + string
                        continue
                elif element.previous_sibling and element.previous_sibling.name == 'a':
                    text[-1] = text[-1] + ' ' + string
                    continue
                elif element.parent.name == 'p':
                    # Add extra paragraph formatting newline
                    string = '\n' + string
                text += [string]
    doc = '\n'.join(text)
    return doc

في Python 3.x ، يمكنك القيام بذلك بطريقة سهلة للغاية عن طريق استيراد حزم "Imaplib" و "البريد الإلكتروني". على الرغم من أن هذا منشور أقدم ولكن ربما يمكن أن تساعد إجابتي القادمين الجدد في هذا المنشور.

status, data = self.imap.fetch(num, '(RFC822)')
email_msg = email.message_from_bytes(data[0][1]) 
#email.message_from_string(data[0][1])

#If message is multi part we only want the text version of the body, this walks the message and gets the body.

if email_msg.is_multipart():
    for part in email_msg.walk():       
        if part.get_content_type() == "text/plain":
            body = part.get_payload(decode=True) #to control automatic email-style MIME decoding (e.g., Base64, uuencode, quoted-printable)
            body = body.decode()
        elif part.get_content_type() == "text/html":
            continue

الآن يمكنك طباعة متغير الجسم وسيكون بتنسيق النص العادي :) إذا كان جيدًا بما يكفي لك ، فسيكون من الجيد تحديده كإجابة مقبولة.

أفضل عمل بالنسبة لي هو inscripts.

https://github.com/weblyzard/inscriptis

import urllib.request
from inscriptis import get_text

url = "http://www.informationscience.ch"
html = urllib.request.urlopen(url).read().decode('utf-8')

text = get_text(html)
print(text)

النتائج جيدة حقا

يمكنك استخراج النص فقط من HTML مع BeautifulSoup

url = "https://www.geeksforgeeks.org/extracting-email-addresses-using-regular-expressions-python/"
con = urlopen(url).read()
soup = BeautifulSoup(con,'html.parser')
texts = soup.get_text()
print(texts)

في حين أن الكثير من الأشخاص الذين ذكروا باستخدام Regex لتجريد علامات HTML ، هناك الكثير من الجوانب السلبية.

فمثلا:

<p>hello&nbsp;world</p>I love you

يجب تحليلها إلى:

Hello world
I love you

إليك مقتطف توصلت إليه ، يمكنك تناوله لتلبية احتياجاتك المحددة ، ويعمل مثل السحر

import re
import html
def html2text(htm):
    ret = html.unescape(htm)
    ret = ret.translate({
        8209: ord('-'),
        8220: ord('"'),
        8221: ord('"'),
        160: ord(' '),
    })
    ret = re.sub(r"\s", " ", ret, flags = re.MULTILINE)
    ret = re.sub("<br>|<br />|</p>|</div>|</h\d>", "\n", ret, flags = re.IGNORECASE)
    ret = re.sub('<.*?>', ' ', ret, flags=re.DOTALL)
    ret = re.sub(r"  +", " ", ret)
    return ret

إليك الرمز الذي أستخدمه بشكل منتظم.

from bs4 import BeautifulSoup
import urllib.request


def processText(webpage):

    # EMPTY LIST TO STORE PROCESSED TEXT
    proc_text = []

    try:
        news_open = urllib.request.urlopen(webpage.group())
        news_soup = BeautifulSoup(news_open, "lxml")
        news_para = news_soup.find_all("p", text = True)

        for item in news_para:
            # SPLIT WORDS, JOIN WORDS TO REMOVE EXTRA SPACES
            para_text = (' ').join((item.text).split())

            # COMBINE LINES/PARAGRAPHS INTO A LIST
            proc_text.append(para_text)

    except urllib.error.HTTPError:
        pass

    return proc_text

أتمنى أن يساعد ذلك.

تعليق Libreoffice Conster له جدارة لأن الطلب يمكن أن يوظف وحدات الماكرو للبيثون. يبدو أنه يوفر فوائد متعددة للإجابة على هذا السؤال وتعزيز قاعدة الكلي من libreoffice. إذا كان هذا القرار عبارة عن تطبيق لمرة واحدة ، بدلاً من استخدامه كجزء من برنامج إنتاج أكبر ، فإن فتح HTML في الكاتب وحفظ الصفحة كما يبدو أن النص يحل المشكلات التي تمت مناقشتها هنا.

طريق بيرل (آسف يا أمي ، لن أفعل ذلك أبدًا في الإنتاج).

import re

def html2text(html):
    res = re.sub('<.*?>', ' ', html, flags=re.DOTALL | re.MULTILINE)
    res = re.sub('\n+', '\n', res)
    res = re.sub('\r+', '', res)
    res = re.sub('[\t ]+', ' ', res)
    res = re.sub('\t+', '\t', res)
    res = re.sub('(\n )+', '\n ', res)
    return res

أنا أحقق ذلك شيئًا كهذا.

>>> import requests
>>> url = "http://news.bbc.co.uk/2/hi/health/2284783.stm"
>>> res = requests.get(url)
>>> text = res.text
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top