باستخدام شوربة جميلة بيثون وحدة لاستبدال الكلمات الدليلية مع نص عادي

StackOverflow https://stackoverflow.com/questions/2061718

  •  20-09-2019
  •  | 
  •  

سؤال

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

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

<div id="abc">
    some long text goes <a href="/"> here </a> and hopefully it 
    will get picked up by the parser as content
</div>

results = soup.findAll(text=lambda(x): len(x) > 20)

عند استخدام رمز أعلاه للحصول على نص طويل ، فإنه يكسر (تحديد النص سوف تبدأ من أمل..') في العلامات.لذلك حاولت أن تحل محل الوسم مع نص عادي على النحو التالي:

anchors = soup.findAll('a')

for a in anchors:
  a.replaceWith('plain text')

أعلاه لا يعمل بسبب شوربة جميلة إدراج السلسلة كما NavigableString و الذي يسبب نفس المشكلة عند استخدام findAll مع ليون(x) > 20.يمكنني استخدام التعبيرات العادية تحليل html كما نص عادي أول كل العلامات غير المرغوب فيها ومن ثم استدعاء شوربة جميلة.ولكن أود أن تجنب معالجة المحتوى نفسه مرتين أنا أحاول تحليل هذه الصفحات لذا أنا يمكن أن تظهر مقتطف من محتوى معين الرابط (كثيرا مثل Facebook Share) -- و إذا كان كل شيء يتم مع شوربة جميلة, أفترض أنه سيكون أسرع.

لذلك سؤالي:هل هناك طريقة واضحة فئة' واستبدالها 'نص عادي باستخدام شوربة جميلة.إن لم يكن ما تكون أفضل طريقة للقيام بذلك ؟

شكرا على اقتراحاتكم!

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

import urllib
from BeautifulSoup import BeautifulSoup

page = urllib.urlopen('http://www.engadget.com/2010/01/12/kingston-ssdnow-v-dips-to-30gb-size-lower-price/')

anchors = soup.findAll('a')
i = 0
for a in anchors:
    print str(i) + ":" + str(a)
    for a in anchors:
        if (a.string is None): a.string = ''
        if (a.previousSibling is None and a.nextSibling is None):
            a.previousSibling = a.string
        elif (a.previousSibling is None and a.nextSibling is not None):
            a.nextSibling.replaceWith(a.string + a.nextSibling)
        elif (a.previousSibling is not None and a.nextSibling is None):
            a.previousSibling.replaceWith(a.previousSibling + a.string)
        else:
            a.previousSibling.replaceWith(a.previousSibling + a.string + a.nextSibling)
            a.nextSibling.extract()
    i = i+1

عند تشغيل التعليمات البرمجية أعلاه ، أحصل على الخطأ التالي:

0:<a href="http://www.switched.com/category/ces-2010">Stay up to date with 
Switched's CES 2010 coverage</a>
Traceback (most recent call last):
  File "parselink.py", line 44, in <module>
  a.previousSibling.replaceWith(a.previousSibling + a.string + a.nextSibling)
 TypeError: unsupported operand type(s) for +: 'Tag' and 'NavigableString'

عندما أنظر الكود, 'البقاء حتى الآن.." ليس لديه أي سابقة الأخوة (لم أكن كيف السابقة الأخوة عملت حتى رأيت أليكس رمز على أساس الاختبار يبدو أنه يبحث عن "النص" قبل الوسم).لذا, إذا كان هناك أي سابقة الأخوة, أنا مندهش أنه لا يمر إذا كان منطق.previousSibling لا و ألف ؛ nextSibling هو لا شيء.

هل يمكن أن اسمحوا لي أن أعرف ما أقوم به خطأ ؟

-ecognium

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

المحلول

وهو النهج الذي يعمل محددة مثال:

from BeautifulSoup import BeautifulSoup

ht = '''
<div id="abc">
    some long text goes <a href="/"> here </a> and hopefully it 
    will get picked up by the parser as content
</div>
'''
soup = BeautifulSoup(ht)

anchors = soup.findAll('a')
for a in anchors:
  a.previousSibling.replaceWith(a.previousSibling + a.string)

results = soup.findAll(text=lambda(x): len(x) > 20)

print results

التي تنبعث

$ python bs.py
[u'\n    some long text goes  here ', u' and hopefully it \n    will get picked up by the parser as content\n']

وبطبيعة الحال, وربما كنت سوف تحتاج إلى أن تأخذ أكثر قليلا من الرعاية ، أي ما إذا كان هناك أي a.string, أو إذا a.previousSibling هو None -- سوف تحتاج مناسب if البيانات لرعاية مثل هذه الحالات الزاوية.ولكن آمل أن يكون هذا العام فكرة يمكن أن تساعدك.(في الواقع قد ترغب أيضا دمج القادم الأخوة إذا كان سلسلة -- لست متأكدا كيف يلعب مع الاستدلال len(x) > 20, ولكن نقول على سبيل المثال أن لديك اثنين من 9-سلاسل الأحرف مع <a> تحتوي على 5-سلاسل الأحرف في الوسط ربما كنت تريد أن تلتقط الكثير بأنها "23-شخصيات سلسلة"?لا أستطيع أن أقول لأنني لا أفهم الدافع الخاص بك ارشادي).

أتصور أنه إلى جانب <a> العلامات سوف تحتاج أيضا إلى إزالة أخرى ، مثل <b> أو <strong>, ربما <p> و/أو <br>, الخ... ؟ أعتقد أن هذا أيضا يعتمد على ما فكرة الفعلية وراء الاستدلال!

نصائح أخرى

عندما حاولت تتسطح الكلمات في الوثيقة ، أن الطريقة, الكلمات' المحتوى بأكمله سيكون سحب ما يصل إلى العقدة الأصل في مكان (أردت أن تقلل من محتوى p الوسم مع جميع الفقرات الفرعية والقوائم ، div و span, ، وما إلى ذلك.الداخل ولكن التخلص من نمط و الخط العلامات وبعض الرهيبة word إلى html مولد بقايا) ، وجدت أنها معقدة نوعا ما فعله مع BeautifulSoup نفسها منذ استخراج() أيضا إلى إزالة المحتوى ، replaceWith() unfortunatetly لا يقبل لا شيء كما حجة.بعد بعض البرية العودية التجارب ، قررت أخيرا أن استخدام التعابير العادية سواء قبل أو بعد معالجة الوثيقة مع BeautifulSoup مع الطريقة التالية:

import re
def flatten_tags(s, tags):
   pattern = re.compile(r"<(( )*|/?)(%s)(([^<>]*=\\\".*\\\")*|[^<>]*)/?>"%(isinstance(tags, basestring) and tags or "|".join(tags)))
   return pattern.sub("", s)

على tags الحجة إما علامة واحدة أو قائمة من العلامات أن يكون بالارض.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top