HTML को Python में स्ट्रिंग्स से स्ट्रिप करें


268
from mechanize import Browser
br = Browser()
br.open('http://somewebpage')
html = br.response().readlines()
for line in html:
  print line

HTML फ़ाइल में एक लाइन प्रिंट करते समय, मैं केवल प्रत्येक HTML तत्व की सामग्री को दिखाने का एक तरीका खोजने की कोशिश कर रहा हूं, न कि केवल प्रारूपण। यदि यह पता चलता है '<a href="whatever.com">some text</a>', तो यह केवल 'कुछ पाठ', '<b>hello</b>'प्रिंट 'हैलो' आदि को मुद्रित करेगा, ऐसा करने के बारे में कोई कैसे जाएगा?


16
एक महत्वपूर्ण विचार यह है कि HTML संस्थाओं (जैसे &amp;) को कैसे संभालना है । आप या तो 1) उन्हें टैग के साथ हटा सकते हैं (अक्सर अवांछनीय, और अनावश्यक के रूप में वे सादे पाठ के बराबर होते हैं), 2) उन्हें अपरिवर्तित छोड़ दें (यदि उपयुक्त पाठ एचटीएमएल संदर्भ में वापस जा रहा है तो एक उपयुक्त समाधान) या 3 ) उन्हें सादे पाठ को डिकोड करें (यदि छीन हुआ पाठ डेटाबेस या किसी अन्य गैर-HTML संदर्भ में जा रहा है, या यदि आपका वेब ढांचा स्वचालित रूप से आपके लिए पाठ से बचने वाला HTML निष्पादित करता है)।
सोरेन लोर्बोर्ग

2
@ SørenLøvborg बिंदु 2 के लिए): stackoverflow.com/questions/753052/…
रॉबर्ट

2
यहां शीर्ष उत्तर, जो मार्च 2014 तक Django परियोजना द्वारा उपयोग किया गया था, क्रॉस-साइट स्क्रिप्टिंग के खिलाफ असुरक्षित पाया गया है - एक उदाहरण के लिए उस लिंक को देखें जो इसके माध्यम से बनाता है। मैं ब्लीच.क्लीन (), मार्कअपसेफ़ के स्ट्रिपैग, या RECENT Django के स्ट्रिप_टैग का उपयोग करने की सलाह देता हूं।
२२

जवाबों:


418

मैंने हमेशा HTML टैग को हटाने के लिए इस फ़ंक्शन का उपयोग किया, क्योंकि इसके लिए केवल पायथन stdlib की आवश्यकता होती है:

पायथन 3 के लिए:

from io import StringIO
from html.parser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        super().__init__()
        self.reset()
        self.strict = False
        self.convert_charrefs= True
        self.text = StringIO()
    def handle_data(self, d):
        self.text.write(d)
    def get_data(self):
        return self.text.getvalue()

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

पायथन 2 के लिए:

from HTMLParser import HTMLParser
from StringIO import StringIO

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.text = StringIO()
    def handle_data(self, d):
        self.text.write(d)
    def get_data(self):
        return self.text.getvalue()

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

3
दो साल + बाद में, एक ही मुद्दे का सामना करना पड़ रहा है, और यह कहीं अधिक सुरुचिपूर्ण समाधान है। मेरे द्वारा किए गए परिवर्तन के बजाय केवल स्वयं को वापस करना था। एक सूची के रूप में, इसलिए मैं तत्व सामग्री के माध्यम से कदम रख सकता था।
निर्देश

47
ध्यान दें कि यह HTML इकाइयाँ (जैसे &amp;) टैग्स को भी स्ट्रिप्स करता है।
सोरेन लोर्बोर्ग

30
@ सूर्या मुझे यकीन है कि आपने इसे देखा है
tkone

8
महान जवाब के लिए धन्यवाद। पायथन (3.2+) के नए संस्करणों का उपयोग करने वाले आप में से एक के लिए ध्यान देने वाली बात यह है कि आपको मूल वर्ग के __init__फ़ंक्शन को कॉल करना होगा। यहाँ देखें: stackoverflow.com/questions/11061058/...
छद्मलेबल

10
Html एंटिटीज़ (यूनिकोड में परिवर्तित) रखने के लिए, मैंने दो पंक्तियाँ जोड़ीं : parser = HTMLParser()और html = parser.unescape(html)strip_tags फ़ंक्शन की शुरुआत में।
जेम्स डोएप्प - पिहेंटाग्यू

156

मैंने उन मामलों के बारे में ज्यादा नहीं सोचा है, जो याद आएंगे, लेकिन आप एक साधारण रेगेक्स कर सकते हैं:

re.sub('<[^<]+?>', '', text)

उन लोगों के लिए जो रेगेक्स को नहीं समझते हैं, यह एक स्ट्रिंग की खोज करते हैं <...>, जहां आंतरिक सामग्री एक या अधिक ( +) वर्णों से बनी होती है जो कि नहीं है <। इसका ?मतलब है कि यह सबसे छोटी स्ट्रिंग से मेल खाएगा। उदाहरण के लिए <p>Hello</p>, यह मेल खाएगा <'p>और </p>अलग से ?। इसके बिना, यह पूरे स्ट्रिंग से मेल खाएगा <..Hello..>

यदि <html (उदा। 2 < 3) में गैर-टैग दिखाई देता है , तो इसे &...वैसे भी भागने के क्रम के रूप में लिखा जाना चाहिए ताकि ^<अनावश्यक हो।


10
यह लगभग वैसा ही है जैसा कि Django की स्ट्रिप_टैग्स करती है।
ब्लू

10
ध्यान दें कि यह HTML संस्थाओं (जैसे &amp;) आउटपुट में अपरिवर्तित छोड़ देता है ।
सोरेन लोर्बोर्ग

35
कोई भी इस विधि को कुछ इस तरह से कर सकता है: <स्क्रिप्ट <स्क्रिप्ट >> अलर्ट ("हाय!") << / स्क्रिप्ट> / स्क्रिप्ट>

19
यह मत करो! जैसा कि @ जूलियो गार्सिया कहते हैं, यह सुरक्षित नहीं है!
rescdsk

18
लोग, HTML स्ट्रिपिंग और HTML सैनिटाइजिंग को भ्रमित नहीं करते हैं। हां, टूटे या दुर्भावनापूर्ण इनपुट के लिए यह उत्तर इसमें HTML टैग के साथ आउटपुट उत्पन्न कर सकता है। यह अभी भी HTML टैग्स को छीनने के लिए एक पूरी तरह से वैध दृष्टिकोण है। हालाँकि , HTML टैग्स को अलग करना उचित HTML सैनिटाइजिंग के लिए एक वैध प्रतिस्थापन नहीं है। नियम कठिन नहीं है: जब भी आप HTML आउटपुट में एक सादा-पाठ स्ट्रिंग सम्मिलित करते हैं, तो आपको हमेशा HTML से इसे बचाना चाहिए (उपयोग करना cgi.escape(s, True)), भले ही आप "जानते" हों कि इसमें HTML शामिल नहीं है (उदाहरण के लिए, क्योंकि आपने HTML सामग्री छीन ली है) । हालांकि, यह ओपी के बारे में नहीं पूछा गया है।
सोरेन लोर्बोर्ग

76

आप ब्यूटीफुल get_text()फीचर का इस्तेमाल कर सकते हैं ।

from bs4 import BeautifulSoup

html_str = '''
<td><a href="http://www.fakewebsite.com">Please can you strip me?</a>
<br/><a href="http://www.fakewebsite.com">I am waiting....</a>
</td>
'''
soup = BeautifulSoup(html_str)

print(soup.get_text()) 
#or via attribute of Soup Object: print(soup.text)

पार्सर को स्पष्ट रूप से निर्दिष्ट करना उचित है , उदाहरण के BeautifulSoup(html_str, features="html.parser")लिए, आउटपुट प्रजनन योग्य होने के लिए।


32

लघु संस्करण!

import re, cgi
tag_re = re.compile(r'(<!--.*?-->|<[^>]*>)')

# Remove well-formed tags, fixing mistakes by legitimate users
no_tags = tag_re.sub('', user_input)

# Clean up anything else by escaping
ready_for_web = cgi.escape(no_tags)

रेगेक्स स्रोत: मार्कअपसेफ़ । उनका संस्करण HTML संस्थाओं को भी संभालता है, जबकि यह त्वरित नहीं है।

मैं केवल टैग क्यों नहीं छीन सकता और इसे छोड़ दूं?

यह लोगों को <i>italicizing</i>चीजों से दूर रखने के लिए एक चीज है , बिना किसी चीज को iइधर-उधर तैरते हुए छोड़ना । लेकिन यह मनमाना इनपुट लेने और इसे पूरी तरह से हानिरहित बनाने के लिए एक और है। इस पृष्ठ की अधिकांश तकनीकें अस्पष्ट टिप्पणियों ( <!--) और कोण-कोष्ठक जैसी चीजों को छोड़ देंगी जो टैग का हिस्सा नहीं हैं ()blah <<<><blah ) बरकरार हैं। HTMLParser संस्करण भी पूर्ण टैग छोड़ सकते हैं, अगर वे एक असंगत टिप्पणी के अंदर हैं।

यदि आपका टेम्पलेट है तो क्या होगा {{ firstname }} {{ lastname }}? firstname = '<a'और lastname = 'href="http://evil.com/">'इस पृष्ठ पर हर टैग स्ट्रिपर (@Medeiros को छोड़कर!) के माध्यम से जाने देंगे, क्योंकि वे अपने आप ही पूर्ण टैग नहीं हैं। सामान्य HTML टैग्स को अलग करना पर्याप्त नहीं है।

Django के strip_tags, इस प्रश्न के शीर्ष उत्तर का एक उन्नत (अगला शीर्षक) देखें, निम्नलिखित चेतावनी देता है:

परिणामी स्ट्रिंग HTML सुरक्षित होने के बारे में बिल्कुल कोई गारंटी नहीं दी गई है। तो strip_tagsपहले से बचने के बिना कॉल के परिणाम को कभी भी सुरक्षित न करें, उदाहरण के लिए escape()

उनकी सलाह का पालन करें!

HTMLParser के साथ टैग हटाने के लिए, आपको इसे कई बार चलाना होगा।

इस प्रश्न के शीर्ष उत्तर को दरकिनार करना आसान है।

इस स्ट्रिंग को देखें ( स्रोत और चर्चा ):

<img<!-- --> src=x onerror=alert(1);//><!-- -->

पहली बार HTMLParser इसे देखता है, यह नहीं बता सकता है कि <img...>यह एक टैग है। यह टूटा हुआ दिखता है, इसलिए HTMLParser इससे छुटकारा नहीं पाता है। यह केवल <!-- comments -->आपको छोड़ कर, बाहर ले जाता है

<img src=x onerror=alert(1);//>

मार्च, 2014 में Django परियोजना के लिए इस समस्या का खुलासा किया गया था। उनके पुराने strip_tagsअनिवार्य रूप से इस प्रश्न के शीर्ष उत्तर के समान थे। उनका नया संस्करण मूल रूप से इसे लूप में चलाता है जब तक कि इसे फिर से चलाने से स्ट्रिंग में बदलाव नहीं होता है:

# _strip_once runs HTMLParser once, pulling out just the text of all the nodes.

def strip_tags(value):
    """Returns the given HTML with all tags stripped."""
    # Note: in typical case this loop executes _strip_once once. Loop condition
    # is redundant, but helps to reduce number of executions of _strip_once.
    while '<' in value and '>' in value:
        new_value = _strip_once(value)
        if len(new_value) >= len(value):
            # _strip_once was not able to detect more tags
            break
        value = new_value
    return value

बेशक, यह कोई भी मुद्दा नहीं है यदि आप हमेशा के परिणाम से बच जाते हैं strip_tags()

अपडेट 19 मार्च, 2015 : 1.4.20, 1.6.11, 1.7.7, और 1.8c1 से पहले Django के संस्करणों में एक बग था। ये संस्करण स्ट्रिप_टैग्स () फ़ंक्शन में एक अनंत लूप दर्ज कर सकते हैं। निश्चित संस्करण ऊपर पुन: प्रस्तुत किया गया है। अधिक जानकारी यहाँ

नकल या उपयोग करने के लिए अच्छी चीजें

मेरा उदाहरण कोड HTML एंटिटीज को हैंडल नहीं करता है - Django और MarkupSafe पैकेज्ड वर्जन।

मेरा उदाहरण कोड क्रॉस-साइट स्क्रिप्टिंग की रोकथाम के लिए उत्कृष्ट मार्कअप कैफे पुस्तकालय से निकाला गया है । यह सुविधाजनक और तेज़ है (C स्पीडअप के साथ अपने मूल पायथन संस्करण के लिए)। यह Google App Engine में शामिल है , और इसका उपयोग Jinja2 (2.7 और ऊपर) द्वारा किया गया है , Mako, Pylons और बहुत कुछ द्वारा किया जाता है। यह आसानी से Django 1.7 से Django टेम्प्लेट के साथ काम करता है।

हाल के संस्करण से Django की स्ट्रिप_टैग्स और अन्य HTML उपयोगिताओं अच्छे हैं, लेकिन मैं उन्हें MarkupSafe की तुलना में कम सुविधाजनक लगता हूं। वे बहुत आत्म-निहित हैं, आप इस फ़ाइल से जो कुछ भी चाहते हैं उसे कॉपी कर सकते हैं ।

यदि आपको लगभग सभी टैग्स को स्ट्रिप करने की आवश्यकता है , तो ब्लीच लाइब्रेरी अच्छी है। आपके पास यह नियम हो सकते हैं जैसे "मेरे उपयोगकर्ता चीजों को इटैलिक कर सकते हैं, लेकिन वे iframes नहीं बना सकते हैं।"

अपने टैग स्ट्रिपर के गुणों को समझें! उस पर फ़ज़ी टेस्ट चलाएं! इस कोड को मैंने इस उत्तर के लिए अनुसंधान करने के लिए उपयोग किया है।

शीश नोट - यह सवाल स्वयं कंसोल पर छपाई के बारे में है, लेकिन यह "स्ट्रिंग से अजगर पट्टी एचटीएमएल" के लिए शीर्ष Google परिणाम है, इसलिए वेब के बारे में यह जवाब 99% है।


मेरा "वैकल्पिक अंतिम पंक्ति" उदाहरण कोड html संस्थाओं को नहीं संभालता है - यह कितना बुरा है?
बचाता है

मैं केवल html का एक छोटा हिस्सा बिना किसी विशेष टैग के पार्स कर रहा हूं, और आपका लघु संस्करण बहुत अच्छा काम करता है। साझा करने के लिए धन्यवाद!
tbolender

31

मुझे टैग हटाने और HTML संस्थाओं को सादे पाठ में डिकोड करने के लिए एक तरीके की आवश्यकता थी । निम्नलिखित समाधान एल्फ के उत्तर पर आधारित है (जो मैं उपयोग नहीं कर सकता क्योंकि यह स्ट्रिप्स एंटिटीज़ है)।

from HTMLParser import HTMLParser
import htmlentitydefs

class HTMLTextExtractor(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.result = [ ]

    def handle_data(self, d):
        self.result.append(d)

    def handle_charref(self, number):
        codepoint = int(number[1:], 16) if number[0] in (u'x', u'X') else int(number)
        self.result.append(unichr(codepoint))

    def handle_entityref(self, name):
        codepoint = htmlentitydefs.name2codepoint[name]
        self.result.append(unichr(codepoint))

    def get_text(self):
        return u''.join(self.result)

def html_to_text(html):
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

एक त्वरित परीक्षण:

html = u'<a href="#">Demo <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>'
print repr(html_to_text(html))

परिणाम:

u'Demo (\xac \u0394\u03b7\u03bc\u03ce)'

गलती संभालना:

  • अमान्य HTML संरचना के कारण HTMLParseError हो सकती है ।
  • HTML संस्थाओं नाम से अमान्य (जैसे) &#apos; , जो XML और XHTML में मान्य है, लेकिन सादा HTML नहीं) ValueErrorअपवाद का कारण बनेंगी।
  • न्यूमेरिक एचटीएमएल इकाइयां पायथन द्वारा स्वीकार्य यूनिकोड रेंज के बाहर कोड बिंदु निर्दिष्ट करती हैं (जैसे, कुछ सिस्टम पर, बेसिक बहुभाषी विमान के बाहर के अक्षर )ValueError अपवाद का बनेंगे।

सुरक्षा नोट: HTML स्ट्रिपिंग (HTML में सादे पाठ में HTML को परिवर्तित करना) के साथ HTML स्ट्रिपिंग (HTML को सादे पाठ में बदलना) को भ्रमित न करें। यह उत्तर HTML को हटा देगा और संस्थाओं को सादे पाठ में डिकोड करेगा - जो परिणाम को HTML संदर्भ में उपयोग करने के लिए सुरक्षित नहीं बनाता है।

उदाहरण: &lt;script&gt;alert("Hello");&lt;/script&gt; परिवर्तित किया जाएगा <script>alert("Hello");</script>, जो कि 100% सही व्यवहार है, लेकिन स्पष्ट रूप से पर्याप्त नहीं है यदि परिणामी सादे पाठ को HTML पृष्ठ में डाला गया है।

नियम कठिन नहीं है: जब भी आप HTML आउटपुट में एक सादा-पाठ स्ट्रिंग सम्मिलित करते हैं, तो आपको हमेशा करना चाहिए HTML से इसे बचाना (उपयोग करना cgi.escape(s, True)), भले ही आप "जानते" हों कि इसमें HTML शामिल नहीं है (उदाहरण के लिए, क्योंकि आपने HTML सामग्री छीन ली है) ।

(हालांकि, ओपी ने कंसोल के परिणाम को प्रिंट करने के बारे में पूछा, जिस स्थिति में कोई HTML भागने की आवश्यकता नहीं है।)

पायथन 3.4+ संस्करण: (सिद्धांत के साथ!)

import html.parser

class HTMLTextExtractor(html.parser.HTMLParser):
    def __init__(self):
        super(HTMLTextExtractor, self).__init__()
        self.result = [ ]

    def handle_data(self, d):
        self.result.append(d)

    def get_text(self):
        return ''.join(self.result)

def html_to_text(html):
    """Converts HTML to plain text (stripping tags and converting entities).
    >>> html_to_text('<a href="#">Demo<!--...--> <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>')
    'Demo (\xac \u0394\u03b7\u03bc\u03ce)'

    "Plain text" doesn't mean result can safely be used as-is in HTML.
    >>> html_to_text('&lt;script&gt;alert("Hello");&lt;/script&gt;')
    '<script>alert("Hello");</script>'

    Always use html.escape to sanitize text before using in an HTML context!

    HTMLParser will do its best to make sense of invalid HTML.
    >>> html_to_text('x < y &lt z <!--b')
    'x < y < z '

    Unrecognized named entities are included as-is. '&apos;' is recognized,
    despite being XML only.
    >>> html_to_text('&nosuchentity; &apos; ')
    "&nosuchentity; ' "
    """
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

ध्यान दें कि HTMLParser पायथन 3 (जिसका अर्थ कम कोड और बेहतर एरर हैंडलिंग है) में सुधार हुआ है।


18

इसका एक सरल तरीका है:

def remove_html_markup(s):
    tag = False
    quote = False
    out = ""

    for c in s:
            if c == '<' and not quote:
                tag = True
            elif c == '>' and not quote:
                tag = False
            elif (c == '"' or c == "'") and tag:
                quote = not quote
            elif not tag:
                out = out + c

    return out

इस विचार को यहाँ समझाया गया है: http://youtu.be/2tu9LTDujbw

आप इसे यहां काम करते हुए देख सकते हैं: http://youtu.be/HPkNPcYed9M?t=35s

पुनश्च - यदि आप कक्षा में रुचि रखते हैं (अजगर के साथ स्मार्ट डिबगिंग के बारे में) तो मैं आपको एक लिंक देता हूं: http://www.udacity.com/overview/Course/cs259/CourseRev/1 । यह निःशुल्क है!

आपका स्वागत है! :)


2
मुझे आश्चर्य है कि यह जवाब सिर्फ क्यों दिया गया। यह बिना किसी समस्या के समस्या को हल करने का एक सरल तरीका है। बस शुद्ध अजगर और यह लिंक द्वारा दिखाए गए अनुसार काम करता है।
मेदिएरोस

2
संभवतः लोग उन्हें सुरक्षा देने के लिए लिबास पसंद करते हैं। मैंने आपको कोड का परीक्षण किया और पारित कर दिया, और मैं हमेशा एक छोटे से कोड को पसंद करता हूं जिसे मैं एक लीब का उपयोग करने की तुलना में समझता हूं और यह मानता हूं कि यह ठीक है जब तक कि एक बग पॉप अप नहीं हो जाता। मेरे लिए वही है जिसकी मुझे तलाश थी और फिर से धन्यवाद। चढ़ाव के बारे में, उस मानसिकता में मत जाओ। यहां के लोगों को गुणवत्ता की परवाह करनी चाहिए न कि वोट की। हाल ही में एसओ एक ऐसा स्थान बन गया है, जहां हर कोई अंक चाहता है और ज्ञान नहीं।
जिमी केन

2
इस समाधान के साथ समस्या त्रुटि हैंडलिंग है। उदाहरण के लिए यदि आप <b class="o'>x</b>इनपुट फंक्शन आउटपुट के रूप में देते हैं x। लेकिन वास्तव में यह इनपुट अमान्य है। मुझे लगता है कि इसीलिए लोग लिबास पसंद करते हैं।
laltin

1
यह उस इनपुट के साथ भी काम करता है। बस परीक्षण किया गया। बस महसूस करें कि उन पुस्तकालयों के अंदर आपको समान कोड मिलेगा। यह बहुत अजगर नहीं है, मुझे पता है। सी या जावा कोड की तरह दिखता है। मुझे लगता है कि यह कुशल है और आसानी से किसी अन्य भाषा में रखी जा सकती है।
मेडिएरोस

1
सरल, पायथोनिक और चर्चा की गई अन्य विधियों की तुलना में अच्छा या बेहतर काम करता है। यह संभव है कि यह कुछ बीमार एचटीएमएल के लिए काम नहीं करेगा लेकिन इस पर कोई काबू नहीं है।
डेंसन

16

यदि आपको HTML संस्थाओं (यानी &amp;) को संरक्षित करने की आवश्यकता है , तो मैंने Eloff के उत्तर में "handle_entityref" विधि जोड़ी ।

from HTMLParser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def handle_entityref(self, name):
        self.fed.append('&%s;' % name)
    def get_data(self):
        return ''.join(self.fed)

def html_to_text(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

13

यदि आप सभी HTML टैग्स को पट्टी करना चाहते हैं तो मैंने पाया कि ब्यूटीफुल का उपयोग करना सबसे आसान तरीका है:

from bs4 import BeautifulSoup  # Or from BeautifulSoup import BeautifulSoup

def stripHtmlTags(htmlTxt):
    if htmlTxt is None:
            return None
        else:
            return ''.join(BeautifulSoup(htmlTxt).findAll(text=True)) 

मैंने स्वीकार किए गए उत्तर के कोड की कोशिश की, लेकिन मुझे "RuntimeError: अधिकतम पुनरावृत्ति की गहराई पार हो गई" थी, जो कोड के उपरोक्त ब्लॉक के साथ नहीं हुआ था।


1
मैंने सिर्फ आपके तरीके की कोशिश की क्योंकि यह क्लीनर लगता है, यह काम करता है, अच्छी तरह से ... यह इनपुट टैग को पट्टी नहीं करता है!
रूस्तमपुर

मुझे लगता है कि सुंदरसुपे के एक सरल अनुप्रयोग में व्हाट्सएप के साथ एक समस्या है ''.join(BeautifulSoup('<em>he</em>llo<br>world').find_all(text=True)):। यहां आउटपुट "हेलोवर्ल्ड" है, जबकि आप शायद चाहते हैं कि यह "हैलो वर्ल्ड" हो। ' '.join(BeautifulSoup('<em>he</em>llo<br>world').find_all(text=True))मदद नहीं करता है क्योंकि यह "वह दुनिया को खो देता है" बन जाता है।
फिन Finरूप नीलसन

@kustomrtr, माफ करना, मेरी अज्ञानता, मैं आत्म तर्क में क्या डालूं? NameError: नाम 'स्व' परिभाषित नहीं है
Ian_De_Oliveira

@Ian_De_Oliveira आप इसे हटा सकते हैं, मैंने मान लिया कि यह एक कक्षा के अंदर है लेकिन इसकी आवश्यकता नहीं है। मैंने इसे हटाने का उत्तर भी संपादित किया
वासिलिस

@Ian_De_Oliveira आप इसे हटा सकते हैं, मैंने मान लिया कि यह एक कक्षा के अंदर है लेकिन इसकी आवश्यकता नहीं है। मैंने इसे हटाने का उत्तर भी संपादित किया
वासिलिस

9

एक lxml.html -based समाधान ( lxml एक देशी पुस्तकालय है और इसलिए किसी भी शुद्ध अजगर समाधान की तुलना में बहुत तेज़ है)।

from lxml import html
from lxml.html.clean import clean_html

tree = html.fromstring("""<span class="item-summary">
                            Detailed answers to any questions you might have
                        </span>""")

print(clean_html(tree).strip())

# >>> Detailed answers to any questions you might have

इसके अलावा http://lxml.de/lxmlhtml.html#cleaning-up-html को देखें कि वास्तव में lxml.cleaner क्या करता है।

यदि आपको पाठ में परिवर्तित होने से पहले वास्तव में क्या स्वच्छता है, इस पर अधिक नियंत्रण की आवश्यकता है, तो आप निर्माण में इच्छित विकल्पों को पास करके स्पष्ट रूप से lxml Cleaner का उपयोग करना चाहते हैं , जैसे:

cleaner = Cleaner(page_structure=True,
                  meta=True,
                  embedded=True,
                  links=True,
                  style=True,
                  processing_instructions=True,
                  inline_style=True,
                  scripts=True,
                  javascript=True,
                  comments=True,
                  frames=True,
                  forms=True,
                  annoying_tags=True,
                  remove_unknown_tags=True,
                  safe_attrs_only=True,
                  safe_attrs=frozenset(['src','color', 'href', 'title', 'class', 'name', 'id']),
                  remove_tags=('span', 'font', 'div')
                  )
sanitized_html = cleaner.clean_html(unsafe_html)

1
मुझे अट्रैक्शन मिला: 'HtmlElement' ऑब्जेक्ट की कोई विशेषता 'स्ट्रिप' नहीं है
aris

9

यहाँ एक सरल उपाय है जो HTML टैग्स को स्ट्रिप्स करता है और आश्चर्यजनक रूप से तेज़ lxmlलाइब्रेरी के आधार पर HTML संस्थाओं को डिकोड करता है :

from lxml import html

def strip_html(s):
    return str(html.fromstring(s).text_content())

strip_html('Ein <a href="">sch&ouml;ner</a> Text.')  # Output: Ein schöner Text.

3
2020 तक, यह HTML की सामग्री को छीनने का सबसे तेज़ और सबसे अच्छा तरीका था। साथ ही डिकोडिंग से निपटने का बोनस। भाषा का पता लगाने के लिए महान!
dfabiano

text_content()रिटर्न lxml.etree._ElementUnicodeResultइसलिए आपको इसे पहले स्ट्रिंग करना पड़ सकता है
सुजान

1
@ सुजाना अच्छी बात है। ऐसा लगता है strजैसे ऑटो संचालन के लिए कड़े संचालन +और अनुक्रमण के लिए तैयार किया गया है []। किसी भी तरह अच्छे उपाय के लिए कलाकारों को जोड़ा।
रॉबिन डिनसे

7

सुंदर सूप पैकेज यह आपके लिए तुरंत करता है।

from bs4 import BeautifulSoup

soup = BeautifulSoup(html)
text = soup.get_text()
print(text)

3
समीक्षा कतार से: मैं आपसे अनुरोध कर सकता हूं कि कृपया अपने उत्तर के आसपास कुछ और संदर्भ जोड़ दें। कोड-केवल उत्तर समझना मुश्किल है। यह पूछने वाले और भविष्य के पाठकों दोनों की मदद करेगा यदि आप अपनी पोस्ट में अधिक जानकारी जोड़ सकते हैं।
help-info.de

2

यहाँ अजगर 3 के लिए मेरा समाधान है।

import html
import re

def html_to_txt(html_text):
    ## unescape html
    txt = html.unescape(html_text)
    tags = re.findall("<[^>]+>",txt)
    print("found tags: ")
    print(tags)
    for tag in tags:
        txt=txt.replace(tag,'')
    return txt

निश्चित नहीं है कि यह सही है, लेकिन मेरे उपयोग के मामले को हल किया और सरल लगता है।


2

आप या तो एक अलग HTML पार्सर ( जैसे lxml , या सुंदर सूप ) का उपयोग कर सकते हैं - एक जो केवल पाठ निकालने के लिए फ़ंक्शन प्रदान करता है। या, आप अपने लाइन स्ट्रिंग पर एक रेगेक्स चला सकते हैं जो टैग्स को स्ट्रिप्स करता है। अधिक के लिए अजगर डॉक्स देखें ।


1
एमके लिंक मर चुका है। एक विकल्प है?

2
पायथन वेबसाइट में अब कैसे-कैसे अच्छे हैं, यहां बताया गया है कि कैसे-टू: docs.python.org/howto/regex
जेसन कून

5
Lxml में:lxml.html.fromstring(s).text_content()
Bluu

1
Lxml के साथ Bluu का उदाहरण HTML संस्थाओं (जैसे &amp;) को पाठ में डिकोड करता है।
सोरेन लोर्बोर्ग

1

मैंने Python 3.1 [बहुत धन्यवाद!] के लिए Eloff के उत्तर का सफलतापूर्वक उपयोग किया है।

मैंने पायथन 3.2.3 में अपग्रेड किया, और त्रुटियों में भाग गया।

समाधान, यहां दिए गए उत्तरदाता थॉमस के के लिए धन्यवाद, super().__init__()निम्नलिखित कोड में सम्मिलित करना है:

def __init__(self):
    self.reset()
    self.fed = []

... इसे इस तरह से बनाने के लिए:

def __init__(self):
    super().__init__()
    self.reset()
    self.fed = []

... और यह पायथन 3.2.3 के लिए काम करेगा।

फिर से, फिक्स के लिए थॉमस के के लिए धन्यवाद और एल्फ के मूल कोड के लिए ऊपर प्रदान किया गया!


1

आप अपना स्वयं का कार्य लिख सकते हैं:

def StripTags(text):
     finished = 0
     while not finished:
         finished = 1
         start = text.find("<")
         if start >= 0:
             stop = text[start:].find(">")
             if stop >= 0:
                 text = text[:start] + text[start+stop+1:]
                 finished = 0
     return text

1
क्या तार में शामिल होने से स्ट्रिंग की एक नई प्रतिलिपि बनती है?
जेरेमी एल

1
@ न्यूडलिंग - हाँ, यह करता है, जो अक्सर उपयोग किए जाने वाले कार्यों में कुछ बल्कि प्रभावशाली अक्षमताओं को जन्म दे सकता है (या, इस मामले के लिए, अक्सर उपयोग किए जाने वाले कार्य जो पाठ के बड़े ब्लब्स पर कार्य करते हैं।) विस्तार के लिए इस पृष्ठ को देखें । : डी
जेरेमी सैंडल

क्या यह उद्धृत तारों के खिलाफ परीक्षण करता है? नंबर
जिमी केन

1

यदि वे केवल एक बार चलते हैं, तो HTML- पार्सर के साथ समाधान सभी टूटने योग्य हैं:

html_to_text('<<b>script>alert("hacked")<</b>/script>

का परिणाम:

<script>alert("hacked")</script>

क्या आप को रोकने का इरादा है। यदि आप HTML-Parser का उपयोग करते हैं, तो टैग को तब तक गिनें जब तक कि शून्य को बदल न दिया जाए:

from HTMLParser import HTMLParser

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
        self.containstags = False

    def handle_starttag(self, tag, attrs):
       self.containstags = True

    def handle_data(self, d):
        self.fed.append(d)

    def has_tags(self):
        return self.containstags

    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    must_filtered = True
    while ( must_filtered ):
        s = MLStripper()
        s.feed(html)
        html = s.get_data()
        must_filtered = s.has_tags()
    return html

1
यदि आप एक फ़ंक्शन को कॉल करते हैं html_to_textऔर आप उस टेक्स्ट से बचने के बिना HTML के अंदर उस फ़ंक्शन से आउटपुट होने वाले टेक्स्ट को एम्बेड करते हैं, तो यह भागने की कमी है, जो html_to_textफ़ंक्शन नहीं बल्कि एक सुरक्षा भेद्यता है। html_to_textसमारोह तुम कभी नहीं वादा किया उत्पादन पाठ किया जाएगा। और HTML को बचने के बिना पाठ में सम्मिलित करना एक संभावित सुरक्षा भेद्यता है चाहे आपको पाठ html_to_text किसी अन्य स्रोत से मिला हो ।
कास्परड

आप मामले में सही हैं, बचने की कमी के लिए, लेकिन सवाल किसी दिए गए स्ट्रिंग से बचने के लिए नहीं दिए गए स्ट्रिंग से html को स्ट्रिप करने का था। यदि पहले के उत्तर कुछ html को हटाने के परिणामस्वरूप उनके समाधान के साथ नए HTML का निर्माण करते हैं, तो क्या इस समाधान का उपयोग खतरनाक है।
फाल्क निसियस

1

यह एक त्वरित सुधार है और इसे और भी अधिक अनुकूलित किया जा सकता है लेकिन यह ठीक काम करेगा। यह कोड सभी गैर-रिक्त टैग को "" से बदल देगा और सभी html टैग एक दिए गए इनपुट टेक्स्ट को बनाते हैं। आप इसका उपयोग कर सकते हैं ।/file.py इनपुट आउटपुट

    #!/usr/bin/python
import sys

def replace(strng,replaceText):
    rpl = 0
    while rpl > -1:
        rpl = strng.find(replaceText)
        if rpl != -1:
            strng = strng[0:rpl] + strng[rpl + len(replaceText):]
    return strng


lessThanPos = -1
count = 0
listOf = []

try:
    #write File
    writeto = open(sys.argv[2],'w')

    #read file and store it in list
    f = open(sys.argv[1],'r')
    for readLine in f.readlines():
        listOf.append(readLine)         
    f.close()

    #remove all tags  
    for line in listOf:
        count = 0;  
        lessThanPos = -1  
        lineTemp =  line

            for char in lineTemp:

            if char == "<":
                lessThanPos = count
            if char == ">":
                if lessThanPos > -1:
                    if line[lessThanPos:count + 1] != '<>':
                        lineTemp = replace(lineTemp,line[lessThanPos:count + 1])
                        lessThanPos = -1
            count = count + 1
        lineTemp = lineTemp.replace("&lt","<")
        lineTemp = lineTemp.replace("&gt",">")                  
        writeto.write(lineTemp)  
    writeto.close() 
    print "Write To --- >" , sys.argv[2]
except:
    print "Help: invalid arguments or exception"
    print "Usage : ",sys.argv[0]," inputfile outputfile"

1

एक अजगर 3-सोरेन-लॉबॉर्ग के उत्तर का अनुकूलन

from html.parser import HTMLParser
from html.entities import html5

class HTMLTextExtractor(HTMLParser):
    """ Adaption of http://stackoverflow.com/a/7778368/196732 """
    def __init__(self):
        super().__init__()
        self.result = []

    def handle_data(self, d):
        self.result.append(d)

    def handle_charref(self, number):
        codepoint = int(number[1:], 16) if number[0] in (u'x', u'X') else int(number)
        self.result.append(unichr(codepoint))

    def handle_entityref(self, name):
        if name in html5:
            self.result.append(unichr(html5[name]))

    def get_text(self):
        return u''.join(self.result)

def html_to_text(html):
    s = HTMLTextExtractor()
    s.feed(html)
    return s.get_text()

1

एक परियोजना के लिए, मुझे इतनी पट्टी HTML की आवश्यकता थी, लेकिन सीएसएस और जेएस भी। इस प्रकार, मैंने एलॉफ़ के उत्तर का एक बदलाव किया:

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.strict = False
        self.convert_charrefs= True
        self.fed = []
        self.css = False
    def handle_starttag(self, tag, attrs):
        if tag == "style" or tag=="script":
            self.css = True
    def handle_endtag(self, tag):
        if tag=="style" or tag=="script":
            self.css=False
    def handle_data(self, d):
        if not self.css:
            self.fed.append(d)
    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

1

यहां वर्तमान में स्वीकृत उत्तर ( https://stackoverflow.com/a/925630/95989 ) के समान एक समाधान है , सिवाय इसके कि यह आंतरिक का उपयोग करता हैHTMLParser सीधे वर्ग (यानी कोई उपवर्ग) , जिससे यह अधिक महत्वपूर्ण हो जाता है:

डीआईएफ़ स्ट्रिप_एचटीएमएल (पाठ):
    भागों = []                                                                      
    parser = HTMLParser ()                                                           
    parser.handle_data = parts.append                                               
    parser.feed (पाठ)                                                               
    वापसी '' .जमीन (भागों)

0

मैं गितूब को पढ़ रहा हूँ और मुझे लगता है कि निम्नलिखित वास्तव में अच्छी तरह से काम करता है:

import re
import lxml.html

def strip_markdown(x):
    links_sub = re.sub(r'\[(.+)\]\([^\)]+\)', r'\1', x)
    bold_sub = re.sub(r'\*\*([^*]+)\*\*', r'\1', links_sub)
    emph_sub = re.sub(r'\*([^*]+)\*', r'\1', bold_sub)
    return emph_sub

def strip_html(x):
    return lxml.html.fromstring(x).text_content() if x else ''

और तब

readme = """<img src="https://raw.githubusercontent.com/kootenpv/sky/master/resources/skylogo.png" />

            sky is a web scraping framework, implemented with the latest python versions in mind (3.4+). 
            It uses the asynchronous `asyncio` framework, as well as many popular modules 
            and extensions.

            Most importantly, it aims for **next generation** web crawling where machine intelligence 
            is used to speed up the development/maintainance/reliability of crawling.

            It mainly does this by considering the user to be interested in content 
            from *domains*, not just a collection of *single pages*
            ([templating approach](#templating-approach))."""

strip_markdown(strip_html(readme))

सभी मार्कडाउन और HTML को सही तरीके से हटाता है।


0

BeautifulSoup, html2text या @Eloff के कोड का उपयोग करते हुए, ज्यादातर समय, यह कुछ html एलिमेंट्स, जावास्क्रिप्ट कोड रहता है ...

तो आप इन पुस्तकालयों के संयोजन का उपयोग कर सकते हैं और मार्कडाउन स्वरूपण (पायथन 3) को हटा सकते हैं:

import re
import html2text
from bs4 import BeautifulSoup
def html2Text(html):
    def removeMarkdown(text):
        for current in ["^[ #*]{2,30}", "^[ ]{0,30}\d\\\.", "^[ ]{0,30}\d\."]:
            markdown = re.compile(current, flags=re.MULTILINE)
            text = markdown.sub(" ", text)
        return text
    def removeAngular(text):
        angular = re.compile("[{][|].{2,40}[|][}]|[{][*].{2,40}[*][}]|[{][{].{2,40}[}][}]|\[\[.{2,40}\]\]")
        text = angular.sub(" ", text)
        return text
    h = html2text.HTML2Text()
    h.images_to_alt = True
    h.ignore_links = True
    h.ignore_emphasis = False
    h.skip_internal_links = True
    text = h.handle(html)
    soup = BeautifulSoup(text, "html.parser")
    text = soup.text
    text = removeAngular(text)
    text = removeMarkdown(text)
    return text

यह मेरे लिए अच्छा काम करता है लेकिन इसे बढ़ाया जा सकता है, अवश्य ...


0

सरल कोड !. यह सभी तरह के टैग और सामग्री को इसके अंदर से निकाल देगा।

def rm(s):
    start=False
    end=False
    s=' '+s
    for i in range(len(s)-1):
        if i<len(s):
            if start!=False:
                if s[i]=='>':
                    end=i
                    s=s[:start]+s[end+1:]
                    start=end=False
            else:
                if s[i]=='<':
                    start=i
    if s.count('<')>0:
        self.rm(s)
    else:
        s=s.replace('&nbsp;', ' ')
        return s

लेकिन यह पूर्ण परिणाम नहीं देगा यदि पाठ में <> प्रतीक इसके अंदर हों।


0
# This is a regex solution.
import re
def removeHtml(html):
  if not html: return html
  # Remove comments first
  innerText = re.compile('<!--[\s\S]*?-->').sub('',html)
  while innerText.find('>')>=0: # Loop through nested Tags
    text = re.compile('<[^<>]+?>').sub('',innerText)
    if text == innerText:
      break
    innerText = text

  return innerText.strip()

-2

यह विधि मेरे लिए त्रुटिपूर्ण रूप से काम करती है और इसके लिए किसी अतिरिक्त संस्थापन की आवश्यकता नहीं है:

import re
import htmlentitydefs

def convertentity(m):
    if m.group(1)=='#':
        try:
            return unichr(int(m.group(2)))
        except ValueError:
            return '&#%s;' % m.group(2)
        try:
            return htmlentitydefs.entitydefs[m.group(2)]
        except KeyError:
            return '&%s;' % m.group(2)

def converthtml(s):
    return re.sub(r'&(#?)(.+?);',convertentity,s)

html =  converthtml(html)
html.replace("&nbsp;", " ") ## Get rid of the remnants of certain formatting(subscript,superscript,etc).

3
यह HTML संस्थाओं को सादे पाठ में डिकोड करता है, लेकिन जाहिर है कि वास्तव में कोई टैग नहीं छीनता है, जो कि मूल प्रश्न था। (इसके अलावा, दूसरे प्रयास को छोड़कर, ब्लॉक को कोड के लिए डी-इंडेंट करने की आवश्यकता है, यहां तक ​​कि उतना ही करने के लिए भी)।
सोरेन लोर्बोर्ग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.