我使用urllib2从网页中获取数据。所有页面的内容均为英文,因此不存在处理非英文文本的问题。然而,页面是编码的,它们有时包含HTML实体,如£或版权符号等。
我想检查页面的某些部分是否包含某些关键字 - 但是,我想进行不区分大小写的检查(原因很明显)。
将返回的网页内容转换为所有小写字母的最佳方法是什么?
def get_page_content_as_lower_case(url):
request = urllib2.Request(url)
page = urllib2.urlopen(request)
temp = page.read()
return str(temp).lower() # this dosen't work because page contains utf-8 data
[[更新]]
我不必使用urllib2来获取数据,实际上我可能会使用BeautifulSoup,因为我需要从页面中的特定元素中检索数据 - 对于哪个BS来说,这是一个更好的选择。我更改了标题以反映这一点。
但是,问题仍然存在,取出的数据是在utf-8中的某些非asci编码(应该是)。我确实检查了其中一个页面,编码是iso-8859-1。
由于我只关心英语,我想知道如何获取从页面检索到的数据的小写ASCII字符串版本 - 这样我就可以对关键字是否进行区分大小写的测试在文中找到。
我假设我仅限于英语(来自英语网站)的事实减少了编码的选择?我对编码知之甚少,但我认为有效的选择是:
这是一个有效的假设,如果是,也许有一种方法可以编写一个'健壮'函数,它接受一个包含英文文本的编码字符串并返回一个小写的ASCII字符串版本吗?
答案 0 :(得分:3)
不区分大小写的字符串搜索比简单搜索低级字符变体更复杂。例如,德国用户希望将STRASSE
和Straße
与搜索字词Straße
匹配,但'STRASSE'.lower() == 'strasse'
(并且您不能简单地替换双与ß相关 - Trasse中没有ß。其他语言(特别是Turkish)也会有类似的复杂情况。
如果您希望支持除英语之外的其他语言,则应使用可以处理正确案例折叠的库(例如Matthew Barnett's regexp
)。
话虽如此,提取页面内容的方法是:
import contextlib
def get_page_content(url):
with contextlib.closing(urllib2.urlopen(url)) as uh:
content = uh.read().decode('utf-8')
return content
# You can call .lower() on the result, but that won't work in general
答案 1 :(得分:2)
或Requests:
page_text = requests.get(url).text
lowercase_text = page_text.lower()
(请求将自动解码响应。)
正如@tchrist所说,.lower()
将无法完成unicode文本的工作。
您可以查看这个替代正则表达式实现,该实现为unicode不区分大小写的比较实现了案例折叠:http://code.google.com/p/mrab-regex-hg/
还有可用的案例折叠表:http://unicode.org/Public/UNIDATA/CaseFolding.txt
答案 2 :(得分:1)
BeautifulSoup在内部将数据存储为Unicode,因此您无需手动执行字符编码操作。
在文本中查找关键字(不区分大小写)(属性值中的不或标记名称):
#!/usr/bin/env python
import urllib2
from contextlib import closing
import regex # pip install regex
from BeautifulSoup import BeautifulSoup
with closing(urllib2.urlopen(URL)) as page:
soup = BeautifulSoup(page)
print soup(text=regex.compile(ur'(?fi)\L<keywords>',
keywords=['your', 'keywords', 'go', 'here']))
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import regex
from BeautifulSoup import BeautifulSoup, Comment
html = u'''<div attr="PoSt in attribute should not be found">
<!-- it must not find post inside a comment either -->
<ol> <li> tag names must not match
<li> Post will be found
<li> the same with post
<li> and post
<li> and poſt
<li> this is ignored
</ol>
</div>'''
soup = BeautifulSoup(html)
# remove comments
comments = soup.findAll(text=lambda t: isinstance(t, Comment))
for comment in comments: comment.extract()
# find text with keywords (case-insensitive)
print ''.join(soup(text=regex.compile(ur'(?fi)\L<opts>', opts=['post', 'li'])))
# compare it with '.lower()'
print '.lower():'
print ''.join(soup(text=lambda t: any(k in t.lower() for k in ['post', 'li'])))
# or exact match
print 'exact match:'
print ''.join(soup(text=' the same with post\n'))
Post will be found
the same with post
and post
and poſt
.lower():
Post will be found
the same with post
exact match:
the same with post