BeautifulSoup的stripped_strings中换行符太多... 如何获取更接近原始HTML的纯文本格式?
使用Python 2.7和bs4,考虑以下这段HTML代码:
<div class="pd-t10">
<ul class="bullet-list c-body pd-b20">
<li class="mr-t20">
<strong>
<em>Innerhalb Deutschlands</em>
</strong>: 0800 100 6711</li>
<li class="mr-t20">International: Siehe die Liste der
<a href="/de/support/contacts/us_support.html" fallback="Auf Englisch" target="new">gebührenfreien Telefonnummern weltweit</a> von VMware.</li>
<li class="mr-t20">
<strong>Wichtiger Hinweis:</strong> Bitte halten Sie Ihre
<a href="/de/support/customer-number-faq.html" fallback="Auf Englisch">Kundennummer</a> bereit, wenn Sie den Support anrufen. Wenn Sie über ein VMware-Konto verfügen, finden Sie Ihre Kundennummer auf der
<a href="/account/secure/customerRegistration.do?action=existingCustomer">Profilseite</a>.</li>
</ul>
</div>
用.stripped_strings可以提取出文本,但打印出来的纯文本格式和浏览器显示的样子不太一样:
for x in foo.stripped_strings:
print x
结果是:
Innerhalb Deutschlands
: 0800 100 6711
International: Siehe die Liste der
gebührenfreien Telefonnummern weltweit
von VMware.
Wichtiger Hinweis:
Bitte halten Sie Ihre
Kundennummer
bereit, wenn Sie den Support anrufen. Wenn Sie über ein VMware-Konto verfügen, finden Sie Ihre Kundennummer auf der
Profilseite
.
但我想看到的是:
Innerhalb Deutschlands: 0800 100 6711
International: Siehe die Liste der gebührenfreien Telefonnummern weltweit von VMware.
Wichtiger Hinweis: Bitte halten Sie Ihre Kundennummer bereit, wenn Sie den Support anrufen. Wenn Sie über ein VMware-Konto verfügen, finden Sie Ihre Kundennummer auf der Profilseite.
有没有什么聪明的方法我没想到?使用get_text和find_all(text=True)得到的结果也差不多……
再多说一点……让我困惑的是:这些soup对象似乎即使在标签被移除后,仍然保留了一些记忆……
如果我们对每个不是<p>
、<li>
或<br>
的标签使用.unwrap(),foo会变成:
<div class="pd-t10">
<li class="mr-t20">
Innerhalb Deutschlands
: 0800 100 6711</li>
<li class="mr-t20">International: Siehe die Liste der
gebührenfreien Telefonnummern weltweit von VMware.</li>
<li class="mr-t20">
Wichtiger Hinweis: Bitte halten Sie Ihre
Kundennummer bereit, wenn Sie den Support anrufen. Wenn Sie über ein VMware-Konto verfügen, finden Sie Ihre Kundennummer auf der
Profilseite.</li>
</div>
但这仍然没有达到你预期的效果:
[txt for txt in foo.stripped_strings]
[u'Innerhalb Deutschlands', u': 0800 100 6711', u'International: Siehe die Liste der', u'geb\xfchrenfreien Telefonnummern weltweit', u'von VMware.', u'Wichtiger Hinweis:', u'Bitte halten Sie Ihre', u'Kundennummer', u'bereit, wenn Sie den Support anrufen. Wenn Sie \xfcber ein VMware-Konto verf\xfcgen, finden Sie Ihre Kundennummer auf der', u'Profilseite', u'.']
不过,如果我们把去掉标签的代码写入一个临时文件,然后把它作为一个新的soup对象打开,我们就能更接近想要的结果:
[txt for txt in newSoup.stripped_strings]
[u'Innerhalb Deutschlands\n: 0800 100 6711', u'International: Siehe die Liste der \n geb\u7aefhrenfreien Telefonnummern weltweit von VMware.', u'Wichtiger Hinweis: Bitte halten Sie Ihre \n Kundennummer bereit, wenn Sie den Support anrufen. Wenn Sie \u7aefber ein VMware-Konto verf\u7aefgen, finden Sie Ihre Kundennummer auf der \n Profilseite.']
现在只需要把每个列表项中的换行符替换成空格,并去掉多余的空白(' '.join(listitem.split())
)。这样就解决了这个一般性的问题,但这并没有解释为什么直接输出字符串并创建一个新的soup对象的行为和现有的soup对象不一样。
1 个回答
1
我从来不抓取整个文本,而是总是有针对性地抓取。
不过既然你想要这样做,那我会使用下面这种简单的工具来找到正确的解决方案。
记住,我假设数据总是以这种格式出现 a:b
,就像 Innerhalb Deutschlands: 0800 100 6711
这样。
所以我会这样处理你的 html
:
soup=BeautifulSoup(html)
text=soup.text.replace("\n:",":").replace("\n "," ")
text=text.split("\n")
text=filter(None, text) # This is to remove the empty elements
text=[" ".join(c.split()) for c in text] # To remove the extra whitespaces
for i in text:
print i
Out[46]:
Innerhalb Deutschlands: 0800 100 6711
International: Siehe die Liste der gebührenfreien Telefonnummern weltweit von VMware.
Wichtiger Hinweis: Bitte halten Sie Ihre Kundennummer bereit, wenn Sie den Support anrufen. Wenn Sie über ein VMware-Konto verfügen, finden Sie Ihre Kundennummer auf der Profilseite.
希望这能帮到你 :-)