说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/90720889
目录
一丶Django搭建搜索网站
1. es完成搜索建议
- 搜索建议接口文档:https://www.elastic.co/guide/en/elasticsearch/reference/5.1/search-suggesters-completion.html
- 在接口文档中已经说明要使用此接口,需要添加suggest字段的映射,如果将suggest的analyzer直接设置为"ik_analyzer"在进行初始化的时候会报错,解决这个bug,则需要定义一个类并继承elasticsearch_dsl.analysis模块下的CustomAnalyzer类,并重写父类的get_analysis_definition方法,该方法只需要返回一个空字典即可解决此bug
class CustomAnalyzer(_CustomAnalyzer):
def get_analysis_definition(self):
return {}
ik_analyzer = CustomAnalyzer(“ik_max_word”, filter=[“lowercase”])
class ArticleType(DocType):
suggest = Completion(analyzer=ik_analyzer)
- 在elasticsearch-head页面中删除之前创建的jobbole索引,重新运行es_type模块,查看新生成的jobbole索引信息中的suggest字段
2.搜索建议字段保存
- 在接口文档中详细说明了搜索建议查询匹配的预期文本,但没有告知我们要如何设置input的值
PUT music / song / 1?refresh
{
“suggest”:[
{
“input”:“Nevermind”,
“weight”:10
},
{
“input”:“Nirvana”,
“weight”:3
}
]
}
- 在上一篇博客在使用Kibana工具时,查看分析器解析的结果是对数据进行了分词操作,那么就可以利用这个接口进行数据分词
- 在pipelines文件中定义一个全局方法,在这个方法需要接收两个参数,index为索引名称info_tuple为元组类型接收多个字段参数与其的权重值,在方法中遍历获取字段内容与权重值,通过链接的ArticleType实例对象analyze方法获取解析结果,再从解析结果words中获取token分词数据
from elasticsearch_dsl.connections import connections
es = connections.create_connection(ArticleType._doc_type.using)
def gen_suggests(index, info_tuple):
#根据字符串生成搜索建议数组
used_words = set()
suggests = []
for text, weight in info_tuple:
if text:
#调用es的analyze接口分析字符串
words = es.indices.analyze(index=index, analyzer=“ik_max_word”, params={‘filter’:[“lowercase”]}, body=text)
anylyzed_words = set([r[“token”] for r in words[“tokens”] if len(r[“token”])>1])
new_words = anylyzed_words - used_words
else:
new_words = set()
if new_words:
suggests.append({"input":list(new_words), "weight":weight})
return suggests
- 在ElasticsearchPipeline管道类中调用save方法之前生成搜索建议词的保存,调用gen_suggests方法
article.suggest = gen_suggests(ArticleType._doc_type.index, ((article.title,10),(article.tags, 7)))
- Debug测试生成搜索建议分词
- 刷新elasticsearch-head可视化页面jobbole索引数据浏览
3.创建Django项目
- 安装项目虚拟环境
- 在Pycharm中创建一个新的Django项目
- 创建完成后,项目目录结构如下
- Debug测试运行项目成功
4.快速搭建搜索网站主页
- 在项目根目录下创建static目录,存放静态资源文件,并将模板文件拷贝到templates目录下
- 在项目根级urls中使用TemplateView类的as_view方法将index模板也就是主页面渲染显示
urlpatterns = [
url(r'admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name="index.html"), name='index'),
]
- 在settings文件中将static目录添加配置中
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
- 在index.html模板文件中动态获取静态资源路径
- 访问http://127.0.0.1:8000/地址,成功渲染出index页面
5.elasticsearch模糊查询来完成搜索关键字自动补全功能
- 这里需要使用fuzzy关键字也就是模糊查询来完成在搜索框输入不完整的关键字自动补全该关键字,如输入pyth则会提示补全后的python关键字,查看elasticsearch5.1.1版本提供的接口文档示例
- 在Kibana工具页面中使用如上接口测试自动补全
6. django实现elasticsearch的搜索建议
- 首先需要将es_types中python与elasticsearch_dsl交互的代码拷贝到django项目models中
from django.db import models
Create your models here.
from elasticsearch_dsl import DocType, Date, Nested, Boolean, analyzer,Completion, Keyword, Text, Integer
from elasticsearch_dsl.connections import connections
from elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzer
connections.create_connection(hosts=[“localhost”])
class CustomAnalyzer(_CustomAnalyzer):
def get_analysis_definition(self):
return {}
ik_analyzer = CustomAnalyzer(“ik_max_word”, filter=[“lowercase”])
class ArticleType(DocType):
suggest = Completion(analyzer=ik_analyzer)
title = Text(analyzer=“ik_max_word”)
create_date = Date()
url = Keyword()
url_object_id = Keyword()
cover_image_url = Keyword()
cover_image_path = Keyword()
praise_nums = Integer()
comment_nums = Integer()
fav_nums = Integer()
tags = Text(analyzer=“ik_max_word”)
content = Text(analyzer=“ik_max_word”)
class Meta:
index = "jobbole"
doc_type = "article"
if name == ‘main’:
ArticleType.init()
- 需要在当前虚拟环境中安装elasticsearch_dsl
- 在search应用views中定义类视图get方法,返回搜索建议title字段数据
class SearchSuggest(View):
def get(self, request):
key_words = request.GET.get('s', '')
re_datas = []
if key_words:
s = ArticleType.search()
s = s.suggest('song_suggest', key_words, completion={
"field": "suggest", "fuzzy": {
"fuzziness": 2
},
"size": 10
})
suggestions = s.execute_suggest()
for match in suggestions.song_suggest[0].options:
source = match._source
re_datas.append(source["title"])
return HttpResponse(json.dumps(re_datas), content_type="application/json")
- 在index模板文件中定义js代码,通过ajax异步get请求方式向接口发送请求
<script type="text/javascript"> var suggest_url = "{% url "suggest" %}" var search_url = '/search'
$('.searchList').on('click', '.searchItem', function(){ $('.searchList .searchItem').removeClass('current'); $(this).addClass('current'); }); function removeByValue(arr, val) { for(var i=0; i<arr.length; i++) { if(arr[i] == val) { arr.splice(i, 1); break; } } } // 搜索建议 $(function(){ $('.searchInput').bind(' input propertychange ',function(){ var searchText = $(this).val(); var tmpHtml = "" $.ajax({ cache: false, type: 'get', dataType:'json', url:suggest_url+"?s="+searchText+"&s_type="+$(".searchItem.current").attr('data-type'), async: true, success: function(data) { for (var i=0;i<data.length;i++){ tmpHtml += '<li><a href="'+search_url+'?q='+data[i]+'">'+data[i]+'</a></li>' } $(".dataList").html("") $(".dataList").append(tmpHtml); if (data.length == 0){ $('.dataList').hide() }else { $('.dataList').show() } } }); } ); }) hideElement($('.dataList'), $('.searchInput'));
</script>
- 为了方便测试搜索建议提示,博主运行AirticSpider项目疯狂爬取伯乐在线网站的文章数据并写入到elasticsearch jobbole索引文档数据中
- 在elasticsearch-head页面中数据概览中jobbole索引的docs数据量为2783
- 重启运行django项目,强制刷新index页面,输入搜索关键字,成功加载出搜索建议以及自动补全关键字
7. django实现elasticsearch的搜索功能
- 在页面输入搜索关键字后点击搜索按钮,即跳转到相关相关文章的列表页,在文章标题部分的关键字应该显示为高亮状态,即所以根据官网提供的接口文档,在Kibana工具页面中进行测试
- 在应用search/views中使用如下代码测试如上接口是否成功获取对匹配的字段内容进行高亮处理
client = Elasticsearch(hosts=["127.0.0.1"])
response = client.search(
index="jobbole",
body={
"query": {
"multi_match": {
"query": "python",
"fields": ["tags", "title", "content"]
}
},
"from": 0,
"size": 10,
"highlight": {
"pre_tags": ['<span class="keyWord">'],
"post_tags": ['</span>'],
"fields": {
"title": {},
"content": {},
}
}
}
)
total_nums = response["hits"]["total"]
- Debug断点测试如上代码,成功获取到Kibana工具中接口测试获取到python关键字的_shards和hits数据
- 通过上面的代码可以获取到匹配关键字的数据,现在就将这些数据保存到一个数组中,再传递到result.html模板中进行显示,首先需要获取用户输入的搜索关键字到elasticsearch索引jobbole中匹配所有的相关的文章标签标题以及内容,并对相关文章的标题和内容匹配的搜索内容进行高亮系显示,最后是获取hits字典中的数据数据并保存到hit_list字典中传递到模板result中
class SearchView(View): """搜索功能""" def get(self, request): key_words = request.GET.get("q", "") response = client.search( index="jobbole", body={ "query": { "multi_match": { "query": key_words, "fields": ["tags", "title", "content"] } }, "from": 0, "size": 10, "highlight": { "pre_tags": ['<span class="keyWord">'], "post_tags": ['</span>'], "fields": { "title": {}, "content": {}, } } } ) total_nums = response["hits"]["total"] hit_list = [] # 获取响应中国的hits字段数据,并保存到hit_dict字典中 for hit in response["hits"]["hits"]: hit_dict = {} if "title" in hit["highlight"]: hit_dict["title"] = "".join(hit["highlight"]["title"]) else: hit_dict["title"] = hit["_source"]["title"] if "content" in hit["highlight"]: hit_dict["content"] = "".join(hit["highlight"]["content"])[:500] else: hit_dict["content"] = hit["_source"]["content"][:500]
hit_dict["create_date"] = hit["_source"]["create_date"] hit_dict["url"] = hit["_source"]["url"] hit_dict["score"] = hit["_score"] hit_list.append(hit_dict) return render(request, "result.html", {"all_hits":hit_list, "key_words": key_words})
- 在result模板中对后端传递的数据进行打印显示
<div class="resultList">
{% for hit in all_hits %}
<div class="resultItem">
<div class="itemHead">
<a href="{{ hit.url }}" target="_blank" class="title">{% autoescape off %}{{ hit.title }}{% endautoescape %}</a>
<span class="divsion">-</span>
<span class="fileType">
<span class="label">来源:</span>
<span class="value">伯乐在线</span>
</span>
<span class="dependValue">
<span class="label">得分:</span>
<span class="value">{{ hit.score }}</span>
</span>
</div>
<div class="itemBody">
{% autoescape off %}{{ hit.content }}{% endautoescape %}
</div>
<div class="itemFoot">
<span class="info">
<label>网站:</label>
<span class="value">伯乐在线</span>
</span>
<span class="info">
<label>发布时间:</label>
<span class="value">2017-04-23</span>
</span>
</div>
</div>
{% endfor %}
</div>
- 在根级urls中配置路由
url(r'^search/$',SearchView.as_view(), name='search')
- 还需要在主页模板index中定义search_url的链接地址使用反向解析进行定义,然后就是定义搜索方法完成页面的跳转
var search_url = "{% url 'search' %}" <script> var searchArr; //定义一个search的,判断浏览器有无数据存储(搜索历史) if(localStorage.search){ //如果有,转换成 数组的形式存放到searchArr的数组里(localStorage以字符串的形式存储,所以要把它转换成数组的形式) searchArr= localStorage.search.split(",") }else{ //如果没有,则定义searchArr为一个空的数组 searchArr = []; } //把存储的数据显示出来作为搜索历史 MapSearchArr();
function add_search(){ var val = $(".searchInput").val(); if (val.length>=2){ //点击搜索按钮时,去重 KillRepeat(val); //去重后把数组存储到浏览器localStorage localStorage.search = searchArr; //然后再把搜索内容显示出来 MapSearchArr(); } window.location.href=search_url+'?q='+val+"&s_type="+$(".searchItem.current").attr('data-type') } function MapSearchArr(){ var tmpHtml = ""; var arrLen = 0 if (searchArr.length >= 5){ arrLen = 5 }else { arrLen = searchArr.length } for (var i=0;i<arrLen;i++){ tmpHtml += '<a href="'+search_url+'?q='+searchArr[i]+'">'+searchArr[i]+'</a>' } $(".mysearch .all-search").html(tmpHtml); } //去重 function KillRepeat(val){ var kill = 0; for (var i=0;i<searchArr.length;i++){ if(val===searchArr[i]){ kill ++; } } if(kill<1){ searchArr.unshift(val); }else { removeByValue(searchArr, val) searchArr.unshift(val) } }
</script>
- 重新启动项目,在主页进行搜索功能测试,点击输入python时的自动补全提示跳转到搜索结果列表页面
- 直接在搜索框输入python点击搜索按钮,跳转到搜索结果列表页,并在主页我的搜索项中显示用户搜索历史
- 在搜索结果页面中也就是result页面,同样有搜索框,该搜索框除了会将主页搜索的关键字设置结果页面input value中外,还应该向首页搜索框一样具备搜索功能,这里需要重点说明一点,当在搜索结果页对搜索与主页一样的内容时,点击搜索功能按钮则不会触发页面搜索;在结构页面的搜索功能与主页搜索功能一样,即在result模板中定义js函数,当用户点击搜索时激活此input的onclick属性调用add_search函数,向后端接口SearchView发送请求数据,完成搜索功能
<script> var search_url = "{% url 'search' %}"; var searchArr; //定义一个search的,判断浏览器有无数据存储(搜索历史) if(localStorage.search){ //如果有,转换成 数组的形式存放到searchArr的数组里(localStorage以字符串的形式存储,所以要把它转换成数组的形式) searchArr= localStorage.search.split(",") }else{ //如果没有,则定义searchArr为一个空的数组 searchArr = []; } //把存储的数据显示出来作为搜索历史 MapSearchArr();
function add_search(){ {#alert(search_url);#} var val = $(".searchInput").val(); {#alert(val);#} if (val.length>=2){ //点击搜索按钮时,去重 KillRepeat(val); //去重后把数组存储到浏览器localStorage localStorage.search = searchArr; //然后再把搜索内容显示出来 MapSearchArr(); } {#alert(111);#} {#window.location.href=search_url+'?q='+val+"&s_type="+$(".searchItem.current").attr('data-type');#} setTimeout(function () { window.location.href=search_url+'?q='+val+"&s_type="+$(".searchItem.current").attr('data-type'); },100) } function MapSearchArr(){ var tmpHtml = ""; var arrLen = 0 if (searchArr.length >= 5){ arrLen = 5 }else { arrLen = searchArr.length } for (var i=0;i<arrLen;i++){ tmpHtml += '<a href="'+search_url+'?q='+searchArr[i]+'">'+searchArr[i]+'</a>' } $(".mysearch .all-search").html(tmpHtml); } //去重 function KillRepeat(val){ var kill = 0; for (var i=0;i<searchArr.length;i++){ if(val===searchArr[i]){ kill ++; } } if(kill<1){ searchArr.unshift(val); }else { removeByValue(searchArr, val) searchArr.unshift(val) } }
</script>
- 在result模板中根据后端接口返回的数据,进行页面字段数据的打印
<div class="resultList">
{% for hit in all_hits %}
<div class="resultItem">
<div class="itemHead">
<a href="{{ hit.url }}" target="_blank" class="title">{% autoescape off %}{{ hit.title }}{% endautoescape %}</a>
<span class="divsion">-</span>
<span class="fileType">
<span class="label">来源:</span>
<span class="value">伯乐在线</span>
</span>
<span class="dependValue">
<span class="label">得分:</span>
<span class="value">{{ hit.score }}</span>
</span>
</div>
<div class="itemBody">
{% autoescape off %}{{ hit.content }}{% endautoescape %}
</div>
<div class="itemFoot">
<span class="info">
<label>网站:</label>
<span class="value">伯乐在线</span>
</span>
<span class="info">
<label>发布时间:</label>
<span class="value">{{ hit.create_date }}</span>
</span>
</div>
</div>
{% endfor %}
</div>
- 测试在搜索结构页面进行字段搜索
8.django实现搜索结果分页
- 使用js完成数据的分页显示,首先在result模板中定义分页js代码函数,来完成页面标签div类选择器pagination的分页数据填充
var key_words = "{{ key_words }}"
//分页
$(".pagination").pagination({{ total_nums|add:'-1' }}, {
current_page :{{ page|add:'-1' }}, //当前页码
items_per_page :10,
display_msg :true,
callback :pageselectCallback
});
function pageselectCallback(page_id, jq) {
var pageid = page_id +Number(1);
{#alert(pageid)#}
window.location.href=search_url+'?q='+key_words+'&p='+pageid
}
- 在上面定义的js代码中需要在后端接口中获取total_nums总页数以及page当前页的值并传递给result模板中
page = request.GET.get("p", "1")
total_nums = response["hits"]["total"]
if(page%10) >0:
page_nums = int(total_nums/10)+1
else:
page_nums = int(total_nums/10)
- 测试搜索结果页result.html分页功能
- 在搜索结果页面搜索框下会显示对搜索字段数据的数据量页码数以及搜索用时时间,总页面数page_nums以及数据量total_nums在进行分页数据显示时已经在视图中进行获取并传递给模板了,现在只需要在视图中通过执行代码段时记录当前时间,执行搜索代码后再获取结束搜索的时间,进行减法操作即可获取搜索时间
start_time = datetime.now()
response = client.search(
index="jobbole",
body={
"query": {
"multi_match": {
"query": key_words,
"fields": ["tags", "title", "content"]
}
},
"from": (page-1)*10,
"size": 10,
"highlight": {
"pre_tags": ['<span class="keyWord">'],
"post_tags": ['</span>'],
"fields": {
"title": {},
"content": {},
}
}
}
)
end_time = datetime.now()
last_seconds = (end_time-start_time).total_seconds()
- 在模板中进行数据填坑
<span class="info">找到约 <span class="totalResult">{{ total_nums }}</span> 条结果(用时<span class="time">{{ last_seconds }}</span>秒),共约<span class="totalPage">{{ page_nums }}</span>页</span>
- 测试搜索华为,则成功显示搜索信息
9.搜索记录、热门搜索功能实现
- 在搜索结果页面左侧显示伯乐在线网站条目数据,该数据是通过scrapy爬取并写入到jobbole索引doc库中获取的数据,因此数据是随时变化的,所以需要将该数据保存到redis数据,这样读写效率就比较高了
- 首先需要在ArticleSpider伯乐在线爬虫项目环境中安装redis
- 在ArticleSpider项目pipelines/ElasticsearchPipeline管道类中使用redis incr方法往本地redis数据库0中保存名为jobbole的key并加1操作,当向es中保存一条数据时,则在redis数据库0中使jobbole_count的值+1,这样就可以统计伯乐在线网站文章数目
- 为了测试是否向我们预期那样每当执行redis_cli.incr("jobbole_count")代码时jobbole_count的值进行+1操作,在项目目录下新建一个test.py文件,测试代码如下
# -*- coding: utf-8 -*-
__author__ = 'cdtaogang'
__date__ = '2019/6/5 12:48'
import redis
redis_cli = redis.StrictRedis()
redis_cli.incr(“jobbole_count”)
- 通过run运行test.py成功后,查看redis 0数据库的数据,测试成功
- 回到LcvSearch django项目中在views视图中,获取redis数据库中的jobbole_count的值然后传递到模板中,在LcvSearch 环境中同样也需要安装redis,这个就不在演示了
jobbole_count = redis_cli.get("jobbole_count")
- 在模板中找到对应的标签字段打印jobbole_count的值即可
<li>
<span class="name">伯乐在线</span>
<span class="unit">({{ jobbole_count }})</span>
</li>
- 刷新页面,则成功显示出保存到redis数据的jobbole的值,需要说明的是,因为没有运行ArticleSpider爬虫项目即当然不会执行ElasticsearchPipeline管道类中的代码,所以页面上显示的伯乐在线网站的数目为1
- 为了好看博主打算花一段时间重新爬取伯乐在线网站的文章数据
- 爬取一定时间后,不断刷新页面,伯乐在线网站的数据条目在不断的增加,因为爬虫项目同时在不停的爬取并写入的es中
- 在主页和搜索结果页面都会有我的搜索记录以及热门搜索排行显示,我的搜索实现过程就是当点击搜索按钮时会调用js中的add_search函数,在函数中获取input输入框中的关键字然后在函数中调用KillRepeat函数并将获取的关键字传递到该函数中,在KillRepeat函数中如果出现该关键字出现在我的搜索列表中,则会去删除列表中的该关键字也就是去重操作,然后将搜索的关键字保存到浏览器的localStorage缓存中,最后再调用MapSearchArr函数将搜索内容显示出来,之前在主页面已经通过js代码实现了我的搜索功能数据显示,所以现在重点是做热门搜索功能,在search模板中定义与index模板中相同的js代码即可,这个就不细说了
- 热门搜索功能数据显示,实现逻辑需要将热门搜索的关键字通过redis的zincrby命令将关键字keyword保存到redis数据库search_keywords_set键中并设定其increment增量值为1,再通过redis的zrangebyscore命令获取
min
和max
可以是-inf
和+inf区间分值的数据,具体的命令文档可以访问
http://redisdoc.com/redis官方文档进行查阅
- 在views视图中编写以下代码即可,上面已经说明代码的作用
redis_cli.zincrby("search_keywords_set", 1, key_words)
hot_search = redis_cli.zrangebyscore("search_keywords_set", "-inf", "+inf", start=0, num=5)
- 在result模板中遍历打印显示出热门搜索关键字
<div class="hotSearch">
<h6>热门搜索</h6>
<ul class="historyList">
{% for search_word in hot_search %}
<li><a href="/search?q={{ search_word }}">{{ search_word }}</a></li>
{% endfor %}
</ul>
</div>
- 强制刷新搜索结果页面,成功显示出热门搜索关键词
- 在主页面,搜索框下的热门搜索也需要进行数据设置获取,之前显示主页面使用django提供的view,这里因为要向首页模板中传递redis数据库中的search_keywords_set键的数据,所以需要定义主页类视图IndexView get方法来渲染模板以及向模板传递数据
class IndexView(View):
"""主页"""
def get(self, request):
hot_search = redis_cli.zrangebyscore("search_keywords_set", "-inf", "+inf", start=0, num=5)
return render(request, "index.html", {"hot_search":hot_search})
- 然后在index模板中进行打印热门数据
<p class="history">
<label>热门搜索:</label>
{% for search_words in hot_search %}
<a href="/search?q={{ search_words }}">{{ search_words }}</a>
{% endfor %}
</p>
- 强制刷新主页,成功显示热门搜索关键词
二丶通过scrapyd部署scrapy爬虫
1.在ArticleSpider项目的虚拟环境中安装scrapyd
- scrapyd的参考文档:https://scrapyd.readthedocs.io/en/stable/
- 在scrapy_py3虚拟环境中安装scrapyd
- 安装scrapyd后,启动运行scrapyd命令成功,当访问http://127.0.0.1:6800/后点击进入jobs后,则出现如下错误
- 回到控制台查看运行报错日志,发现是全是指向twisted包的错误,博主猜想是twisted版本与scrapyd版本不兼容问题,于是回退安装twisted==18.9.0版本
- 安装twisted==18.9.0版本
- 重新刷新页面则不再报错,问题解决
- 启动scrapyd命令说白了可就是运行其服务器,运行成功后会在其目录下创建dbs目录,因为博主是在scrapy_p3虚拟环境中使用pip安装的scrapyd包,所以需要在d盘也就是博主的项目盘下创建test目录在test目录下创建scrapyd目录,然后在Terminal命令终端中进入创建好的scrapyd目录,执行scrapyd命令后,成功生成了dbs目录
2.安装及配置scrapyd客户端
- 安装scrapy-client包
- 在ArticleSpider爬虫项目下的scrapy.cfg配置文件中打开注释掉的url,并对deploy定义一个任意名称
[settings]
default = ArticleSpider.settings
[deploy:cdtaogang]
url = http://localhost:6800/
project = ArticleSpider
- 在虚拟环境scrapy_py3/Scripts目录下可以看到安装scrapyd-client包后生成的scrapyd-deploy文件,这个文件在linux系统中可以直接执行scrapyd-deploy命令,但是在windows中该文件并没有后缀名,所以无法执行scrapyd-deploy命令,这是一个巨坑;要想在windows中执行scrapyd-deploy命令,则需要在scrapy_py3/Scripts目录下新建一个scrapyd-deploy.bat批处理文件,并编写该文件如下内容;第一个路径为虚拟环境中使用的python解释器路径,第二个为scrapyd-deploy路径
@echo off
“D:\scrapy_py3\Scripts\python.exe” “D:\scrapy_py3\Scripts\scrapyd-deploy” %1 %2 %3 %4 %5 %6 %7 %8 %9
- 测试运行scrapyd-deploy -l命令打印出ArticleSpider项目scrapy.cfg配置数据,即配置scrapyd-client成功
- 在正式部署项目之前,需要执行scrapy list命令,确保能够打印出scrapy项目的name名称
3.项目部署
- 在ArticleSpider项目settings配置文件中还需要将ArticleSpider项目目录添加进来
import sys
BASE_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'ArticleSpider'))
- 在Terminal终端中执行scrapyd-deploy cdtaogang -p ArticleSpider命令,参数就是之前的配置信息这个不多说,这个命令就相当于打包文件的意思
- 然后在test/scrapyd目录中生成了eggs/ArticleSpider目录下的1559740467.egg文件
- 使用scrapyd-deploy cdtaogang -p ArticleSpider命令将项目打包上传到服务器后,但是并没有运行,需要根据文档API说明执行文档中的curl命令
- curl命令windows本身是没有的,但博主以前写项目的时候,安装过windows版本的curl命令程序,安装过Anaconda时也会默认安装curl命令,还有一种方法就是在windows中安装cmder程序,启动该程序可以执行curl命令
- 执行curl http://localhost:6800/daemonstatus.json命令可以查看scrapyd的状态
- 根据scrapyd文档上执行curl http://localhost:6800/schedule.json -d project=myproject -d spider=somespider命令来启动scrapy项目
- 启动ArticleSpider项目下的jobbole爬虫应用成功后,回到scrapyd服务器页面http://127.0.0.1:6800/jobs进行强制刷新后,则运行成功,因为页面不是自动刷新的,从下图可以看见运行时间,随时刷新页面这个时间都是在变化的,客户端运行结束后,就会显示finish的时间
- 演示以上博主所说的爬虫启动一直运行,而页面是需要手动刷新的