python - Scrapy:crawlspider 不生成嵌套回调中的所有链接

标签 python scrapy yield

我写了一个 scrapy crawlspider 来抓取一个结构类似于类别页面 > 类型页面 > 列表页面 > 项目页面的站点。在类别页面上有很多机器类别,每个类别都有一个包含很多类型的类型页面,每个不同类型都有一个项目列表,最后每台机器都有一个包含它的信息的页面。

我的蜘蛛有一个规则,从主页到类别页面,我在其中定义回调 parsecatpage,这会生成一个项目,抓取类别并为页面上的每个类别生成一个新请求。我使用 request.meta 传递项目和类别名称,并指定回调是解析类型页面。

Parsetypepage 从 response.meta 中获取项目,然后为每个类型生成请求并传递项目,以及 request.meta 中类别和类型的串联。回调是parsemachinelist。

Parsemachinelist 从 response.meta 中获取项目,然后为列表中的每个项目生成请求,并通过 request.meta 将项目、类别/类型、描述传递给最终回调 parsemachine。这将获取元属性并使用页面上的信息和从先前页面传递的信息填充项目中的所有字段,最终生成一个项目。

如果我将其限制为单个类别和类型(例如 contains[@href, "filter=c:Grinders"]contains[@href, "filter=t :Disc+-+Horizo​​ntal%2C+Single+End"]) 然后它就可以工作了,最后一页上每台机器都有一个机器项目。问题是,一旦我允许蜘蛛抓取所有类别和所有类型,它只会在它到达的最后一页的第一页返回机器的抓取项目,一旦完成,蜘蛛就完成了,但没有获取其他类别等。

这是(匿名)代码

from scrapy.selector import HtmlXPathSelector
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.http import Request
from myspider.items import MachineItem
import urlparse


class MachineSpider(CrawlSpider):
    name = 'myspider'
    allowed_domains = ['example.com']
    start_urls = ['http://www.example.com/index.php']

    rules = (
        Rule(SgmlLinkExtractor(allow_domains=('example.com'),allow=('12\.html'),unique=True),callback='parsecatpage'),
        )

    def parsecatpage(self, response):
        hxs = HtmlXPathSelector(response)
#this works, next line doesn't   categories = hxs.select('//a[contains(@href, "filter=c:Grinders")]')  
        categories = hxs.select('//a[contains(@href, "filter=c:Grinders") or contains(@href, "filter=c:Lathes")]')
        for cat in categories:
            item = MachineItem()
            req = Request(urlparse.urljoin(response.url,''.join(cat.select("@href").extract()).strip()),callback=self.parsetypepage)
            req.meta['item'] = item
            req.meta['machinecategory'] = ''.join(cat.select("./text()").extract())
            yield req

    def parsetypepage(self, response):
        hxs = HtmlXPathSelector(response)
#this works, next line doesn't   types = hxs.select('//a[contains(@href, "filter=t:Disc+-+Horizontal%2C+Single+End")]')
        types = hxs.select('//a[contains(@href, "filter=t:Disc+-+Horizontal%2C+Single+End") or contains(@href, "filter=t:Lathe%2C+Production")]')
        for typ in types:
            item = response.meta['item']
            req = Request(urlparse.urljoin(response.url,''.join(typ.select("@href").extract()).strip()),callback=self.parsemachinelist)
            req.meta['item'] = item
            req.meta['machinecategory'] = ': '.join([response.meta['machinecategory'],''.join(typ.select("./text()").extract())])
            yield req

    def parsemachinelist(self, response):
        hxs = HtmlXPathSelector(response)
        for row in hxs.select('//tr[contains(td/a/@href, "action=searchdet")]'):
            item = response.meta['item']
            req = Request(urlparse.urljoin(response.url,''.join(row.select('./td/a[contains(@href,"action=searchdet")]/@href').extract()).strip()),callback=self.parsemachine)
            print urlparse.urljoin(response.url,''.join(row.select('./td/a[contains(@href,"action=searchdet")]/@href').extract()).strip())
            req.meta['item'] = item
            req.meta['descr'] = row.select('./td/div/text()').extract()
            req.meta['machinecategory'] = response.meta['machinecategory']
            yield req

    def parsemachine(self, response):
        hxs = HtmlXPathSelector(response)
        item = response.meta['item']
        item['machinecategory'] = response.meta['machinecategory']
        item['comp_name'] = 'Name'
        item['description'] = response.meta['descr']
        item['makemodel'] = ' '.join([''.join(hxs.select('//table/tr[contains(td/strong/text(), "Make")]/td/text()').extract()),''.join(hxs.select('//table/tr[contains(td/strong/text(), "Model")]/td/text()').extract())])
        item['capacity'] = hxs.select('//tr[contains(td/strong/text(), "Capacity")]/td/text()').extract()
        relative_image_url = hxs.select('//img[contains(@src, "custom/modules/images")]/@src')[0].extract()
        abs_image_url = urlparse.urljoin(response.url, relative_image_url.strip())
        item['image_urls'] = [abs_image_url]
        yield item

SPIDER = MachineSpider()

例如,蜘蛛会在类别页面上找到研磨机,然后转到研磨机类型页面,在那里它会找到 Disc Horizo​​ntal Single End 类型,然后它会转到该页面并找到机器列表并转到每个机器页面,最后每台机器都会有一个项目。如果您尝试转到 Grinders 和 Lathes,虽然它会通过 Grinders 正常运行,但它会抓取 Lathes 和 Lathes 类型页面并停在那里,而不会生成对 Lathes 列表页面和最终 Lathes 页面的请求。

有人可以帮忙吗?为什么蜘蛛不进入第二个(或第三个等)机器列表页面,一旦有多个类别的机器?

很抱歉这篇史诗般的帖子,只是想解释一下问题!!

谢谢!!

最佳答案

您应该打印请求的 url,以确保它没问题。你也可以试试这个版本:

def parsecatpage(self, response):
    hxs = HtmlXPathSelector(response)
    categories = hxs.select('//a[contains(@href, "filter=c:Grinders") or contains(@href, "filter=c:Lathes")]')
    for cat in categories:
        item = MachineItem()
        cat_url = urlparse.urljoin(response.url, cat.select("./@href").extract()[0])
        print 'url:', cat_url # to see what's there
        cat_name = cat.select("./text()").extract()[0]
        req = Request(cat_url, callback=self.parsetypepage, meta={'item': item, 'machinecategory': cat_name})
        yield req

关于python - Scrapy:crawlspider 不生成嵌套回调中的所有链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9705184/

相关文章:

python - 碎片 : storing the data

Python:Scrapy 蜘蛛不返回结果?

python - 这个 python 语法是什么意思?

java - Java 中的 Thread.yield() 和 Thread.sleep(0) 有什么区别?

python - Anaconda:安装本地二进制包到Windows中的conda环境

Python自定义日志到数据库

python - 为什么 Pycharm 可以找到我的模块,但不能运行它?

python - 如何在 scrapy 爬虫中使用用户名/密码进行身份验证?

python - 有没有办法将动态 url_prefix 添加到 Flask 应用程序中的所有路由?

flutter - 在 Dart (Flutter) 中将两个 "yield"并排放置,只有第二个被执行