বিউটিউসলসপ গ্র্যাব দৃশ্যমান ওয়েবপেজ পাঠ্য


124

মূলত, আমি কোনও ওয়েবপৃষ্ঠায় দৃশ্যমান পাঠ্য কঠোরভাবে দখল করতে বিউটিফুলসপ ব্যবহার করতে চাই । উদাহরণস্বরূপ, এই ওয়েবপেজটি আমার পরীক্ষার কেস। এবং আমি মূলত কেবলমাত্র এখানে এবং সেখানে বডি টেক্সট (নিবন্ধ) এবং সম্ভবত কয়েকটি ট্যাব নাম পেতে চাই। আমি এই এসও প্রশ্নে পরামর্শটি চেষ্টা করেছি যা প্রচুর <script>ট্যাগ এবং এইচটিএমএল মন্তব্য দেয় যা আমি চাই না। findAll()কেবলমাত্র একটি ওয়েবপৃষ্ঠায় দৃশ্যমান পাঠ্যগুলি পেতে ফাংশনটির জন্য আমার প্রয়োজনীয় যুক্তিগুলি আমি খুঁজে বের করতে পারি না ।

সুতরাং, আমার স্ক্রিপ্ট, মন্তব্য, সিএসএস বাদে সমস্ত দৃশ্যমান পাঠ্য কীভাবে খুঁজে পাওয়া উচিত?

উত্তর:


239

এটা চেষ্টা কর:

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

47
+1 এর soup.findAll(text=True)বৈশিষ্ট্যটি সম্পর্কে কখনও জানতেন না
হার্টলি ব্রডি

7
সাম্প্রতিক বিএস 4 এর জন্য (কমপক্ষে) আপনি isinstance(element, Comment)একটি রেজেক্সের সাথে মিলের পরিবর্তে মন্তব্যগুলি সনাক্ত করতে পারেন ।
ট্রিপলি

5
আমি বিশ্বাস করি লাইন 2 হওয়া উচিতsoup = BeautifulSoup(html)
jczaplew

11
দৃশ্যমান ফাংশনে, মন্তব্যগুলি খুঁজে পাওয়ার জন্য এলিফ কাজ করছে বলে মনে হয় না। আমি এটি আপডেট করতে হবে elif isinstance(element,bs4.element.Comment):। আমি পিতামাতার তালিকায় 'মেটা' যুক্তও করেছি।
রাশ সেভেজ

4
উপরের ফিল্টারটির ফলাফলটিতে প্রচুর পরিমাণে \ n রয়েছে, সাদা স্পেস এবং নতুন লাইনগুলি দূর করতে নিম্নলিখিত কোড যুক্ত করুন: elif re.match(r"[\s\r\n]+",str(element)): return False
天才小飞猫

37

@ জবোচি থেকে অনুমোদিত উত্তরটি আমার পক্ষে কাজ করে না। স্ট্রিং () ফাংশন কল একটি ব্যতিক্রম উত্থাপন করে কারণ এটি বিউটিফুলসুপ উপাদানটিতে অ-এসিআই অক্ষরগুলি এনকোড করতে পারে না। উদাহরণস্বরূপ ওয়েব পৃষ্ঠাটি দৃশ্যমান পাঠ্যে ফিল্টার করার জন্য এখানে আরও একটি সুসংগত উপায়।

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

1
যদি str(element)এনকোডিংয়ের সমস্যাগুলির সাথে ব্যর্থ হয় unicode(element)তবে আপনি যদি পাইথন 2 ব্যবহার করছেন তবে তার পরিবর্তে চেষ্টা করা উচিত
mknaf

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

4
পূর্ববর্তী উত্তরগুলি আমার পক্ষে কাজ করে নি, তবে এটি করেছে :)
rjurney

যদি আমি url imfuna.com এ এটি চেষ্টা করি তবে পৃষ্ঠায় আরও অনেক পাঠ / শব্দ রয়েছে সত্ত্বেও এটি কেবল 6 টি শব্দ (ইমফুনা সম্পত্তি ইনভেন্টরি এবং পরিদর্শন অ্যাপ্লিকেশন) ফেরত দেয় ... কোনও উত্তর কেন এই উত্তরটির জন্য কাজ করে না? URL? @ কুমড়ো
the_t_test_1

10

রেন্ডারযুক্ত সামগ্রী পেতে আমি বিউটিফুল স্যুপ ব্যবহার করে সম্পূর্ণ সম্মান করি তবে এটি কোনও পৃষ্ঠায় রেন্ডার করা সামগ্রী অর্জনের জন্য আদর্শ প্যাকেজ হতে পারে না।

রেন্ডার করা সামগ্রী বা একটি সাধারণ ব্রাউজারে দৃশ্যমান সামগ্রী পেতে আমার একইরকম সমস্যা হয়েছিল। বিশেষত আমার নীচে এমন একটি সাধারণ উদাহরণ সহ কাজ করার জন্য অনেকগুলি সম্ভবত এপিপিকাল কেস ছিল। এক্ষেত্রে ডিসপ্লেযোগ্যযোগ্য ট্যাগটি স্টাইল ট্যাগে বাসা বেঁধে দেওয়া হয় এবং আমি যাচাই করে দেখেছি এমন অনেক ব্রাউজারে এটি দৃশ্যমান নয়। অন্যান্য বৈচিত্রগুলি যেমন কারও কাছে শ্রেণি ট্যাগ সেটিং প্রদর্শনকে সংজ্ঞায়িত করার মতো উপস্থিত রয়েছে। তারপরে ডিভের জন্য এই ক্লাসটি ব্যবহার করে।

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

এই সমাধানটিতে অবশ্যই অনেক ক্ষেত্রে অ্যাপ্লিকেশন রয়েছে এবং কাজটি সাধারণত বেশ ভালভাবে সম্পাদন করে তবে উপরে পোস্ট করা এইচটিএমএলটিতে রেন্ডার করা হয়নি এমন পাঠ্যটি ধরে রেখেছে। অতএব অনুসন্ধানের পরে বেশ কয়েকটি সমাধান এখানে এসেছিল বিউটিফুলসৌপ get_text সমস্ত ট্যাগ এবং জাভাস্ক্রিপ্ট স্ট্রিপ করে না এবং এখানে পাইথন ব্যবহার করে সরল পাঠ্যে এইচডিএমএল রেন্ডার করা হয়েছে

আমি এই উভয় সমাধানের চেষ্টা করেছি: html2text এবং nltk.clean_html এবং সময় ফলাফল দেখে অবাক হয়েছি তাই ভেবেছিল তারা উত্তরসূরির জন্য একটি উত্তর নিশ্চিত করে। অবশ্যই, গতিটি ডেটা সামগ্রীর উপর নির্ভর করে ...

@ হেলজ থেকে এখানে একটি উত্তর ছিল সমস্ত কিছুর nltk ব্যবহার সম্পর্কে।

import nltk

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

এটি রেন্ডার এইচটিএমএল সহ একটি স্ট্রিং ফিরিয়ে দিতে সত্যিই ভাল কাজ করেছে। এই এনএলটিকি মডিউলটি এইচটিএমএল 2 টেক্সটের চেয়েও দ্রুত ছিল, যদিও সম্ভবত এইচটিএমএল 2 টেক্সট আরও শক্তিশালী।

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

3

আপনি যদি পারফরম্যান্স সম্পর্কে যত্নশীল হন তবে এখানে আরও একটি কার্যকর উপায় রয়েছে:

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যাতে আপনি একাধিক লুপের মধ্যে না গিয়েই পিতামাতার ট্যাগের নামটি সরাসরি পরীক্ষা করতে পারেন।


2

শিরোনামটি একটি <nyt_headline>ট্যাগের অভ্যন্তরে থাকে যা কোনও <h1>ট্যাগের ভিতরে বাসা হয় এবং <div>"নিবন্ধ" আইডি সহ একটি ট্যাগ থাকে।

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

কাজ করা উচিত.

নিবন্ধের মূল অংশটি একটি <nyt_text>ট্যাগের অভ্যন্তরে থাকে যা <div>"আর্টিকেলবডি" আইডি সহ একটি ট্যাগের ভিতরে থাকে । <nyt_text> উপাদানটির অভ্যন্তরে , পাঠ্য নিজেই <p> ট্যাগগুলির মধ্যে থাকে । চিত্রগুলি এই <p>ট্যাগগুলির মধ্যে নেই। সিনট্যাক্স নিয়ে পরীক্ষা করা আমার পক্ষে কঠিন, তবে আমি আশা করি একটি কাজের স্ক্র্যাপটি এরকম কিছু দেখাবে।

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

আমি নিশ্চিত যে এটি এই পরীক্ষার ক্ষেত্রে কাজ করে, আরও সাধারণ জবাব খুঁজছে যা অন্যান্য অন্যান্য ওয়েবসাইটে প্রয়োগ করা যেতে পারে ... এখন পর্যন্ত, আমি <script> </script> ট্যাগ এবং < -। * -> মতামত ও তাদের "সঙ্গে" প্রতিস্থাপন কিন্তু যে এমনকি সমষ্টি কারণে ধরণ কঠিন প্রতিপাদন হচ্ছে ..
user233864

2

যদিও, আমি সাধারণভাবে সম্পূর্ণরূপে সুন্দর-স্যুপ ব্যবহার করার পরামর্শ দিচ্ছি, যদি কেউ যে কোনও কারণে কোনও ত্রুটিযুক্ত এইচটিএমএল (যেমন আপনার ওয়েব পৃষ্ঠার কেবলমাত্র একটি বিভাগ বা লাইন রয়েছে) এর দৃশ্যমান অংশগুলি প্রদর্শন করতে চাইছেন, তবে নিম্নলিখিতগুলি ট্যাগ <এবং >ট্যাগগুলির মধ্যে সামগ্রী সরিয়ে ফেলবে :

import re   ## only use with malformed html - this is not efficient
def display_visible_html_using_re(text):             
    return(re.sub("(\<.*?\>)", "",text))

2

খালি লাইন এবং ক্র্যাপ ছাড়াই, কেবল স্ট্রিংগুলি পেতে কম কোডের সাথে বিউটিফুলসৌপ ব্যবহার করা সহজতম উপায়।

tag = <Parent_Tag_that_contains_the_data>
soup = BeautifulSoup(tag, 'html.parser')

for i in soup.stripped_strings:
    print repr(i)

0

এই কেসটি হ্যান্ডেল করার সহজ উপায় হ'ল ব্যবহার করা getattr()। আপনি এই উদাহরণটি আপনার প্রয়োজনের সাথে মানিয়ে নিতে পারেন:

from bs4 import BeautifulSoup

source_html = """
<span class="ratingsDisplay">
    <a class="ratingNumber" href="https://www.youtube.com/watch?v=oHg5SJYRHA0" target="_blank" rel="noopener">
        <span class="ratingsContent">3.7</span>
    </a>
</span>
"""

soup = BeautifulSoup(source_html, "lxml")
my_ratings = getattr(soup.find('span', {"class": "ratingsContent"}), "text", None)
print(my_ratings)

এটি যখন টেক্সট উপাদানটির "3.7"মধ্যে <span class="ratingsContent">3.7</span>উপস্থিত থাকে তখন ট্যাগ অবজেক্টের মধ্যে এটি উপস্থিত থাকে, তবে NoneTypeএটি ডিফল্ট না হয়ে থাকে।

getattr(object, name[, default])

অবজেক্টের নামযুক্ত বৈশিষ্ট্যের মানটি ফিরিয়ে দিন। নাম অবশ্যই একটি স্ট্রিং হতে হবে। স্ট্রিং যদি কোনও অবজেক্টের বৈশিষ্ট্যের নাম হয় তবে ফলাফলটি সেই বৈশিষ্ট্যের মান। উদাহরণস্বরূপ, গেটিয়েটার (এক্স, 'ফুবার') এক্স.ফুবারের সমতুল্য। যদি নামযুক্ত বৈশিষ্ট্যটি বিদ্যমান না থাকে তবে প্রদান করা থাকলে ডিফল্ট ফিরিয়ে দেওয়া হয়, অন্যথায়, অ্যাট্রিবিউটআরার উত্থাপিত হয়।


0
from bs4 import BeautifulSoup
from bs4.element import Comment
import urllib.request
import re
import ssl

def tag_visible(element):
    if element.parent.name in ['style', 'script', 'head', 'title', 'meta', '[document]']:
        return False
    if isinstance(element, Comment):
        return False
    if re.match(r"[\n]+",str(element)): return False
    return True
def text_from_html(url):
    body = urllib.request.urlopen(url,context=ssl._create_unverified_context()).read()
    soup = BeautifulSoup(body ,"lxml")
    texts = soup.findAll(text=True)
    visible_texts = filter(tag_visible, texts)  
    text = u",".join(t.strip() for t in visible_texts)
    text = text.lstrip().rstrip()
    text = text.split(',')
    clean_text = ''
    for sen in text:
        if sen:
            sen = sen.rstrip().lstrip()
            clean_text += sen+','
    return clean_text
url = 'http://www.nytimes.com/2009/12/21/us/21storm.html'
print(text_from_html(url))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.