目的解析
在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 lang="en">
<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框架,搜索结果如下所示