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,本文章到此结束,下一篇讲讲如何构造代理中间件