Scrapy - 解析页面提取项目 - 然后跟随并存储项目URL内容

24 投票
2 回答
12280 浏览
提问于 2025-04-16 16:37

我有个问题想问关于如何在Scrapy中实现某个功能。我有一个爬虫,它会爬取商品的列表页面。每当找到一个包含商品的列表页面时,就会调用parse_item()这个回调函数来提取商品的数据,并生成商品信息。到目前为止,一切都很好,运行得很顺利。

但是每个商品除了其他数据外,还有一个链接,里面有关于这个商品的更多细节。我想要跟踪这个链接,并把获取到的内容存储在另一个商品字段(url_contents)中。

我不太确定该如何组织代码来实现这个功能,因为这两个链接(列表链接和某个特定商品的链接)是以不同的方式跟踪的,回调函数在不同的时间被调用,但我需要在处理同一个商品时把它们关联起来。

到目前为止,我的代码看起来是这样的:

class MySpider(CrawlSpider):
    name = "example.com"
    allowed_domains = ["example.com"]
    start_urls = [
        "http://www.example.com/?q=example",
    ]

    rules = (
        Rule(SgmlLinkExtractor(allow=('example\.com', 'start='), deny=('sort='), restrict_xpaths = '//div[@class="pagination"]'), callback='parse_item'),
        Rule(SgmlLinkExtractor(allow=('item\/detail', )), follow = False),
    )


    def parse_item(self, response):
        main_selector = HtmlXPathSelector(response)
        xpath = '//h2[@class="title"]'

        sub_selectors = main_selector.select(xpath)

        for sel in sub_selectors:
            item = ExampleItem()
            l = ExampleLoader(item = item, selector = sel)
            l.add_xpath('title', 'a[@title]/@title')
            ......
            yield l.load_item()

2 个回答

2

我也遇到了完全一样的问题,从你提问后两天都没有人回答来看,看来唯一的解决办法就是在你的 parse_item 函数里手动访问那个网址。

我刚接触 Scrapy,所以我不会尝试用它来解决这个问题(虽然我相信是可以做到的),但我的解决办法是使用 urllib 和 BeautifulSoup 手动加载第二页,自己提取那些信息,然后把它保存为 Item 的一部分。是的,这比 Scrapy 正常解析要麻烦得多,但这样做应该能最少麻烦地完成任务。

21

经过一些测试和思考,我找到了一个适合我的解决方案。这个方法的核心是只使用第一个规则,这个规则可以给你列出项目列表。而且,非常重要的是,要在这个规则中添加follow=True。

在parse_item()函数中,你需要返回一个请求,而不是直接返回一个项目,但这个请求是在你加载完项目之后发出的。这个请求是指向项目详细信息的链接。你需要把加载好的项目传给这个请求的回调函数。在回调中处理响应,然后在这里返回项目。

所以,parse_item()的最后部分看起来会是这样的:

itemloaded = l.load_item()

# fill url contents
url = sel.select(item_url_xpath).extract()[0]
request = Request(url, callback = lambda r: self.parse_url_contents(r))
request.meta['item'] = itemloaded

yield request

接着,parse_url_contents()的内容会是这样的:

def parse_url_contents(self, response):
    item = response.request.meta['item']
    item['url_contents'] = response.body
    yield item

如果有人有其他(更好的)办法,请告诉我们。

Stefan

撰写回答