【问题标题】:Python - problem with accented chars when scraping data from websitePython - 从网站抓取数据时重音字符的问题
【发布时间】:2011-09-30 18:47:15
【问题描述】:

我是 Nicola,一个没有真正的计算机编程背景的 Python 新用户。因此,我真的需要一些帮助来解决我遇到的问题。我写了一个代码来从这个网页上抓取数据:

http://finanzalocale.interno.it/sitophp/showQuadro.php?codice=2080500230&tipo=CO&descr_ente=MODENA&anno=2009&cod_modello=CCOU&sigla=MO&tipo_cert=C&isEuro=0&quadro=02

基本上,我的代码的目标是从页面中的所有表中抓取数据并将它们写入 txt 文件。 我在这里粘贴我的代码:

#!/usr/bin/env python


from mechanize import Browser
from BeautifulSoup import BeautifulSoup
import urllib2, os


def extract(soup):
table = soup.findAll("table")[1]
for row in table.findAll('tr')[1:19]:
        col = row.findAll('td')
        voce = col[0].string
        accertamento = col[1].string
        competenza = col[2].string
        residui = col[3].string
        record = (voce, accertamento, competenza, residui)
        print >> outfile, "|".join(record)

table = soup.findAll("table")[2]
for row in table.findAll('tr')[1:21]:
        col = row.findAll('td')
        voce = col[0].string
        accertamento = col[1].string
        competenza = col[2].string
        residui = col[3].string
        record = (voce, accertamento, competenza, residui)
        print >> outfile, "|".join(record)

table = soup.findAll("table")[3]
for row in table.findAll('tr')[1:44]:
        col = row.findAll('td')
        voce = col[0].string
        accertamento = col[1].string
        competenza = col[2].string
        residui = col[3].string
        record = (voce, accertamento, competenza, residui)
        print >> outfile, "|".join(record)

table = soup.findAll("table")[4]
for row in table.findAll('tr')[1:18]:
        col = row.findAll('td')
        voce = col[0].string
        accertamento = col[1].string
        competenza = col[2].string
        residui = col[3].string
        record = (voce, accertamento, competenza, residui)
        print >> outfile, "|".join(record)

    table = soup.findAll("table")[5]
for row in table.findAll('tr')[1:]:
        col = row.findAll('td')
        voce = col[0].string
        accertamento = col[1].string
        competenza = col[2].string
        residui = col[3].string
        record = (voce, accertamento, competenza, residui)
        print >> outfile, "|".join(record)

    table = soup.findAll("table")[6]
for row in table.findAll('tr')[1:]:
        col = row.findAll('td')
        voce = col[0].string
        accertamento = col[1].string
        competenza = col[2].string
        residui = col[3].string
        record = (voce, accertamento, competenza, residui)
        print >> outfile, "|".join(record)


outfile = open("modena_quadro02.txt", "w")
br = Browser()
br.set_handle_robots(False)
url = "http://finanzalocale.interno.it/sitophp/showQuadro.php?codice=2080500230&tipo=CO&descr_ente=MODENA&anno=2009&cod_modello=CCOU&sigla=MO&tipo_cert=C&isEuro=0&quadro=02"
page1 = br.open(url)
html1 = page1.read()
soup1 = BeautifulSoup(html1)
extract(soup1)
outfile.close()

一切都可以正常工作,但该页面中某些表格的第一列包含带有重音字符的单词。 当我运行代码时,我得到以下信息:

Traceback (most recent call last):
File "modena2.py", line 158, in <module>
  extract(soup1)
File "modena2.py", line 98, in extract
  print >> outfile, "|".join(record)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 32: ordinal not in range(128)

我知道问题出在重音字符的编码上。我试图找到解决方案,但这确实超出了我的知识范围。 我要提前感谢所有愿意帮助我的人。我真的很感激! 如果这个问题太基础了,很抱歉,但是,正如我所说,我刚刚开始使用 python,我正在自学一切。

谢谢! 尼古拉

【问题讨论】:

  • 我强烈建议您阅读 Python 文档中的 article by Joel Spolskythis one。在这种特定情况下,您的问题可以通过将"|"更改为u"|"来解决

标签: python unicode beautifulsoup web-scraping diacritics


【解决方案1】:

我会根据反馈再试一次。由于您使用 print 语句来生成输出,因此您的输出必须是字节而不是字符(这是当今操作系统的现实)。默认情况下,Python 的 sys.stdout(打印语句写入的内容)使用“ascii”字符编码。因为只有 0 到 127 的字节值是由 ASCII 定义的,所以这些是您可以打印的唯一字节值。因此字节值错误'\xe0'

您可以通过这样做将sys.stdout 的字符编码更改为UTF-8:

import codecs, sys
sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
print u'|'.join([u'abc', u'\u0100'])

上面的打印语句不会抱怨打印不能用 ASCII 编码表示的 Unicode 字符串。但是,下面的代码打印字节而不是字符,会产生 UnicodeDecodeError 异常,所以要小心:

import codecs, sys
sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
print '|'.join(['abc', '\xe0'])

您可能会发现您的代码正在尝试打印字符,而将 sys.stdout 的字符编码设置为 UTF-8(或 ISO-8859-1)可以解决此问题。但是您可能会发现代码正在尝试打印字节(从 BeautifulSoup API 获得),在这种情况下,修复可能是这样的:

import codecs, sys
sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
print '|'.join(['abc', '\xe0']).decode('ISO-8859-1')

我对BeautifulSoup包不熟悉,但我建议用各种文档测试它,看看它对字符编码的检测是否正确。您的代码没有明确提供编码,它显然是自行决定编码。如果该决定来自meta 编码标签,那就太好了。

【讨论】:

    【解决方案2】:

    编辑:我刚刚尝试过,因为我假设您最后想要一个表格,这是一个导致 csv 的解决方案。

    from mechanize import Browser
    from BeautifulSoup import BeautifulSoup
    import urllib2, os
    import csv
    
    
    def extract(soup):
        table = soup.findAll("table")[1]
        for row in table.findAll('tr')[1:19]:
                col = row.findAll('td')
                voce = col[0].string
                accertamento = col[1].string
                competenza = col[2].string
                residui = col[3].string
                record = (voce, accertamento, competenza, residui)
                outfile.writerow([s.encode('utf8') if type(s) is unicode else s for s in record])
    
        # swap print for outfile statement in all other blocks as well
        # ... 
    
    outfile = csv.writer(open(r'modena_quadro02.csv','wb'))
    br = Browser()
    br.set_handle_robots(False)
    url = "http://finanzalocale.interno.it/sitophp/showQuadro.php?codice=2080500230&tipo=CO&descr_ente=MODENA&anno=2009&cod_modello=CCOU&sigla=MO&tipo_cert=C&isEuro=0&quadro=02"
    page1 = br.open(url)
    html1 = page1.read()
    soup1 = BeautifulSoup(html1)
    extract(soup1)
    

    【讨论】:

      【解决方案3】:

      上周我遇到了类似的问题。在我的 IDE (PyCharm) 中很容易修复。

      这是我的解决方法:

      从 PyCharm 菜单栏开始:文件 -> 设置... -> 编辑器 -> 文件编码,然后设置:“IDE 编码”、“项目编码”和“属性文件的默认编码”全部为 UTF-8 和她现在的工作就像一个魅力。

      希望这会有所帮助!

      【讨论】:

        【解决方案4】:

        问题在于将 Unicode 文本打印到二进制文件:

        >>> print >>open('e0.txt', 'wb'), u'\xe0'
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 0: ordinal not in range(128)
        

        要修复它,请将 Unicode 文本编码为字节 (u'\xe0'.encode('utf-8')) 或以文本模式打开文件:

        #!/usr/bin/env python
        from __future__ import print_function
        import io
        
        with io.open('e0.utf8.txt', encoding='utf-8') as file:
            print(u'\xe0', file=file)
        

        【讨论】:

          【解决方案5】:
          猜你喜欢
          • 2019-06-01
          • 1970-01-01
          • 2018-10-04
          • 1970-01-01
          • 2019-09-26
          • 2016-11-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多