2011-12-29 11 views
2

私はBeautifulSoupを使用してページ上のアドレスのリストを解析しようとしています。テキストと埋め込みタグ付きのタグを取得すると、どのようにしてタグのグラブテキストは、それ以上の(下位レベルの)埋め込みテキストにもテキストが表示されません。埋め込みタグのテキストをさらに取得せずにHTMLタグのテキストを取得するにはどうすればよいですか?

私は.htmlのページに場所から場所へ行くためにPTAGを使用し、ここで私が対処コードです:

Pythonのコマンドラインは、I型:>>>pTag.address

そして、ページコードの以下の部分を受け取る:

<address> 
       Some street address<br />City, State and ZIP<br /> 
<div class="phone"> 
        (123) 456-7890 
       </div> 
</address> 

だから電話をつかむために、私はpTag.address.div.textを入力し、簡単にそれを得ることができます。別のタグにネストされていないアドレステキストを取得したいと思います。私は電話の情報がない場合にエッジケースでre.compileを行うことができましたが、私は何かもっとエレガントなものを望んでいました。

は、基本的にこれは私がより良いBRタグアウトして、欲しいものです:

Some street address<br />City, State and ZIP<br /> 

答えて

1

をそれはextractメソッドを使用してremove elementsすることが可能である:

>>> from BeautifulSoup import BeautifulSoup 
>>> s = '<html><address>Some street address<br />City, State and ZIP<br /><div class="phone">(123) 456-7890</div></address></html>' 
>>> soup = BeautifulSoup(s) 
>>> soup.address.div.extract() 
<div class="phone">(123) 456-7890</div> 
>>> [e.extract() for e in soup.address.findAll('br')] 
[<br />, <br />] 
>>> soup.address.text 
u'Some street addressCity, State and ZIP' 
+0

恐ろしい - 「テキストの最初の行をつかむ」より魔法のような方法がないと、私はこれをもって過渡的に行くだろうと思う。 :) – binarysolo

0

私はむしろあなたが不要なテキスト(divのクラスを削除することができ、のみ BeautifulSoupでその可能性を考えていません= "phone"タグの内容)をテキスト全体から削除します。これは、簡単にを介して達成することができる -

s = '<html><address>Some street address<br />City, State and ZIP<br /><div class="phone">(123) 456-7890</div></address></html>' 
soup = BeautifulSoup(s) 
s1 = soup.address.text     // whole text 
s2 = soup.address.div.text    // unwanted text 
pos = string.find(s1, s2) 
s1 = s1[:pos]       // removing unwanted text 
print s1 
+0

ええ、私は複数の文字列を設定しないことを望んでいましたが、超高速応答のおかげで! – binarysolo

0

あなたがPyQueryを試みることに興味があるなら、ここでそれを行うための別の方法があります:

from pyquery import PyQuery 
s = '<html><address>Some street address<br />City, State and ZIP<br /><div class="phone">(123) 456-7890</div></address></html>' 
d = pyquery.PyQuery(s) 
print d('address').text() 
# 'Some street address City, State and ZIP (123) 456-7890' 
print d('address').remove('*').text() 
# 'Some street address City, State and ZIP' 

これは、テキストコンテンツを抽出する前に、すべての子要素をアドレスから削除します。正規表現で

+0

これはちょっと涼しく、実際にはもっとエレガントですが、別のライブラリが必要です... – binarysolo

0

、それは速いですし、完全なexctractionを容易に可能である:

import re 

ss = '''a line 
another line 
<address> 
    Some street address<br />City, State and ZIP<br /> 
    <div class="phone"> 
     (123) 456-7890 
    </div> 
    <glomo> 
     Hello glomo 
    </glomo> 
</address> 
end of text''' 


def analyze(ss,tag,regx = re.compile('<([^ ]+)([^>]*)>(.*?)</\\1>',re.DOTALL)): 
    extract = re.search('<(%s)[^>]*>(.*?)</\\1>' % tag,ss,re.DOTALL).group(2) 
    li = [] 
    def trt(m): 
     li.append((m.group(1),m.group(2),m.group(3).strip(' \t\r\n'))) 
    li.append(('','',regx.sub(trt,extract).strip('\r\n\t '))) 
    return li 

resu = analyze(ss,'address') 
for el in resu: 
    print el 

print 
print resu[-1][2] 

結果

('div', ' class="phone"', '(123) 456-7890') 
('glomo', '', 'Hello glomo') 
('', '', 'Some street address<br />City, State and ZIP<br />') 

Some street address<br />City, State and ZIP<br /> 

または辞書で結果をputing:

def analyze(ss,tag,regx = re.compile('<([^ ]+)([^>]*)>(.*?)</\\1>',re.DOTALL)): 
    extract = re.search('<(%s)[^>]*>(.*?)</\\1>' % tag,ss,re.DOTALL).group(2) 
    di = {} 
    def trt(m): 
     di[m.group(1)] = (m.group(2),m.group(3).strip(' \t\r\n')) 
    di[''] = ('',regx.sub(trt,extract).strip('\r\n\t ')) 
    return di 

disu = analyze(ss,'address') 
print "disu[''] ==",disu[''] 
print "disu['div'] ==",disu['div'] 
print (disu[x][1] for x in disu if 'phone' in disu[x][0]).next() 

結果

disu[''] == ('', 'Some street address<br />City, State and ZIP<br />') 
disu['div'] == (' class="phone"', '(123) 456-7890') 
(123) 456-7890 

関数は何も返しません(または代わりにNoneを返します)。regx.sub(trt,extract)は、抽出語のfounsタグを""に置き換えます。検査されたタグのテキストのみに残ります。

+0

ええ、私は別のアプローチを考えていました。私はBeautifulSoupがエレガントな3-4ラインのソリューションを提供してくれることを願っていました。 – binarysolo

+0

@binarysolo '' re''はビルトインで、_BeautifulSoup_より速く、_lxml_よりも非常に速いことに注意してください。 – eyquem

+0

ええ、私はそれを理解しています - スピードを上回るシンプルなコード優雅さを追求していたと思います。それ)私は基本的にそれのためにre.compileを避けています。 BeautifulSoupとlxmlはちょっと遅くてかっこ悪いと思いますが...獣の性質だけです。 – binarysolo

1

これはそれを行うことが容易でなければなりませんように感じますが、最高の私が思い付くことができました:

>>> from lxml import etree 
>>> tree = etree.HTML(html) 
>>> tag = tree.xpath('//address')[0] 
>>> ' '.join(tag.xpath('./text()')).strip() 
'Some street address City, State and ZIP' 

はここlxmlを使用して、代替ソリューションです

>>> from BeautifulSoup import BeautifulSoup, NavigableString 
>>> html = """ 
... <html><head></head><body> 
... <address> 
...     Some street address<br />City, State and ZIP<br /> 
... <div class="phone"> 
...      (123) 456-7890 
...     </div> 
... </address> 
... </body></html> 
... """ 
>>> soup = BeautifulSoup(html) 
>>> tag = soup.find('address') 
>>> ' '.join(item for item in tag.contents 
...   if isinstance(item, NavigableString)).strip() 
u'Some street address City, State and ZIP' 

EDIT

+0

私はhuhを知っています...私は同じ方法を感じていました: "もっとエレガントな方法が存在しなければなりません"しかし何も考えることができませんでした。これは既にかなり良いです、そしてNavigableStringsは素晴らしいタッチです。 – binarysolo

関連する問題