scrapy 集成到 django(二) - 处理外键

在上一篇文章中,介绍了如何搭建 scrapy-django 项目,结尾的时候说道,如果在 django-orm 中存在外键,该如何处理呢

项目地址: recruitment

比如在 django/models.py 中


class Recruit(models.Model):

    belong = models.ForeignKey('Firm', verbose_name='所属公司')
    resource = models.CharField('信息来源', max_length=255)
    url = models.URLField('信息链接', default='')
    # ...

class Firm(models.Model):
    # 公司相关信息
    firm_introduction = models.TextField('公司简介')
    # ...


这里定义了一个 belong 外键,因为一家公司可能发布多个职位。处理外键的难度在于,在 pipelines 中一次只能处理一个 item ,按照之前的写法,我们处理的 item 要么是 职位信息,要么是公司信息,这样要将两部分对上号,是有些困难的。

以下给出解决方案
在 crawlend/spiders.py 中处理完数据后


# ...
def parse(self, response):
    item = {}
    offer = CrawlendItem()
    firm = FirmItem()

    offer['resource'] = '智联'
    firm['firm_introduction'] = 'XXXX'
    # ...

    item['offer'] = offer
    item['firm'] = firm

    yield item


看到了么,处理外键的关键在于,一次性将两个 Item 打包到一个 dict 中。这样我们在 pipelines 中解析 dict ,同时取到两个 dict ,这样就可以设置外键了。

pipelines.py


from .items import CrawlendItem, FirmItem, ProxyItem
from backend.models import Proxy, Firm, Recruit

class CrawlendPipeline(object):

    def process_item(self, item, spider):
        '''
        :param item: dict
        :param spider:
        :return:
        '''
        # 检查数据库内是否存在该公司
        def _check_firm(firm_name):
            try:
                ins = Firm.objects.get(firm_name=firm_name)
                return ins
            except:
                return None
        #
        if isinstance(item, dict):

            # 提取 两个 ITEM
            offer = item['offer']
            firm = item['firm']
            f_name = firm['firm_name']
            offers_ = 0
            # 判断该公司是否存在
            if _check_firm(f_name):
                firm = _check_firm(f_name)
                offers_ = len(firm.recruit_set.filter(name=offer['name']))

            # 保存数据
            firm.save()

            # 判断职位是否有重复
            if offers_ == 0:
                offer['belong'] = Firm.objects.get(firm_name=f_name) 
                offer.save()

            return item

思路: 在查看使用基本的 scrapy_djangoitem 库中,发现在 piplines 部分调用了 item.save() 方法,也就是说,在 piplines 中已经将数据保存下来了,所以 return item 这部分已经无关紧要了。

同时查看 scrapy piplines 的官方文档发现, item 可以为 items 定义的类对象也可以为 字典,所以直接想到凑一个 dict ,然后到 piplines 中再解析。

OK,本文章到此结束,下一篇讲讲如何构造代理中间件

posted @ 2017-08-06 17:40  zx576  阅读(858)  评论(0编辑  收藏  举报