上回,我已經大概把爬蟲寫出來了。
我寫了一個內容爬蟲,一個爬取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 |
bashpython manage.py shell |
1 2 3 4 5 6 7 8 9 10 11 12 |
python>>> from web.spider import TagSpider >>> t = TagSpider(u'微信') >>> t.crawl_all_pages() 正在抓取TAG:微信, 分頁:1 正在抓取TAG:微信, 分頁:2 正在抓取TAG:微信, 分頁:3 KeyboardInterrupt # 用control-c中斷執行,測試一下就行:) >>> from web.models import Tag, Question >>> Question.objects.all() [, , , , , , , , , , , , , , , , , , , , '...(remaining elements truncated)...'] >>> Question.objects.get(pk=5).tags.all() # 資料庫中id=5的question的tags [, , , ] |
3.3 設定django.contrib.admin來檢視和編輯內容
為了更直觀的觀察我採集的資料,我可以利用django自帶的admin
編輯檔案
1 |
bashvim ~/python_spider/web/admin.py |
1 2 3 4 5 6 |
pythonfrom django.contrib import admin from web.models import Tag, Question, Answer admin.site.register(Tag) admin.site.register(Question) admin.site.register(Answer) |
然後建立超級使用者
1 |
bashpython manage.py createsuperuser # 根據提示建立 |
啟動測試伺服器
1 |
bashpython manage.py runserver 0.0.0.0:80 # 我這是在runabove上,本地直接manage.py runserver |
然後,我訪問http://192.99.71.91/admin/登入剛剛建立的賬號,就能對內容進行檢視和編輯了
OK, 今天的內容到此。
下一篇,是編寫django的view,套用簡單的模板來建站。