【问题标题】:Unicode and UTF-8 encoding issue with Scrapy XPath selector textScrapy XPath 选择器文本的 Unicode 和 UTF-8 编码问题
【发布时间】:2011-04-11 21:37:24
【问题描述】:

我正在使用 Scrapy 和 Python(作为 Django 项目的一部分)来抓取包含德语内容的网站。我安装了libxml2 作为 Scrapy 选择器的后端。

如果我通过选择器提取单词'Hüftsitz'(这是它在网站上的显示方式),我得到:u'H\ufffd\ufffdftsitz'(Scrapy XPath 选择器返回 Unicode 字符串)。

如果我把它编码成UTF-8,我得到:'H\xef\xbf\xbd\xef\xbf\xbdftsitz'。如果我打印出来,我会得到'H??ftsitz',这是不正确的。我想知道为什么会发生这种情况。

网站上的character-set 设置为UTF-8。我正在将sys.getdefaultencoding 设置为UTF-8 的Python shell 上测试上述内容。使用 Django 应用程序,其中来自 XPath 选择器的数据被写入具有 UTF-8 字符集的 MySQL 数据库,我看到了相同的行为。

我在这里忽略了一些明显的东西吗?任何线索或帮助将不胜感激。

【问题讨论】:

    标签: python django unicode utf-8 scrapy


    【解决方案1】:

    u'\ufffd' 是"unicode replacement character",通常打印为黑色三角形内的问号。不是 u 变音符号。所以问题一定出在上游的某个地方。检查返回的网页标题所说的编码,并验证它实际上是什么,它说的是什么。

    插入 unicode 替换字符通常是为了替换非法或无法识别的字符,这可能是由多种原因引起的,但最有可能的是 编码不是它声称的那样。

    【讨论】:

      【解决方案2】:

      非常感谢您的回答,约翰和史蒂文。你的回答让我有了不同的想法,这让我找到了问题的根源,也找到了一个可行的解决方案。

      我正在使用以下测试代码:

      import urllib
      import urllib2
      from scrapy.selector import HtmlXPathSelector
      from scrapy.http import HtmlResponse
      
      URL = "http://jackjones.bestsellershop.com/DE/jeans/clark-vintage-jos-217-sup/37246/37256"
      
      url_handler = urllib2.build_opener()
      urllib2.install_opener(url_handler)
      
      handle = url_handler.open(URL)
      response = handle.read()
      handle.close()
      
      html_response = HtmlResponse(URL).replace(body=response) # Problematic line
      hxs = HtmlXPathSelector(html_response)
      
      desc = hxs.select('//span[@id="attribute-content"]/text()')
      desc_text = desc.extract()[0]
      print desc_text
      print desc_text.encode('utf-8')
      

      在 Scrapy shell 中,当我提取描述数据时,结果很好。这让我有理由怀疑我的代码有问题,因为在 pdb 提示符下,我看到提取数据中的替换字符。

      我浏览了 Response class 的 Scrapy 文档并将上面的代码调整为:

      import urllib
      import urllib2
      from scrapy.selector import HtmlXPathSelector
      from scrapy.http import HtmlResponse
      
      URL = "http://jackjones.bestsellershop.com/DE/jeans/clark-vintage-jos-217-sup/37246/37256"
      
      url_handler = urllib2.build_opener()
      urllib2.install_opener(url_handler)
      
      handle = url_handler.open(URL)
      response = handle.read()
      handle.close()
      
      #html_response = HtmlResponse(URL).replace(body=response)
      html_response = HtmlResponse(URL, body=response)
      hxs = HtmlXPathSelector(html_response)
      
      desc = hxs.select('//span[@id="attribute-content"]/text()')
      desc_text = desc.extract()[0]
      print desc_text
      print desc_text.encode('utf-8')
      

      我所做的更改是将html_response = HtmlResponse(URL).replace(body=response) 行替换为html_response = HtmlResponse(URL, body=response)。据我了解,replace() 方法从编码的角度以某种方式破坏了特殊字符。

      如果有人想详细说明replace() 方法到底做错了什么,我将非常感谢您的努力。

      再次感谢您。

      【讨论】:

        【解决方案3】:

        U+FFFD 是您在执行some_bytes.decode('some-encoding', 'replace') 时得到的替换字符,some_bytes 的某些子字符串无法解码。

        你有两个:u'H\ufffd\ufffdftsitz' ...这表明 u-umlaut 被表示为两个字节,每个字节都未能解码。最有可能的是,该站点以 UTF-8 编码,但软件正试图将其解码为 ASCII。尝试解码为 ASCII 通常发生在意外转换为 Unicode 时,并且使用 ASCII 作为默认编码。但是,在这种情况下,人们不会期望使用 'replace' arg。代码更有可能采用编码并且由认为“不引发异常”与“有效”含义相同的人编写。

        编辑您的问题以提供 URL,并显示生成u'H\ufffd\ufffdftsitz'最小代码。

        【讨论】:

        • 非常感谢您的回复,约翰。我发现了问题并提供了解释它的答案。
        猜你喜欢
        • 2016-03-12
        • 2023-03-15
        • 2018-06-17
        • 2019-10-30
        • 2018-01-16
        • 1970-01-01
        • 2010-12-26
        • 2010-10-09
        • 2013-09-11
        相关资源
        最近更新 更多