上回,我已经大概把爬虫写出来了。
我写了一个内容爬虫,一个爬取tag里面内容链接的爬虫
其实还差一个,就是收集一共有哪些tag的爬虫。但是这里先不说这个问题,因为我上次忘了 这次又不想弄。。
还有个原因:如果实际采集的话,直接用http://segmentfault.com/questions/newest?page=1
这个链接 获取所有问题,挨个爬就行。
进入正题
第三部分,采集入库。
3.1 定义数据库(or model or schema)
为了入库,我需要在Django定义一个数据库的结构。(不说nosql和mongodb(也是一个nosql但是很像关系型)的事)
还记得那个名叫web的app么,里面有个叫models.py
的文件,我现在就来编辑它。
1 |
bashvim ~/python_spider/web/models.py |
内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
python# -*- coding: utf-8 -*- from django.db import models # Create your models here. class Tag(models.Model): title = models.CharField(max_length=30) def __unicode__(self): return self.title class Question(models.Model): title = models.CharField(max_length=255) content = models.TextField() tags = models.ManyToManyField(Tag, related_name='questions') sf_id = models.CharField(max_length=16, default='0') # 加上这个可以记住问题在sf的位置,方便以后更新或者其他操作 update_date = models.DateTimeField(auto_now=True) def __unicode__(self): return self.title class Answer(models.Model): question = models.ForeignKey(Question, related_name='answers') content = models.TextField() def __unicode__(self): return 'To question %s' % self.question.title |
都很直白,关于各个field可以看看 Django 的文档。
然后,我需要告诉我的python_spider项目,在运行的时候加载web这个app(项目不会自动加载里面的app)。
1 |
bashvim ~/python_spider/python_spider/settings.py |
在INSTALLED_APPS里面加入web:
1 2 3 4 5 6 7 8 9 |
pythonINSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'web', ) |
下面,就可以用django自动生成数据库schema了
1 2 3 |
bashcd ~/python_spider python manage.py makemigrations python manage.py migrate |
现在,我~/python_spider
目录就产生了一个db.sqlite3
文件,这是我的数据库。
把玩一番我的模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
python>>> from web.models import Answer, Question, Tag >>> tag = Tag() >>> tag.title = u'测试标签' >>> tag.save() >>> tag >>> question = Question(title=u'测试提问', content=u'提问内容') >>> question.save() >>> question.tags.add(tag) >>> question.save() >>> answer = Answer(content=u'回答内容', question=question) >>> answer.save() >>> tag.questions.all() # 根据tag找question [] >>> question.tags.all() # 获取question的tags [] >>> question.answers.all() # 获取问题的答案 [] |
以上操作结果正常,说明定义的models是可用的。
3.2 入库
接下来,我需要把采集的信息入库,说白了,就是把我自己蜘蛛的信息利用django的ORM存到django连接的数据库里面,方便以后再用Django读取用于做站。
入库的方法太多了,这里随便写一种,就是在web app里面建立一个spider.py, 里面定义两个蜘蛛,继承之前自己写的蜘蛛,再添加入库方法。
1 |
bashvim ~/python_spider/web/spider.py |
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
python# -*- coding: utf-8 -*- from sfspider import spider from web.models import Answer, Question, Tag class ContentSpider(spider.SegmentfaultQuestionSpider): def save(self): # 添加save()方法 sf_id = self.url.split('/')[-1] # 1 tags = [Tag.objects.get_or_create(title=tag_title)[0] for tag_title in self.tags] # 2 question, created = Question.objects.get_or_create( sf_id=sf_id, defaults={'title':self.title, 'content':self.content} ) # 3 question.tags.add(*tags) # 4 question.save() for answer in self.answers: Answer.objects.get_or_create(content=answer, question=question) return question, created class TagSpider(spider.SegmentfaultTagSpider): def crawl(self): # 采集当前分页 sf_ids = [url.split('/')[-1] for url in self.questions] for sf_id in sf_ids: question, created = ContentSpider(sf_id).save() def crawl_all_pages(self): while True: print u'正在抓取TAG:%s, 分页:%s' % (self.tag_name, self.page) # 5 self.crawl() if not self.has_next_page: break else: self.next_page() |
- 这个地方写得很笨,之前该在SegmentfaultQuestionSpider加上这个属性。
- 创建或者获取该提问的tags
- 创建或者获取提问,采用sf_id来避免重复
- 把tags都添加到提问,这里用*是因为这个方法原本的参数是(tag1, tag2, tag3)。但是我们的tags是个列表
- 测试的时候方便看看进度
然后,测试下我们的入库脚本
1 |