无法获得正确的Xpath

时间:2015-08-20 11:03:57

标签: xml xpath web-crawler scrapy scrapy-spider

我正在尝试使用常规xpath从购物小部件中提取所有产品链接和图像链接。

这是网站: http://www.stopitrightnow.com/

这是我的xpath:

xpath('.//*[@class="shopthepost-widget"]/a/@href').extract()

我认为这会拉动所有链接,但它什么都不做。

以下是窗口小部件源的开头供参考。

class="shopthepost-widget" data-widget-id="708473" data-widget-uid="1"><div id="stp-55d44feabd0eb" class="stp-outer stp-no-controls ">
    <a class="stp-control stp-left stp-hidden">&lt;</a>
    <div class="stp-inner">
        <div class="stp-slide" style="left: -0%">
                        <a href="http://rstyle.me/iA-n/zzhv34c_" target="_blank" rel="nofollow" class="stp-product " data-index="0">
                <span class="stp-help"></span>
                <img src="//images.rewardstyle.com/img?v=2.13&amp;p=n_24878713">
                            </a>
                        <a href="http://rstyle.me/iA-n/zzhvw4c_" target="_blank" rel="nofollow" class="stp-product " data-index="1">
                <span class="stp-help"></span>
                <img src="//images.rewardstyle.com/img?v=2.13&amp;p=n_24878708">
                            </a>

只是复制xpath将是具体的。

任何和所有帮助将不胜感激。

更新

这是蜘蛛。

import scrapy
from scrapy.spiders import Spider
from scrapy.selector import Selector
from main.items import MainItem


class WebSpider(scrapy.Spider):
    name = "web"
    allowed_domains = ["stopitrightnow.com"]
    start_urls = (
        'http://www.stopitrightnow.com/',
    )

    def parse(self, response):
        sel = Selector(response)
        titles = sel.xpath('.//h3[@class="post-title entry-title"]//text()').extract()
        dates = sel.xpath('.//h2[@class="date-header"]/span/text()').extract()
        picUrls = sel.xpath('.//div[@class="post-body entry-content"]//@href').extract()
        stockUrls = sel.xpath('.//*[@class="stp-slide"]/a/@href').extract()

        items = []

        for title, date, picUrl, stockUrl in zip(titles, dates, picUrls, stockUrls):
            item = MainItem()
            item["title"] = title.strip()
            item["date"] = date.strip()
            item["picUrl"] = picUrl.strip()
            item["stockUrl"] = stockUrl.strip()
            items.append(item)
        return items

3 个答案:

答案 0 :(得分:3)

如果您查看Scrapy看到的结果,您可以看到在使用class="shopthepost-widget"创建标记时涉及一些JavaScript:

<div class="shopthepost-widget" data-widget-id="909962">
<script type="text/javascript">!function(d,s,id){var e, p = /^http:/.test(d.location) ? 'http' : 'https';if(!d.getElementById(id)) {e = d.createElement(s);e.id = id;e.src = p + '://' + 'widgets.rewardstyle.com' + '/js/shopthepost.js';d.body.appendChild(e);}if(typeof window.__stp === 'object') if(d.readyState === 'complete') {window.__stp.init();}}(document, 'script', 'shopthepost-script');</script><br>
<div class="rs-adblock">
<img onerror="this.parentNode.innerHTML='Disable your ad blocking software to view this content.'" src="//assets.rewardstyle.com/images/search/350.gif" style="height: 15px; width: 15px;"><noscript>JavaScript is currently disabled in this browser. Reactivate it to view this content.</noscript></div>
</div>

您可以使用以下命令来实现:

def parse(self, response):
    for widget in response.xpath("//*[@class='shopthepost-widget']"):
        print widget.extract()

浏览器执行JavaScript代码 - 但Scrapy没有。这就是为什么你必须在Scrapy中验证你的输入。

答案 1 :(得分:2)

从您的代码中,您不熟悉Selector类及其工作原理。我强烈建议您查看Selector类并熟悉它以便可靠地使用它。这非常重要,因为response.xpath只是response.selector.xpath的便捷方法,response.selector是一个以Selector作为文本的response.body类。

有了这个,我将假设Scrapy实际上看到的是提供的HTML并仅解决xpath问题。

在另一个问题(这个问题的副本)中,您写道您正在使用以下内容来获取项目:

for widget in response.xpath("//div[@class='shopthepost-widget']"):
    print response.xpath('.//*[@class="shopthepost-widget"]//a/@href').extract()

实际上,您正在重新处理整个树,并为每个小部件重新提取每个匹配项,而不仅仅是该节点中的那些项。

使用widget而不是重新解析整个页面。 widget将是一个实例Selector课程,可以解决您已经完成的选择。

for widget in response.xpath("//div[@class='shopthepost-widget']"):
    print widget.xpath('.//a/@href').extract()

在您的抓取工具中出现另一个明显问题时,这一点再次显而易见。在您的parse方法中。您从页面上的各个位置提取数据,然后将它们全部压缩,并假设所有内容都匹配正确。如果帖子没有标题怎么办?然后你错误地将每篇文章归结为日期/链接等。所有缺失的条目级联以进一步搞乱您的项目。

相反,逐个选择帖子条目并使用它们:

for post in response.xpath('//div[@class="post hentry"]'):
    title = post.xpath('.//h3[@class="post-title entry-title"]//text()'.extract()
    date = post.xpath('.//h2[@class="date-header"]/span/text()').extract()
    # Do more stuff here...

这将仅选择您正在处理的节点下方找到的相关标签,而不是在整个响应范围内。您维护已存在的层次关系,并拥有可靠的数据。

我强烈建议您重新阅读整个Scrapy文档并熟悉它。如果您要进一步做任何事情或刮刮多个页面,也可以转换为生成器并使用yield代替return

答案 2 :(得分:1)

您还需要为a元素添加双斜杠:

xpath('.//*[@class="shopthepost-widget"]//a/@href').extract()

xpath中的第一个.意味着您需要在该点拥有正确的上下文。如果“当前节点”是小部件的任何父节点,它将正常工作,否则它将不会。

xpath也可以优化,因为//相对昂贵。例如,如果您知道始终是直接父级,则可以首先定位<div class="stp-slide" />

xpath('.//*[@class="stp-slide"]/a/@href').extract()