Python Scrapy无法正确解析某些html文件

Python Scrapy无法正确解析某些html文件,python,scrapy,Python,Scrapy,我已经使用了Scrapy几个星期了,最近,我发现HtmlXPathSelector无法正确解析一些html文件 在网页中,只有一个名为 `div id='param-more' class='mod_param '`. 当我使用xpath//div[@id='param-more']选择标记时,它返回[] 我试过scrapy shell,也得到了同样的结果 当使用wget检索网页时,我还可以在html源文件中找到标签div id='param-more'class='mod_param',

我已经使用了Scrapy几个星期了,最近,我发现HtmlXPathSelector无法正确解析一些html文件

在网页中,只有一个名为

`div id='param-more' class='mod_param  '`. 
当我使用xpath//div[@id='param-more']选择标记时,它返回[]

我试过scrapy shell,也得到了同样的结果

当使用wget检索网页时,我还可以在html源文件中找到标签div id='param-more'class='mod_param',我认为这不是由于触发操作而显示标签的原因造成的

请给我一些解决这个问题的建议

下面是关于这个问题的代码sinppet。处理上述url时,lennodes_产品始终为0


这似乎是XPathSelectors的一个bug。我创建了一个快速测试爬行器,遇到了同样的问题。我相信这与页面上的非标准字符有关

我认为问题不在于“param more”div与任何javascript事件或CSS隐藏相关联。我禁用了javascript,还更改了我的用户代理和位置,以查看这是否影响了页面上的数据。没有

但是,我能够使用beautifulsoup解析“param more”div:

from scrapy.selector import HtmlXPathSelector
from scrapy.spider import BaseSpider
from bs4 import BeautifulSoup

class TestSpider(BaseSpider):
    name = "Test"

    start_urls = [
        "http://detail.zol.com.cn/series/268/10227_1.html"
                 ]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)

        #data = hxs.select("//div[@id='param-more']").extract()

        data = response.body
        soup = BeautifulSoup(data)
        print soup.find(id='param-more')
其他人可能更了解XPathSelect问题,但目前,您可以将beautifulsoup找到的HTML保存到项目中,并将其传递到管道中

以下是指向最新beautifulsoup版本的链接:

更新

我相信我找到了具体的问题。正在讨论的网页在元标记中指定它使用。从GB 2312到unicode的转换是有问题的,因为有些字符没有字符。这不是问题,除了UnicodeAmmit,beautifulsoup的编码检测模块,实际上确定编码为ISO 8859-2。问题是lxml通过查看。因此,lxml和scrapy感知到的编码类型不匹配

以下代码演示了上述问题,并提供了一种不必依赖BS4库的替代方案:

from scrapy.selector import HtmlXPathSelector
from scrapy.spider import BaseSpider
from bs4 import BeautifulSoup
import chardet

class TestSpider(BaseSpider):
    name = "Test"

    start_urls = [
        "http://detail.zol.com.cn/series/268/10227_1.html"
                 ]

    def parse(self, response):

        encoding = chardet.detect(response.body)['encoding']
        if encoding != 'utf-8':
            response.body = response.body.decode(encoding, 'replace').encode('utf-8')

        hxs = HtmlXPathSelector(response)
        data = hxs.select("//div[@id='param-more']").extract()
        #print encoding
        print data
在这里,您可以看到,通过强制lxml使用utf-8编码,它不会试图从它认为的GB2312->utf-8映射

在scrapy中,HTMLXPathSelectors编码在scrapy/select/lxmlsel.py模块中设置。该模块使用response.encoding属性将响应主体传递给lxml解析器,该属性最终在scrapy/http/response/test.py模块中设置

处理设置response.encoding属性的代码如下:

@property
def encoding(self):
    return self._get_encoding(infer=True)

def _get_encoding(self, infer=False):
    enc = self._declared_encoding()
    if enc and not encoding_exists(enc):
        enc = None
    if not enc and infer:
        enc = self._body_inferred_encoding()
    if not enc:
        enc = self._DEFAULT_ENCODING
    return resolve_encoding(enc)

def _declared_encoding(self):
    return self._encoding or self._headers_encoding() \
        or self._body_declared_encoding()
这里需要注意的重要一点是_headers _encoding和_encoding最终都会反映头中meta标记中声明的编码,而实际上是使用UnicodeAmmit或chardet之类的东西来确定文档编码。因此,当文档包含指定编码的无效字符时,就会出现这种情况,我相信Scrapy会忽略这一点,最终导致我们今天看到的问题

'mod_param ' != 'mod_param'
该类不等于mod_param,但它确实包含mod_param,请注意末尾有一个空格:

stav@maia:~$ scrapy shell http://detail.zol.com.cn/series/268/10227_1.html
2012-08-23 09:17:28-0500 [scrapy] INFO: Scrapy 0.15.1 started (bot: scrapybot)
Python 2.7.3 (default, Aug  1 2012, 05:14:39)
IPython 0.12.1 -- An enhanced Interactive Python.

In [1]: hxs.select("//div[@class='mod_param']")
Out[1]: []

In [2]: hxs.select("//div[contains(@class,'mod_param')]")
Out[2]: [<HtmlXPathSelector xpath="//div[contains(@class,'mod_param')]" data=u'<div id="param-more" class="mod_param  "'>]

In [3]: len(hxs.select("//div[contains(@class,'mod_param')]").extract())
Out[3]: 1

In [4]: len(hxs.select("//div[contains(@class,'mod_param')]").extract()[0])
Out[4]: 5372

请显示返回错误结果的特定代码。代码段刚刚添加:默认情况下,HtmlXPathSelector使用lxml作为后端,可能它与lxml无法处理的html源文件有问题。当问题出现时,我将使用BeautifulSoup来处理此类网页。非常感谢:D*特别发现了问题。我提供了一个替代我以前绕过这个问题的方法。哇,它很管用!但是,我爬过了好几百个simliar页面,比如[只有这个页面有问题。例如,[has a simliar tag div id='param-normal,我可以使用HtmlXPathSelector获取标记。这些页面具有相同的“字符集”。在处理html源文件之前检查字符集是一种很好的做法。再次感谢:我认为问题在于,尽管在原始页面上,存在非法字符,但由于它们的字符集与meta标记中指定的字符集不同。我的猜测是,如果它在具有类似结构和内容的其他页面上工作,那么只有第一个页面具有非法的错误映射字符。它们可能超出了charmap识别的字符集的范围。无论如何,我很高兴你能让它工作!Cong老鼠!谢谢你在scrapy用户邮件列表中的帮助:但是当我尝试你的方法时,它仍然得到相同的结果[]
stav@maia:~$ scrapy shell http://detail.zol.com.cn/series/268/10227_1.html
2012-08-23 09:17:28-0500 [scrapy] INFO: Scrapy 0.15.1 started (bot: scrapybot)
Python 2.7.3 (default, Aug  1 2012, 05:14:39)
IPython 0.12.1 -- An enhanced Interactive Python.

In [1]: hxs.select("//div[@class='mod_param']")
Out[1]: []

In [2]: hxs.select("//div[contains(@class,'mod_param')]")
Out[2]: [<HtmlXPathSelector xpath="//div[contains(@class,'mod_param')]" data=u'<div id="param-more" class="mod_param  "'>]

In [3]: len(hxs.select("//div[contains(@class,'mod_param')]").extract())
Out[3]: 1

In [4]: len(hxs.select("//div[contains(@class,'mod_param')]").extract()[0])
Out[4]: 5372