从使用urllib2或BeautifulSoup获取的(可能已编码的)字符串返回小写ASCII字符串

时间:2012-01-26 00:45:45

标签: python utf-8

我使用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
  • ISO-8859-1
  • UTF-8

这是一个有效的假设,如果是,也许有一种方法可以编写一个'健壮'函数,它接受一个包含英文文本的编码字符串并返回一个小写的ASCII字符串版本吗?

3 个答案:

答案 0 :(得分:3)

不区分大小写的字符串搜索比简单搜索低级字符变体更复杂。例如,德国用户希望将STRASSEStraß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']))

示例(@tchrist的Unicode词语)

#!/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