目的解析
在Django網站架構下,建立Scrapy爬蟲架構,擷取豆瓣電影Top250的資料,将資料儲存到mysql資料庫中,最後連結ElasticSearch搜尋,将資訊導入到其中,實作可以在前端頁面搜尋資料。
建立Django網站
本文在pycharm中直接建立(我的項目名為Top250)
建立完項目,建立app,打開terminal 輸入指令
python manage.py startapp 子產品的名字(我的是douban_test)
我這邊Django的版本是3.2.13,運作的時候報錯os,隻需要在setting中import os 即可
建立app之後,在setting的installled_apps中加入新建立的app名字
啟動Django,點選右上角的運作按鈕即可
在浏覽器輸入127.0.0.1:8000,顯示如下,即運作成功
Django的運作順序是從項目的urls.py轉到app的urls.py再到views.py,然後到顯示html
我們開始設定在douban_test的目錄中建立檔案urls.py
from douban_test import views
from django.urls import path
app_name = 'douban_test' #此處改成自己的app名字
urlpatterns = [
path('', views.IndexView.as_view()),
]
将項目的urls.py與app(即douban_test)的urls.py連接配接起來,在項目的urls.py中設定
path('', include('douban_test.urls')),
path('search/', include('haystack.urls')),
接着進入douban_te的views.py中
from django.shortcuts import render
# Create your views here.
from django.views import View
class IndexView(View): #注意此時的類名,應與urls.py中path('', views.IndexView.as_view()),的IndexView一緻,并且繼 承于View
def get(self,request):
return render(request, 'index.html')
接着在項目的根目錄下建立templates
在templates中建立新的html檔案,html檔案的命名方式與views.py中的index.html一緻
在html裡,我們寫個簡單的搜尋框
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form role="search" method="get" id="searchform" action="{% url 'haystack_search' %}"> # 此處的haystack_search下面會用到,為的是連結ElasticSearch
<input type="search" name="q" placeholder="搜尋" required>
<button type="submit">送出<span class="ion-ios-search-strong"></span></button>
</form>
</body>
</html>
此時,Django的基礎基礎設定結束,還有資料庫表,
在Django的setting中連接配接mysql
#資料庫配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'novel_test',
'USER':'root',
'PASSWORD':'123456',
'HOST':'localhost',
'PORT':3306
}
}
我們分析豆瓣 電影 top250資料中的 ‘名字’ ,‘評分’ , ‘簡介 ’, ‘主演’。我們編寫models.py
from django.db import models
# Create your models here.
class Top(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
grade = models.CharField(max_length=100)
introduction = models.CharField(max_length=1000)
role = models.CharField(max_length=1000)
def __str__(self):
return self.name
接着進行資料庫表的遷移
python manage.py makemigrations
python manage.py migrate
設定Scrapy
在 項目根目錄下的terminal中輸入
pip install scrapy
安裝完成後,還是在根目錄下的terminal
scrapy startproject Top250_spider
cd Top250_spider
scrapy genspider douban_spider movie.douban.com #scrapy genspider 爬蟲項目名 爬蟲網址(後面能改)
結構如下
接下來對Scrapy中的setting設定,連接配接到django中,setting中加入以下代碼
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath('.')))
os.environ['DJANGO_SETTINGS_MODULE'] = 'django_scrapy_test.settings' # 項目名.settings
import django
django.setup()
将setting中的機器人協定
改為False
接着,我們在douban_spider.py中開始對豆瓣top250電影代碼進行編寫
import scrapy
from douban_test.models import Top
class DoubanSpiderSpider(scrapy.Spider):
name = 'douban_spider'
allowed_domains = ['movie.douban.com']
start_urls = ['http://movie.douban.com/top250']
def parse(self, response):
nodelist = response.xpath('//div[@class="info"]')
for node in nodelist:
list = {}
list['name'] = node.xpath("./div[1]/a/span[1]/text()")[0].extract()
list['grade'] = node.xpath("./div[2]/div[1]/span[2]/text()")[0].extract()
list['introduction'] = ''.join(node.xpath("./div[2]/p[2]/span/text()").extract())
list['role'] = node.xpath("./div[2]/p[1]/text()")[0].extract().strip()
Top.objects.create(name=list['name'],grade=list['grade'],introduction=list['introduction'],role=list['role'])
yield list
nextpage = response.xpath('//span[@class="next"]/a/@href').extract()
# print(new_url)
if nextpage:
new_url = 'http://movie.douban.com/top250' + nextpage[0]
yield scrapy.Request(url=new_url,callback=self.parse)
在top250_spider 裡的items.py
from scrapy_djangoitem import DjangoItem
import douban_test as t
class Top250SpiderItem(DjangoItem):
django_model = t.Top
在pipelines.py
from .models.es_types import ArticleIndex
class Top250SpiderPipeline:
def process_item(self, item, spider):
item.save(0
在這裡可以先運作爬蟲,看看資料是否已經儲存到MySQL中
scrapy crawl douban_spider (爬蟲名)
我們可以看到已經成功爬到資料庫中
設定ElasticSearch
接着需要在電腦上安裝ElasticSearch,建議自行搜尋,然後我們在項目裡安裝elasticsearch_dsl
pip in stall elasticsearch_dsl
需要注意安裝的ElasticSearch與這個插件elasticsearch_dsl版本需要一緻,比如
# Elasticsearch 7.x
elasticsearch-dsl>=7.0.0,<8.0.0
# Elasticsearch 6.x
elasticsearch-dsl>=6.0.0,<7.0.0
# Elasticsearch 5.x
elasticsearch-dsl>=5.0.0,<6.0.0
# Elasticsearch 2.x
elasticsearch-dsl>=2.0.0,<3.0.0
在項目models下建立es_types.py檔案,在檔案中建立索引mapping
# -*- coding: utf-8 -*-
from elasticsearch_dsl import Document, Keyword, Text, Integer
from elasticsearch_dsl.connections import connections
connections.create_connection(hosts=["localhost"])
class ArticleIndex(Document):
id = Integer()
name = Keyword()
grade = Integer()
introduction = Text(analyzer="ik_max_word")
role = Text(analyzer="ik_max_word")
class Index:
name = "boge1"
doc_type = "article"
運作es_types.py檔案,需要先開啟elasticsearch服務
回到elasticsearch-head可視化頁面,可以看到成功生成索引
在pipelines檔案中定義管道類ElasticsearchPipeline将資料寫入到es中
from .models.es_types import ArticleIndex
class Top250SpiderPipeline:
def process_item(self, item, spider):
article = ArticleIndex()
article.id = item['id']
article.name = item['name']
article.grade = item['grade']
article.introduction = item['introduction']
article.role = item['role']
article.save()
return item
接着,使用安裝djangohaystack來搭建搜尋系統,連結到django中
# 安裝djangohaystack
pip install django-haystack
接着在django的setting裡加入應用
在配置檔案中配置Haystack為搜尋引擎後端
# 在配置檔案中配置Haystack為搜尋引擎後端
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine', #前面的Elasticsearch7SearchEngine裡的 7 對應着你的elasticsearch的版本
'URL': 'http://127.0.0.1:9200/', # Elasticsearch伺服器ip位址,端口号固定為9200
'INDEX_NAME': 'boge', # Elasticsearch建立的索引庫的名稱
},
}
# 當添加、修改、删除資料時,自動生成索引,保證了在Django運作起來後,
# 有新的資料産生時,Haystack仍然可以讓Elasticsearch實時生成新資料的索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# haystack分頁
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 6
在Django app的檔案裡建立search_indexes.py檔案
from haystack import indexes
from .models import Top
class NewsIndex(indexes.SearchIndex, indexes.Indexable):# 這裡的類名也是固定的,索引的模型名+Index,繼承也是固定的
"""
這個模型的作用類似于django的模型,它告訴haystack哪些資料會被
放進查詢傳回的模型對象中,以及通過哪些字段進行索引和查詢
"""
# 這字段必須這麼寫,用來告訴haystack和搜尋引擎要索引哪些字段
text = indexes.CharField(document=True, use_template=True)
# 模型字段,打包資料
id = indexes.CharField(model_attr='id')
name = indexes.CharField(model_attr='name')
grade = indexes.CharField(model_attr='grade')
introduction = indexes.CharField(model_attr='introduction')
role = indexes.CharField(model_attr='role')
def get_model(self):
"""
傳回建立索引的模型
:return:
"""
return Top
def index_queryset(self, using=None):
"""
傳回要建立索引的資料查詢集
:param using:
:return:
"""
# 這種寫法遵從官方文檔的指引
return self.get_model().objects.filter()
根據上面建立的模型中的第一個text字段中的use_template=True參數,還需要建立一個索引資料模闆,用來告訴搜尋引擎需要索引哪些字段。
在templates中建立檔案search/indexes//_text.txt,
~$ python manage.py rebuild_index # 看到如下類似資訊,說明運作成功
WARNING: This will irreparably remove EVERYTHING from your search index in connection 'default'.
Your choices after this are to restore from backups or rebuild via the `rebuild_index` command.
Are you sure you wish to continue? [y/N] y
Removing all documents from your index because you said so.
All documents removed.
Indexing 889 新聞文章
GET /tzpython/_mapping [status:404 request:0.005s]
接着運作Django架構,搜尋結果如下所示