天降攻城狮

天降攻城狮 查看完整档案

杭州编辑  |  填写毕业院校  |  填写所在公司/组织 www.lqkweb.com 编辑
编辑

百度云搜索http://www.lqkweb.com
搜网盘:http://www.swpan.cn

个人动态

天降攻城狮 发布了文章 · 2020-12-12

3、Flask构建弹幕微电影网站-安装mysql数据库及配置

百度云搜索,搜各种资料:http://www.lqkweb.com

搜网盘,搜各种资料:http://www.swpan.cn

Flask 构建微电影视频网站

已上线演示地址: http://movie.tbquan.cn

安装数据库连接依赖包

安装包flask-sqlalchemy

pip install flask-sqlalchemy

pip list
Package          Version
---------------- -------
Click            7.0
Flask            1.0.2
Flask-SQLAlchemy 2.3.2
itsdangerous     0.24
Jinja2           2.10
MarkupSafe       1.0
pip              18.1
setuptools       40.4.3
SQLAlchemy       1.2.12
Werkzeug         0.14.1
wheel            0.32.1

中文文档

http://www.pythondoc.com/flas...

查看配置键: http://www.pythondoc.com/flas...

BLOG_20181028_122213_58

连接格式

MySQL: mysql://username:password@localhost/mydatabase

创建mysql数据库

下载mysql

https://dev.mysql.com/downloa...

这儿直接用的最新版8.0

MySQL Community Server

学习使用下载社区版就可以

安装mysql

BLOG_20181028_122220_14

BLOG_20181028_122240_15

BLOG_20181028_122247_66

打开开始菜单的MySQL 8.0 Command Line Client验证是否正常安装

Enter password: root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.12 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> \s
--------------
C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe  Ver 8.0.12 for Win64 on x86_64 (MySQL Community Server - GPL)

Connection id:          11
Current database:
Current user:           root@localhost
SSL:                    Cipher in use is DHE-RSA-AES128-GCM-SHA256
Using delimiter:        ;
Server version:         8.0.12 MySQL Community Server - GPL
Protocol version:       10
Connection:             localhost via TCP/IP
Server characterset:    utf8mb4
Db     characterset:    utf8mb4
Client characterset:    gbk
Conn.  characterset:    gbk
TCP port:               3306
Uptime:                 2 min 20 sec

Threads: 2  Questions: 23  Slow queries: 0  Opens: 147  Flush tables: 2  Open tables: 123  Queries per second avg: 0.164
--------------

如果cmd中mysql命令不管用,需要添加环境变量,在Path中添加C:\Program Files\MySQL\MySQL Server 8.0\bin\,也就是mysql的安装目录

然后就通过以下命令可以登录了

mysql -uroot -p
Enter password: root
查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-12-12

2、Flask构建弹幕微电影网站-使用蓝图构建项目目录

百度云搜索,搜各种资料:http://ww.lqkweb.com
盘搜网,搜各种资料:http://www.panso.org

Flask 构建微电影视频网站

蓝图构建项目目录

什么是蓝图

一个应用中或者跨应用制作应用组件和支持通用的模式

蓝图的作用

  • 将不同的功能模块化
  • 构建大型应用
  • 优化项目结构
  • 增强可读性、易于维护

构建方法·定义注册调用

定义蓝图(app/admin/__init__.py)

from flask import Blueprint
admin = Blueprint("admin", __name__)
import views

注册蓝图(app/__init__.py)

from admin import admin as admin_blueprint
app.register_blueprint(admin_blueprint, url_prefix="/admin")

调用蓝图(app/admin/views.py)

from . import admin
@admin.route("/")

开始创建项目

定义蓝图

app/home/__init__.py

from flask import Blueprint

home = Blueprint('home', __name__)

import app.home.views

app/admin/__init__.py

from flask import Blueprint

admin = Blueprint('admin', __name__)

import app.admin.views

调用蓝图

定义视图

app/home/views.py

from . import home

@home.route("/")
def index():
    return "<h1 style='color:blue'>前台</h1>"

app/admin/views.py

from . import admin

@admin.route("/")
def index():
    return "<h1 style='color:red'>后台</h1>"

注册蓝图

app/__init__.py

from flask import Flask

app = Flask(__name__)  # 实例化flask
app.debug = True  # 开启调试模式

from app.home import home as home_blueprint  # 导入
from app.admin import admin as admin_blueprint

app.register_blueprint(home_blueprint)
app.register_blueprint(admin_blueprint, url_prefix="/admin")

运行服务

编写入口脚本,使整个项目启动起来

manage.py

from app import app

if __name__ == '__main__':
    app.run()

然后运行run manage.py启动服务

访问 http://127.0.0.1:5000/ 即可看到前台的蓝色

访问 http://127.0.0.1:5000/admin/ 即可看到后台的红色

现在访问后台就是以 /admin为前缀,拼接后台视图里面的url,来构成整个链接。

查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-12-07

1、Flask构建弹幕微电影网站-环境搭建项目目录分析

百度云搜索:http://www.lqkweb.com

Flask 构建微电影视频网站

演示地址: http://movie.tbquan.cn

环境搭建

pip3 install virtualenvwrapper-win
mkvirtualenv FlaskMovie
(FlaskMovie) C:\Users\xxx>pip list
Package    Version
---------- -------
pip        18.1
setuptools 40.4.3
wheel      0.32.1

(FlaskMovie) C:\Users\xxx>pip install flask
(FlaskMovie) C:\Users\xxx>pip list
Package      Version
------------ -------
Click        7.0
Flask        1.0.2
itsdangerous 0.24
Jinja2       2.10
MarkupSafe   1.0
pip          18.1
setuptools   40.4.3
Werkzeug     0.14.1
wheel        0.32.1

使用PyCharm创建Flask项目

BLOG_20181017_215128_90

BLOG_20181017_215133_39

直接运行app.py,然后通过浏览器访问 http://127.0.0.1:5000/ 即可看到结果

  • 扩展丰富
  • 冗余度小
  • 自由选择组合各种插件
  • 性能优越
  • 轻量级
  • 小型项目快速开发
  • 大型项目毫无压力

Flask框架知识

  1. 学会使用整型、浮点型、路径型、字符串型正则表达式路由转换器
  2. 学会使用psot与get请求,上传文件,cookie获取与响应,404处理
  3. 模板自动转移,定义过滤器,定义全局上下文处理器,Jinja2语法、包含、继承、定义宏
  4. 学会flask-wtf定义表单模型、字段类型、字段验证、视图处理表单、模板使用表单
  5. 学会flask-sqlachemy定义数据库模型,添加、修改、查询、删除数据,数据库事件、数据迁移
  6. 使用蓝图优化项目结构,实现微电影网站前台与后台业务逻辑
  7. flask部署方法,安装nginx、python3、mysql服务以及通过nginx反向代理对视频流媒体限制下载速率,限制单个IP能发起的播放连接数
  8. 微内核+扩展插件(werkzug工具箱、pymysql数据库驱动、sqlalchermy数据库orm、wtforms表单验证工具、jinjia2模板引擎、flask-script命令行脚本、functools定义高阶函数)

视频技术

  1. jwplayer播放器插件
  2. 视频限速限制ip访问
  3. flv、mp4视频格式支持
  4. nginx点播实现

项目目录分析

前台模块(home)

  • 数据模型:models.py
  • 表单处理:home/forms.py
  • 模板目录:templates/home
  • 静态目录:static

后台模块(admin)

  • 数据模型:models.py
  • 表单处理:home/forms.py
  • 模板目录:templates/home
  • 静态目录:static

后台与前台不同的是表单和模板独立

前后台项目目录分析

BLOG_20181017_215143_15

manage.py  # ueke启动脚本
app        # 项目app
    __init__.py        # 初始化文件
    models.py            # 数据模型文件
    static                # 静态目录
    home
        __init__.py        # 初始化脚本
        views.py            # 视图处理文件
        forms.py            # 表单处理文件
    admin
        __init__.py        # 初始化脚本
        views.py            # 视图处理文件
        forms.py            # 表单处理文件
    templates
        home            # 前台模板
        admin            # 后台模板
查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-11-30

51、scrapyd部署scrapy项目

百度云搜索,搜各种资料:http://www.lqkweb.com
搜网盘,搜各种资料:http://www.swpan.cn

scrapyd模块是专门用于部署scrapy项目的,可以部署和管理scrapy项目**

下载地址:https://github.com/scrapy/scr...

建议安装

pip3 install scrapyd

首先安装scrapyd模块,安装后在Python的安装目录下的Scripts文件夹里会生成scrapyd.exe启动文件,如果这个文件存在说明安装成功,我们就可以执行命令了**

启动scrapyd服务

在命令输入:scrapyd

image

如图说明启动成功,关闭或者退出命令窗口,因为我们正真的使用是在指定的启动目录下启动服务的

指定启动*服务目录启动服务*

重新打开命令,cd进入要指定服务的目录后,执行命令scrapyd启动服务

image

此时可以看到启动目录里生成了dbs目录

image

dbs目录里是空的什么都没有

此时我们需要安装scrapyd-client模块

scrapyd-client模块是专门打包scrapy爬虫项目到scrapyd服务中的

下载目录:https://github.com/scrapy/scr...

建议安装

pip3 install scrapyd-client

安装后在Python的安装目录下的Scripts文件夹里会生成scrapyd-deploy无后缀文件,如果有此文件说明安装成功

重点说明:这个scrapyd-deploy无后缀文件是启动文件,在Linux系统下可以远行,在windows下是不能运行的,所以我们需要编辑一下使其在windows可以运行**

 image

在此目录里新建一个scrapyd-deploy.bat文件,注意名称一定要和scrapyd-deploy相同,我们编辑这个bat文件使其在windows可以运行

image

scrapyd-deploy.bat文件编辑

设置python执行文件路径和scrapyd-deploy无后缀文件路径

@echo off
"C:\Users\admin\AppData\Local\Programs\Python\Python35\python.exe" "C:\Users\admin\AppData\Local\Programs\Python\Python35\Scripts\scrapyd-deploy" %1 %2 %3 %4 %5 %6 %7 %8 %9

scrapyd-deploy.bat文件编辑好后,打开命令窗口cd 到scrapy项目中有scrapy.cfg文件的目录,然后执行scrapyd-deploy命令,看看我们编辑的scrapyd-deploy.bat文件是否可以执行

如果下图表示可以执行

 image

设置scrapy项目中的scrapy.cfg文件,这个文件就是给scrapyd-deploy使用的

 scrapy.cfg文件

注意:下面的中文备注不能写在里面,不然会报错,这写的备注只是方便知道怎么设置

# Automatically created by: scrapy startproject
#
# For more information about the [deploy] section see:
# https://scrapyd.readthedocs.org/en/latest/deploy.html

[settings]
default = adc.settings

[deploy:bobby]                      #设置部署名称bobby
url = http://localhost:6800/        #开启url
project = adc                       #项目名称

命令窗口输入:scrapyd-deploy -l     启动服务,可以看到我们设置的部署名称

image

开始打包前,执行一个命令:scrapy list   ,这个命令执行成功说明可以打包了,如果没执行成功说明还有工作没完成

注意执行 scrapy list  命令的时候很有可能出现错误,如果是python无法找到scrapy项目,需要在scrapy项目里的settings.py配置文件里设置成python可识别路径*

# 将当前项目的一级目录adc目录添加到python可以识别目录中
BASE_DIR = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'adc'))

image

如果错误提示,什么远程计算机拒绝,说明你的scrapy项目有链接远程计算机,如链接数据库或者elasticsearch(搜索引擎)之类的,需要先将链接服务器启动**

 执行 scrapy list  命令返回了爬虫名称说明一切ok了,如下图**

image

到此我们就可以开始打包scrapy项目到scrapyd了,用命令结合scrapy项目中的scrapy.cfg文件设置来打包**

scrapy.cfg文件

# Automatically created by: scrapy startproject
#
# For more information about the [deploy] section see:
# https://scrapyd.readthedocs.org/en/latest/deploy.html

[settings]
default = adc.settings

[deploy:bobby]                      #设置部署名称bobby
url = http://localhost:6800/        #开启url
project = adc                       #项目名称

执行打包命令: scrapyd-deploy 部署名称 -p 项目名称

如:scrapyd-deploy bobby -p adc

如下显示表示scrapy项目打包成功**

image

scrapy项目打包成功后说明

scrapy项目打包成功后会在scrapyd启动服务的目录生成相应的文件,如下:*

1、会在scrapyd启动服务的目录下的dbs文件夹生成scrapy项目名称.db*

image

2、会在scrapyd启动服务的目录下的eggs文件夹生成scrapy项目名称的文件夹,里面是一个scrapyd-deploy打包生成的名称.egg*

image

3、会将scrapy爬虫项目打包,在scrapy项目里会生成两个文件夹,build文件夹和project.egg-info文件夹

build文件夹里是打包后的爬虫项目,scrapyd以后远行的就是这个打包后的项目*

project.egg-info文件夹里是打包时的一些配置

说明:scrapyd-deploy只负责将scrapy爬虫项目打包给scrapyd部署,只需要打包一次,打包后,以后的启动爬虫,停止爬虫等scrapy项目管理由scrapyd来完成**

scrapyd管理scrapy项目

注意:scrapyd管理用的 curl 命令,curl命令不支持windows系统,只支持Linux系统,所以在windows系统下我们用cmder来执行命令1、远行爬虫,远行指定scrapy下面的指定爬虫

curl http://localhost:6800/schedule.json -d project=scrapy项目名称 -d spider=爬虫名称
如:
curl http://localhost:6800/schedule.json -d project=adc -d spider=lagou

image

image

2、停止爬虫

curl http://localhost:6800/cancel.json -d project=scrapy项目名称 -d job=远行ID
如:
curl http://localhost:6800/cancel.json -d project=adc -d job=5454948c93bf11e7af0040167eb10a7b

image

image

3、删除scrapy项目

注意:一般删除scrapy项目,需要先执行命令停止项目下在远行的爬虫**

删除项目后会删除scrapyd启动服务的目录下的eggs文件夹生成egg文件,需要重新用scrapyd-deploy打包后才能再次运行

curl http://localhost:6800/delproject.json -d project=scrapy项目名称
如果:
curl http://localhost:6800/delproject.json -d project=adc

image

4、查看有多少个scrapy项目在api中

image

5、查看指定的scrapy项目中有多少个爬虫

curl http://localhost:6800/listspiders.json?project=scrapy项目名称
如:
curl http://localhost:6800/listspiders.json?project=adc

image

scrapyd支持的API 介绍

 scrapyd支持一系列api,下面用一个py文件来介绍

# -*- coding: utf-8 -*-

import requests
import json 

baseUrl ='http://127.0.0.1:6800/'
daemUrl ='http://127.0.0.1:6800/daemonstatus.json'
listproUrl ='http://127.0.0.1:6800/listprojects.json'
listspdUrl ='http://127.0.0.1:6800/listspiders.json?project=%s'
listspdvUrl= 'http://127.0.0.1:6800/listversions.json?project=%s'
listjobUrl ='http://127.0.0.1:6800/listjobs.json?project=%s'
delspdvUrl= 'http://127.0.0.1:6800/delversion.json'

#http://127.0.0.1:6800/daemonstatus.json
#查看scrapyd服务器运行状态
r= requests.get(daemUrl)
print '1.stats :\n %s \n\n'  %r.text  

#http://127.0.0.1:6800/listprojects.json
#获取scrapyd服务器上已经发布的工程列表
r= requests.get(listproUrl)
print '1.1.listprojects : [%s]\n\n'  %r.text
if len(json.loads(r.text)["projects"])>0 :
    project = json.loads(r.text)["projects"][0]

#http://127.0.0.1:6800/listspiders.json?project=myproject
#获取scrapyd服务器上名为myproject的工程下的爬虫清单
listspd=listspd % project
r= requests.get(listspdUrl)
print '2.listspiders : [%s]\n\n'  %r.text 
if json.loads(r.text).has_key("spiders")>0 :
    spider =json.loads(r.text)["spiders"][0]

#http://127.0.0.1:6800/listversions.json?project=myproject
##获取scrapyd服务器上名为myproject的工程下的各爬虫的版本
listspdvUrl=listspdvUrl % project
r = requests.get(listspdvUrl)
print '3.listversions : [%s]\n\n'  %rtext 
if len(json.loads(r.text)["versions"])>0 :
    version = json.loads(r.text)["versions"][0]

#http://127.0.0.1:6800/listjobs.json?project=myproject
#获取scrapyd服务器上的所有任务清单,包括已结束,正在运行的,准备启动的。
listjobUrl=listjobUrl % proName
r=requests.get(listjobUrl)
print '4.listjobs : [%s]\n\n'  %r.text 

#schedule.json
#http://127.0.0.1:6800/schedule.json -d project=myproject -d spider=myspider
#启动scrapyd服务器上myproject工程下的myspider爬虫,使myspider立刻开始运行,注意必须以post方式
schUrl = baseurl + 'schedule.json'
dictdata ={ "project":project,"spider":spider}
r= reqeusts.post(schUrl, json= dictdata)
print '5.1.delversion : [%s]\n\n'  %r.text 

#http://127.0.0.1:6800/delversion.json -d project=myproject -d version=r99'
#删除scrapyd服务器上myproject的工程下的版本名为version的爬虫,注意必须以post方式
delverUrl = baseurl + 'delversion.json'
dictdata={"project":project ,"version": version }
r= reqeusts.post(delverUrl, json= dictdata)
print '6.1.delversion : [%s]\n\n'  %r.text 

#http://127.0.0.1:6800/delproject.json -d project=myproject
#删除scrapyd服务器上myproject工程,注意该命令会自动删除该工程下所有的spider,注意必须以post方式
delProUrl = baseurl + 'delproject.json'
dictdata={"project":project  }
r= reqeusts.post(delverUrl, json= dictdata)
print '6.2.delproject : [%s]\n\n'  %r.text

总结一下:

1、获取状态

http://127.0.0.1:6800/daemonstatus.json

2、获取项目列表
http://127.0.0.1:6800/listprojects.json

3、获取项目下已发布的爬虫列表

http://127.0.0.1:6800/listspiders.json?project=myproject

4、获取项目下已发布的爬虫版本列表

http://127.0.0.1:6800/listversions.json?project=myproject

5、获取爬虫运行状态

http://127.0.0.1:6800/listjobs.json?project=myproject
 6、启动服务器上某一爬虫(必须是已发布到服务器的爬虫)
http://localhost:6800/schedule.json (post方式,data={"project":myproject,"spider":myspider})

7、删除某一版本爬虫

http://127.0.0.1:6800/delversion.json (post方式,data={"project":myproject,"version":myversion})

8、删除某一工程,包括该工程下的各版本爬虫

http://127.0.0.1:6800/delproject.json(post方式,data={"project":myproject})

 到此,基于scrapyd的爬虫发布教程就写完了。

可能有人会说,我直接用scrapy cwal 命令也可以执行爬虫,个人理解用scrapyd服务器管理爬虫,至少有以下几个优势:

1、可以避免爬虫源码被看到。

2、有版本控制。

3、可以远程启动、停止、删除,正是因为这一点,所以scrapyd也是分布式爬虫的解决方案之一。

查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-11-30

50、elasticsearch(搜索引擎)用Django实现我的搜索以及热门搜索

百度云搜索,搜各种资料:http://www.lqkweb.com
搜网盘,搜各种资料:http://www.swpan.cn

第三百七十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现我的搜索以及热门

image

我的搜素简单实现原理
我们可以用js来实现,首先用js获取到输入的搜索词
设置一个数组里存放搜素词,
判断搜索词在数组里是否存在如果存在删除原来的词,重新将新词放在数组最前面
如果不存在直接将新词放在数组最前面即可,然后循环数组显示结果即可

热门搜索
实现原理,当用户搜索一个词时,可以保存到数据库,然后记录搜索次数,
利用redis缓存搜索次数最到的词,过一段时间更新一下缓存

备注:Django结合Scrapy的开源项目可以学习一下
django-dynamic-scraper
https://github.com/holgerd77/...

补充

默认的elasticsearch(搜索引擎)只能搜索1万条数据,在大就会报错了**

设置方法

步骤一:

打开项目的索引库地址,将该索引先关闭,否则设置操步骤二无法提交

image

步骤二:

打开复合查询,填入如下信息,记得选择PUT方式提交,credit_trace_data改为本索引库中的索引,max_result_window设为20亿,此值是integer类型,不能无限大

http://127.0.0.1:9200/    PUT

 credit_trace_data/_settings?preserve_existing=true

 {

  "max_result_window" : "2000000000"

 }

image

最后点击提交申请,如果配置正确右侧窗口会显示如下信息

image

如果要查询max_result_window时只需要将PUT改为get即可

image

最后记得开启索引!

查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-11-24

49、elasticsearch(搜索引擎)用Django实现搜索结果分页

百度云搜索,搜各种资料:http://www.lqkweb.com
搜网盘,搜各种资料:http://www.swpan.cn
酷站群,搜各种网站源码:http://www.kuzq.cn

逻辑处理函数

  计算搜索耗时
  在开始搜索前:start_time = datetime.now()获取当前时间
  在搜索结束后:end_time = datetime.now()获取当前时间
  last_time = (end_time-start_time).total_seconds()结束时间减去开始时间等于用时,转换成秒

from django.shortcuts import render

# Create your views here.
from django.shortcuts import render,HttpResponse
from django.views.generic.base import View
from app1.models import lagouType               # 导入操作elasticsearch(搜索引擎)类
import json
from elasticsearch import Elasticsearch         # 导入原生的elasticsearch(搜索引擎)接口
client = Elasticsearch(hosts=["127.0.0.1"])     # 连接原生的elasticsearch
from datetime import datetime

def indexluoji(request):
    print(request.method)  # 获取用户请求的路径
    return render(request, 'index.html')

def suggestluoji(request):                                      # 搜索自动补全逻辑处理
    key_words = request.GET.get('s', '')                        # 获取到请求词
    re_datas = []
    if key_words:
        s = lagouType.search()                                  # 实例化elasticsearch(搜索引擎)类的search查询
        s = s.suggest('my_suggest', key_words, completion={
            "field": "suggest", "fuzzy": {
                "fuzziness": 1
            },
            "size": 5
        })
        suggestions = s.execute_suggest()
        for match in suggestions.my_suggest[0].options:
            source = match._source
            re_datas.append(source["title"])
    return HttpResponse(json.dumps(re_datas), content_type="application/json")

def searchluoji(request):                                       # 搜索逻辑处理
    key_words = request.GET.get('q', '')                        # 获取到请求词
    page = request.GET.get('p', '1')                            # 获取访问页码
    try:
        page = int(page)
    except:
        page = 1
    start_time = datetime.now()                                 # 获取当前时间
    response = client.search(                                   # 原生的elasticsearch接口的search()方法,就是搜索,可以支持原生elasticsearch语句查询
        index="lagou",                                          # 设置索引名称
        doc_type="biao",                                        # 设置表名称
        body={                                                  # 书写elasticsearch语句
            "query": {
                "multi_match": {                                # multi_match查询
                    "query": key_words,                         # 查询关键词
                    "fields": ["title", "description"]          # 查询字段
                }
            },
            "from": (page-1)*10,                                          # 从第几条开始获取
            "size": 10,                                         # 获取多少条数据
            "highlight": {                                      # 查询关键词高亮处理
                "pre_tags": ['<span class="keyWord">'],         # 高亮开始标签
                "post_tags": ['</span>'],                       # 高亮结束标签
                "fields": {                                     # 高亮设置
                    "title": {},                                # 高亮字段
                    "description": {}                           # 高亮字段
                }
            }
        }
    )
    end_time = datetime.now()                                   # 获取当前时间
    last_time = (end_time-start_time).total_seconds()           # 结束时间减去开始时间等于用时,转换成秒
    total_nums = response["hits"]["total"]                      # 获取查询结果的总条数
    if (page % 10) > 0:                                         # 计算页数
        paga_nums = int(total_nums/10)+1
    else:
        paga_nums = int(total_nums/10)
    hit_list = []                                               # 设置一个列表来储存搜索到的信息,返回给html页面
    for hit in response["hits"]["hits"]:                        # 循环查询到的结果
        hit_dict = {}                                           # 设置一个字典来储存循环结果
        if "title" in hit["highlight"]:                         # 判断title字段,如果高亮字段有类容
            hit_dict["title"] = "".join(hit["highlight"]["title"])      # 获取高亮里的title
        else:
            hit_dict["title"] = hit["_source"]["title"]                 # 否则获取不是高亮里的title

        if "description" in hit["highlight"]:                           # 判断description字段,如果高亮字段有类容
            hit_dict["description"] = "".join(hit["highlight"]["description"])[:500]    # 获取高亮里的description
        else:
            hit_dict["description"] = hit["_source"]["description"]     # 否则获取不是高亮里的description

        hit_dict["url"] = hit["_source"]["url"]                         # 获取返回url

        hit_list.append(hit_dict)                                       # 将获取到内容的字典,添加到列表
    return render(request, 'result.html', {"page": page,                # 当前页码
                                           "total_nums": total_nums,    # 数据总条数
                                           "all_hits": hit_list,        # 数据列表
                                           "key_words": key_words,      # 搜索词
                                           "paga_nums": paga_nums,      # 页数
                                           "last_time": last_time       # 搜索时间
                                           })                           # 显示页面和将列表和搜索词返回到html

HTML

<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml">
{#引入静态文件路径#}
{% load staticfiles %}
<head>
<meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>python-lcv-search搜索引擎</title>
<link href="{% static 'css/style.css'%}" rel="stylesheet" type="text/css" />
<link href="{% static 'css/result.css'%}" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="container">
    <div id="hd" class="ue-clear">
        <a href="/"><div class="logo"></div></a>
        <div class="inputArea">
            <input type="text" class="searchInput" value="{{ key_words }}"/>
            <input type="button" class="searchButton" onclick="add_search()"/>
        </div>
    </div>
    <div class="nav">
        <ul class="searchList">
            <li class="searchItem current" data-type="article">文章</li>
            <li class="searchItem" data-type="question">问答</li>
            <li class="searchItem" data-type="job">职位</li>
        </ul>
    </div>
    <div id="bd" class="ue-clear">
        <div id="main">
            <div class="sideBar">

                <div class="subfield">网站</div>
                <ul class="subfieldContext">
                    <li>
                        <span class="name">伯乐在线</span>
                        <span class="unit">(None)</span>
                    </li>
                    <li>
                        <span class="name">知乎</span>
                        <span class="unit">(9862)</span>
                    </li>
                    <li>
                        <span class="name">拉勾网</span>
                        <span class="unit">(9862)</span>
                    </li>
                    <li class="more">
                        <a href="javascript:;">
                            <span class="text">更多</span>
                            <i class="moreIcon"></i>
                        </a>
                    </li>
                </ul>

                <div class="sideBarShowHide">
                    <a href="javascript:;" class="icon"></a>
                </div>
            </div>
            <div class="resultArea">
                <p class="resultTotal">
                    <span class="info">找到约&nbsp;<span class="totalResult">{{ total_nums }}</span>&nbsp;条结果(用时<span class="time">{{ last_time }}</span>秒),共约<span class="totalPage">{{ paga_nums }}</span>页</span>
                </p>
                <div class="resultList">
                    {% for hit in all_hits %}
                    <div class="resultItem">
                            <div class="itemHead">
                                <a href="{% autoescape off %} {{ hit.url }} {% endautoescape %}"  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">3.401155</span>
                                </span>
                            </div>
                            <div class="itemBody">
                                {% autoescape off %} {{ hit.description }} {% endautoescape %}
                            </div>
                        </div>
                    {% endfor %}
                </div>
                <!-- 分页 -->
                <div class="pagination ue-clear"></div>
                <!-- 相关搜索 -->

            </div>
            <div class="historyArea">
                <div class="hotSearch">
                    <h6>热门搜索</h6>
                    <ul class="historyList">

                            <li><a href="/search?q=linux">linux</a></li>

                    </ul>
                </div>
                <div class="mySearch">
                    <h6>我的搜索</h6>
                    <ul class="historyList">

                    </ul>
                </div>
            </div>
        </div><!-- End of main -->
    </div><!--End of bd-->
</div>

<div id="foot">Copyright &copy;projectsedu.com 版权所有  E-mail:admin@projectsedu.com</div>
</body>
<script type="text/javascript" data-original="{% static 'js/jquery.js'%}"></script>
<script type="text/javascript" data-original="{% static 'js/global.js'%}"></script>
<script type="text/javascript" data-original="{% static 'js/pagination.js'%}"></script>
<script type="text/javascript">
    var search_url = "/search/"

    $('.searchList').on('click', '.searchItem', function(){
        $('.searchList .searchItem').removeClass('current');
        $(this).addClass('current');    
    });

    $.each($('.subfieldContext'), function(i, item){
        $(this).find('li:gt(2)').hide().end().find('li:last').show();        
    });

    function removeByValue(arr, val) {
      for(var i=0; i<arr.length; i++) {
        if(arr[i] == val) {
          arr.splice(i, 1);
          break;
        }
      }
    }
    $('.subfieldContext .more').click(function(e){
        var $more = $(this).parent('.subfieldContext').find('.more');
        if($more.hasClass('show')){

            if($(this).hasClass('define')){
                $(this).parent('.subfieldContext').find('.more').removeClass('show').find('.text').text('自定义');
            }else{
                $(this).parent('.subfieldContext').find('.more').removeClass('show').find('.text').text('更多');    
            }
            $(this).parent('.subfieldContext').find('li:gt(2)').hide().end().find('li:last').show();
        }else{
            $(this).parent('.subfieldContext').find('.more').addClass('show').find('.text').text('收起');
            $(this).parent('.subfieldContext').find('li:gt(2)').show();    
        }

    });

    $('.sideBarShowHide a').click(function(e) {
        if($('#main').hasClass('sideBarHide')){
            $('#main').removeClass('sideBarHide');
            $('#container').removeClass('sideBarHide');
        }else{
            $('#main').addClass('sideBarHide');    
            $('#container').addClass('sideBarHide');
        }

    });
    var key_words = "{{ key_words }}"
    //分页
    $(".pagination").pagination({{ total_nums }}, {
        current_page :{{ page|add:'-1' }}, //当前页码
        items_per_page :10,
        display_msg :true,
        callback :pageselectCallback
    });
    function pageselectCallback(page_id, jq) {
        window.location.href=search_url+'?q='+key_words+'&p='+page_id
    }

    setHeight();
    $(window).resize(function(){
        setHeight();    
    });

    function setHeight(){
        if($('#container').outerHeight() < $(window).height()){
            $('#container').height($(window).height()-33);
        }    
    }
</script>
<script type="text/javascript">
    $('.searchList').on('click', '.searchItem', function(){
        $('.searchList .searchItem').removeClass('current');
        $(this).addClass('current');
    });

    // 联想下拉显示隐藏
    $('.searchInput').on('focus', function(){
        $('.dataList').show()
    });

    // 联想下拉点击
    $('.dataList').on('click', 'li', function(){
        var text = $(this).text();
        $('.searchInput').val(text);
        $('.dataList').hide()
    });

    hideElement($('.dataList'), $('.searchInput'));
</script>
<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 > 6){
            arrLen = 6
        }else {
            arrLen = searchArr.length
        }
        for (var i=0;i<arrLen;i++){
            tmpHtml += '<li><a href="/search?q='+searchArr[i]+'">'+searchArr[i]+'</a></li>'
        }
        $(".mySearch .historyList").append(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>
</html>

结果:

image

image

查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-11-24

48、elasticsearch(搜索引擎)用Django实现搜索功能

百度云搜索,搜各种资料:http://www.lqkweb.com
搜网盘,搜各种资料:http://www.swpan.cn
酷站群,搜各种网站源码:http://www.kuzq.cn

Django实现搜索功能

1、在Django配置搜索结果页的路由映射

"""pachong URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^/pre>, views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^/pre>, Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app1 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^/pre>, views.indexluoji),
    url(r'^index/', views.indexluoji),
    url(r'^suggest//pre>, views.suggestluoji,name="suggest"),     # 搜索字段补全请求
    url(r'^search//pre>, views.searchluoji,name="search"),     # 搜索

]

2、编写逻辑处理函数

在逻辑处理函数里实现搜索数据

(1)获取到用户的搜索词

(2)利用原生的elasticsearch(搜索引擎)接口,实现搜索,注明:elasticsearch-dsl就是在原生的elasticsearch上做了封装

  Elasticsearch()方法,连接原生的elasticsearch服务器

  search()方法,原生elasticsearch查询方法,支持原生的elasticsearch查询语句,返回的原生语句结果也就是字典形式的数据

  在查询语句里进行关键词高亮处理

  将查询到的结果,循环获取到后返回到html页面

from django.shortcuts import render

# Create your views here.
from django.shortcuts import render,HttpResponse
from django.views.generic.base import View
from app1.models import lagouType               # 导入操作elasticsearch(搜索引擎)类
import json
from elasticsearch import Elasticsearch         # 导入原生的elasticsearch(搜索引擎)接口
client = Elasticsearch(hosts=["127.0.0.1"])     # 连接原生的elasticsearch

def indexluoji(request):
    print(request.method)  # 获取用户请求的路径
    return render(request, 'index.html')

def suggestluoji(request):                                      # 搜索自动补全逻辑处理
    key_words = request.GET.get('s', '')                        # 获取到请求词
    re_datas = []
    if key_words:
        s = lagouType.search()                                  # 实例化elasticsearch(搜索引擎)类的search查询
        s = s.suggest('my_suggest', key_words, completion={
            "field": "suggest", "fuzzy": {
                "fuzziness": 1
            },
            "size": 5
        })
        suggestions = s.execute_suggest()
        for match in suggestions.my_suggest[0].options:
            source = match._source
            re_datas.append(source["title"])
    return HttpResponse(json.dumps(re_datas), content_type="application/json")

def searchluoji(request):                                       # 搜索逻辑处理
    key_words = request.GET.get('q', '')                        # 获取到请求词
    response = client.search(                                   # 原生的elasticsearch接口的search()方法,就是搜索,可以支持原生elasticsearch语句查询
        index="lagou",                                          # 设置索引名称
        doc_type="biao",                                        # 设置表名称
        body={                                                  # 书写elasticsearch语句
            "query": {
                "multi_match": {                                # multi_match查询
                    "query": key_words,                         # 查询关键词
                    "fields": ["title", "description"]          # 查询字段
                }
            },
            "from": 0,                                          # 从第几条开始获取
            "size": 10,                                         # 获取多少条数据
            "highlight": {                                      # 查询关键词高亮处理
                "pre_tags": ['<span class="keyWord">'],         # 高亮开始标签
                "post_tags": ['</span>'],                       # 高亮结束标签
                "fields": {                                     # 高亮设置
                    "title": {},                                # 高亮字段
                    "description": {}                           # 高亮字段
                }
            }
        }
    )
    total_nums = response["hits"]["total"]                      # 获取查询结果的总条数
    hit_list = []                                               # 设置一个列表来储存搜索到的信息,返回给html页面
    for hit in response["hits"]["hits"]:                        # 循环查询到的结果
        hit_dict = {}                                           # 设置一个字典来储存循环结果
        if "title" in hit["highlight"]:                         # 判断title字段,如果高亮字段有类容
            hit_dict["title"] = "".join(hit["highlight"]["title"])      # 获取高亮里的title
        else:
            hit_dict["title"] = hit["_source"]["title"]                 # 否则获取不是高亮里的title

        if "description" in hit["highlight"]:                           # 判断description字段,如果高亮字段有类容
            hit_dict["description"] = "".join(hit["highlight"]["description"])[:500]    # 获取高亮里的description
        else:
            hit_dict["description"] = hit["_source"]["description"]     # 否则获取不是高亮里的description

        hit_dict["url"] = hit["_source"]["url"]                         # 获取返回url

        hit_list.append(hit_dict)                                       # 将获取到内容的字典,添加到列表
    return render(request, 'result.html', {"all_hits": hit_list, "key_words": key_words})       #显示页面和将列表和搜索词返回到html

3、html页面接收搜索结果

注意:因为Django实现了防止恶意代码写入,凡是通过变量传输到html页面的html类型代码,将会被自动转换成字符串方式显示,索引我们需要在接收变量的字段用:{% autoescape off %} {{ 接收变量 }} {% endautoescape %},来显示html代码,

搜索后因为进行了一次跳转,所以搜索框里的搜索词将不存在,我们需要在传递搜索结果到页面的时候,将搜索词也传递进来填充到搜索框

<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml">
{#引入静态文件路径#}
{% load staticfiles %}
<head>
<meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>python-lcv-search搜索引擎</title>
<link href="{% static 'css/style.css'%}" rel="stylesheet" type="text/css" />
<link href="{% static 'css/result.css'%}" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="container">
    <div id="hd" class="ue-clear">
        <a href="/"><div class="logo"></div></a>
        <div class="inputArea">
            <input type="text" class="searchInput" value="{{ key_words }}"/>
            <input type="button" class="searchButton" onclick="add_search()"/>
        </div>
    </div>
    <div class="nav">
        <ul class="searchList">
            <li class="searchItem current" data-type="article">文章</li>
            <li class="searchItem" data-type="question">问答</li>
            <li class="searchItem" data-type="job">职位</li>
        </ul>
    </div>
    <div id="bd" class="ue-clear">
        <div id="main">
            <div class="sideBar">

                <div class="subfield">网站</div>
                <ul class="subfieldContext">
                    <li>
                        <span class="name">伯乐在线</span>
                        <span class="unit">(None)</span>
                    </li>
                    <li>
                        <span class="name">知乎</span>
                        <span class="unit">(9862)</span>
                    </li>
                    <li>
                        <span class="name">拉勾网</span>
                        <span class="unit">(9862)</span>
                    </li>
                    <li class="more">
                        <a href="javascript:;">
                            <span class="text">更多</span>
                            <i class="moreIcon"></i>
                        </a>
                    </li>
                </ul>

                <div class="sideBarShowHide">
                    <a href="javascript:;" class="icon"></a>
                </div>
            </div>
            <div class="resultArea">
                <p class="resultTotal">
                    <span class="info">找到约&nbsp;<span class="totalResult">45</span>&nbsp;条结果(用时<span class="time">0.643128</span>秒),共约<span class="totalPage">5</span>页</span>
                </p>
                <div class="resultList">
                    {% for hit in all_hits %}
                    <div class="resultItem">
                            <div class="itemHead">
                                <a href="{% autoescape off %} {{ hit.url }} {% endautoescape %}"  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">3.401155</span>
                                </span>
                            </div>
                            <div class="itemBody">
                                {% autoescape off %} {{ hit.description }} {% endautoescape %}
                            </div>
                        </div>
                    {% endfor %}
                </div>
                <!-- 分页 -->
                <div class="pagination ue-clear"></div>
                <!-- 相关搜索 -->

            </div>
            <div class="historyArea">
                <div class="hotSearch">
                    <h6>热门搜索</h6>
                    <ul class="historyList">

                            <li><a href="/search?q=linux">linux</a></li>

                    </ul>
                </div>
                <div class="mySearch">
                    <h6>我的搜索</h6>
                    <ul class="historyList">

                    </ul>
                </div>
            </div>
        </div><!-- End of main -->
    </div><!--End of bd-->
</div>

<div id="foot">Copyright &copy;projectsedu.com 版权所有  E-mail:admin@projectsedu.com</div>
</body>
<script type="text/javascript" data-original="{% static 'js/jquery.js'%}"></script>
<script type="text/javascript" data-original="{% static 'js/global.js'%}"></script>
<script type="text/javascript" data-original="{% static 'js/pagination.js'%}"></script>
<script type="text/javascript">
    var search_url = "/search/"

    $('.searchList').on('click', '.searchItem', function(){
        $('.searchList .searchItem').removeClass('current');
        $(this).addClass('current');    
    });

    $.each($('.subfieldContext'), function(i, item){
        $(this).find('li:gt(2)').hide().end().find('li:last').show();        
    });

    function removeByValue(arr, val) {
      for(var i=0; i<arr.length; i++) {
        if(arr[i] == val) {
          arr.splice(i, 1);
          break;
        }
      }
    }
    $('.subfieldContext .more').click(function(e){
        var $more = $(this).parent('.subfieldContext').find('.more');
        if($more.hasClass('show')){

            if($(this).hasClass('define')){
                $(this).parent('.subfieldContext').find('.more').removeClass('show').find('.text').text('自定义');
            }else{
                $(this).parent('.subfieldContext').find('.more').removeClass('show').find('.text').text('更多');    
            }
            $(this).parent('.subfieldContext').find('li:gt(2)').hide().end().find('li:last').show();
        }else{
            $(this).parent('.subfieldContext').find('.more').addClass('show').find('.text').text('收起');
            $(this).parent('.subfieldContext').find('li:gt(2)').show();    
        }

    });

    $('.sideBarShowHide a').click(function(e) {
        if($('#main').hasClass('sideBarHide')){
            $('#main').removeClass('sideBarHide');
            $('#container').removeClass('sideBarHide');
        }else{
            $('#main').addClass('sideBarHide');    
            $('#container').addClass('sideBarHide');
        }

    });
    var key_words = "java"
    //分页
    $(".pagination").pagination(45, {
        current_page :0, //当前页码
        items_per_page :10,
        display_msg :true,
        callback :pageselectCallback
    });
    function pageselectCallback(page_id, jq) {
        window.location.href=search_url+'?q='+key_words+'&p='+page_id
    }

    setHeight();
    $(window).resize(function(){
        setHeight();    
    });

    function setHeight(){
        if($('#container').outerHeight() < $(window).height()){
            $('#container').height($(window).height()-33);
        }    
    }
</script>
<script type="text/javascript">
    $('.searchList').on('click', '.searchItem', function(){
        $('.searchList .searchItem').removeClass('current');
        $(this).addClass('current');
    });

    // 联想下拉显示隐藏
    $('.searchInput').on('focus', function(){
        $('.dataList').show()
    });

    // 联想下拉点击
    $('.dataList').on('click', 'li', function(){
        var text = $(this).text();
        $('.searchInput').val(text);
        $('.dataList').hide()
    });

    hideElement($('.dataList'), $('.searchInput'));
</script>
<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 > 6){
            arrLen = 6
        }else {
            arrLen = searchArr.length
        }
        for (var i=0;i<arrLen;i++){
            tmpHtml += '<li><a href="/search?q='+searchArr[i]+'">'+searchArr[i]+'</a></li>'
        }
        $(".mySearch .historyList").append(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>
</html>

最终效果

image

查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-11-23

47、elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

百度云搜索,搜各种资料:http://www.lqkweb.com
搜网盘,搜各种资料:http://www.swpan.cn

image

elasticsearch(搜索引擎)提供了自动补全接口

官方说明:https://www.elastic.co/guide/...

1、创建搜索自动补全字段suggest

自动补全需要用到一个字段名称为suggest类型为Completion类型的一个字段

所以我们需要用将前面的elasticsearch-dsl操作elasticsearch(搜索引擎)增加suggest类型为Completion

注意:因为elasticsearch-dsl源码问题,设置字段为Completion类型指定分词器时会报错,所以我们需要重写CustomAnalyzer类

只有Completion类型才是,其他类型不用,其他类型直接指定分词器即可

#!/usr/bin/env python

from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \
    analyzer, InnerObjectWrapper, Completion, Keyword, Text, Integer

# 更多字段类型见第三百六十四节elasticsearch(搜索引擎)的mapping映射管理
from elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzer    #导入CustomAnalyzer类

from elasticsearch_dsl.connections import connections                       # 导入连接elasticsearch(搜索引擎)服务器方法
connections.create_connection(hosts=['127.0.0.1'])

class CustomAnalyzer(_CustomAnalyzer):                                      # 自定义CustomAnalyzer类,来重写CustomAnalyzer类
    def get_analysis_definition(self):
        return {}

ik_analyzer = CustomAnalyzer("ik_max_word", filter=["lowercase"])           # 实例化重写的CustomAnalyzer类传入分词器和大小写转,将大写转换成小写

class lagouType(DocType):                                                   # 自定义一个类来继承DocType类
    suggest = Completion(analyzer=ik_analyzer)
    # Text类型需要分词,所以需要知道中文分词器,ik_max_wordwei为中文分词器
    title = Text(analyzer="ik_max_word")                                    # 设置,字段名称=字段类型,Text为字符串类型并且可以分词建立倒排索引
    description = Text(analyzer="ik_max_word")
    keywords = Text(analyzer="ik_max_word")
    url = Keyword()                                                         # 设置,字段名称=字段类型,Keyword为普通字符串类型,不分词
    riqi = Date()                                                           # 设置,字段名称=字段类型,Date日期类型

    class Meta:                                                             # Meta是固定写法
        index = "lagou"                                                     # 设置索引名称(相当于数据库名称)
        doc_type = 'biao'                                                   # 设置表名称

if __name__ == "__main__":          # 判断在本代码文件执行才执行里面的方法,其他页面调用的则不执行里面的方法
    lagouType.init()                # 生成elasticsearch(搜索引擎)的索引,表,字段等信息

# 使用方法说明:
# 在要要操作elasticsearch(搜索引擎)的页面,导入此模块
# lagou = lagouType()           #实例化类
# lagou.title = '值'            #要写入字段=值
# lagou.description = '值'
# lagou.keywords = '值'
# lagou.url = '值'
# lagou.riqi = '值'
# lagou.save()                  #将数据写入elasticsearch(搜索引擎)

2、搜索自动补全字段suggest写入数据

搜索自动补全字段suggest接收的要搜索的字段分词数据,详情见下面的自定义分词函数

elasticsearch-dsl操作elasticsearch(搜索引擎)

#!/usr/bin/env python
# -*- coding:utf8 -*-
#!/usr/bin/env python

from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \
    analyzer, InnerObjectWrapper, Completion, Keyword, Text, Integer
from elasticsearch_dsl.connections import connections                       # 导入连接elasticsearch(搜索引擎)服务器方法
# 更多字段类型见第三百六十四节elasticsearch(搜索引擎)的mapping映射管理
from elasticsearch_dsl.analysis import CustomAnalyzer as _CustomAnalyzer    #导入CustomAnalyzer类

connections.create_connection(hosts=['127.0.0.1'])

class CustomAnalyzer(_CustomAnalyzer):                                      # 自定义CustomAnalyzer类,来重写CustomAnalyzer类
    def get_analysis_definition(self):
        return {}

ik_analyzer = CustomAnalyzer("ik_max_word", filter=["lowercase"])           # 实例化重写的CustomAnalyzer类传入分词器和大小写转,将大写转换成小写

class lagouType(DocType):                                                   # 自定义一个类来继承DocType类
    suggest = Completion(analyzer=ik_analyzer)
    # Text类型需要分词,所以需要知道中文分词器,ik_max_wordwei为中文分词器
    title = Text(analyzer="ik_max_word")                                    # 设置,字段名称=字段类型,Text为字符串类型并且可以分词建立倒排索引
    description = Text(analyzer="ik_max_word")
    keywords = Text(analyzer="ik_max_word")
    url = Keyword()                                                         # 设置,字段名称=字段类型,Keyword为普通字符串类型,不分词
    riqi = Date()                                                           # 设置,字段名称=字段类型,Date日期类型

    class Meta:                                                             # Meta是固定写法
        index = "lagou"                                                     # 设置索引名称(相当于数据库名称)
        doc_type = 'biao'                                                   # 设置表名称

def gen_suggest(index, info_tuple):
    # 根据字符串生成搜索建议数组
    """
    此函数主要用于,连接elasticsearch(搜索引擎),使用ik_max_word分词器,将传入的字符串进行分词,返回分词后的结果
    此函数需要两个参数:
    第一个参数:要调用elasticsearch(搜索引擎)分词的索引index,一般是(索引操作类._doc_type.index)
    第二个参数:是一个元组,元祖的元素也是元组,元素元祖里有两个值一个是要分词的字符串,第二个是分词的权重,多个分词传多个元祖如下
    书写格式:
    gen_suggest(lagouType._doc_type.index, (('字符串', 10),('字符串', 8)))
    """
    es = connections.create_connection(lagouType._doc_type.using)       # 连接elasticsearch(搜索引擎),使用操作搜索引擎的类下面的_doc_type.using连接
    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})

    # 返回分词后的列表,里面是字典,
    # 如:[{'input': ['录音', '广告'], 'weight': 10}, {'input': ['新能源', '汽车',], 'weight': 8}]
    return suggests

if __name__ == "__main__":          # 判断在本代码文件执行才执行里面的方法,其他页面调用的则不执行里面的方法
    lagouType.init()                # 生成elasticsearch(搜索引擎)的索引,表,字段等信息
# 使用方法说明:
# 在要要操作elasticsearch(搜索引擎)的页面,导入此模块
# lagou = lagouType()           #实例化类
# lagou.title = '值'            #要写入字段=值
# lagou.description = '值'
# lagou.keywords = '值'
# lagou.url = '值'
# lagou.riqi = '值'
# lagou.save()                  #将数据写入elasticsearch(搜索引擎)

suggest字段写入数据

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
# items.py,文件是专门用于,接收爬虫获取到的数据信息的,就相当于是容器文件

import scrapy
from scrapy.loader.processors import MapCompose, TakeFirst
from scrapy.loader import ItemLoader                            # 导入ItemLoader类也就加载items容器类填充数据
from adc.models.elasticsearch_orm import lagouType, gen_suggest  # 导入elasticsearch操作模块

class LagouItemLoader(ItemLoader):                  # 自定义Loader继承ItemLoader类,在爬虫页面调用这个类填充数据到Item类
    default_output_processor = TakeFirst()          # 默认利用ItemLoader类,加载items容器类填充数据,是列表类型,可以通过TakeFirst()方法,获取到列表里的内容

def tianjia(value):                                 # 自定义数据预处理函数
    return value                                    # 将处理后的数据返给Item

class LagouItem(scrapy.Item):                       # 设置爬虫获取到的信息容器类
    title = scrapy.Field(                           # 接收爬虫获取到的title信息
        input_processor=MapCompose(tianjia),        # 将数据预处理函数名称传入MapCompose方法里处理,数据预处理函数的形式参数value会自动接收字段title
    )
    description = scrapy.Field()
    keywords = scrapy.Field()
    url = scrapy.Field()
    riqi = scrapy.Field()

    def save_to_es(self):
        lagou = lagouType()                         # 实例化elasticsearch(搜索引擎对象)
        lagou.title = self['title']                 # 字段名称=值
        lagou.description = self['description']
        lagou.keywords = self['keywords']
        lagou.url = self['url']
        lagou.riqi = self['riqi']
        # 将title和keywords数据传入分词函数,进行分词组合后返回写入搜索建议字段suggest
        lagou.suggest = gen_suggest(lagouType._doc_type.index, ((lagou.title, 10),(lagou.keywords, 8)))
        lagou.save()                                # 将数据写入elasticsearch(搜索引擎对象)
        return

写入elasticsearch(搜索引擎)后的情况

{
    "_index": "lagou",
    "_type": "biao",
    "_id": "AV5MDu0NXJs9MkF5tFxW",
    "_version": 1,
    "_score": 1,
    "_source": {
        "title": "LED光催化灭蚊灯广告录音_广告录音网-火红广告录音_叫卖录音下载_语音广告制作",
        "keywords": "各类小商品,广告录音,叫卖录音,火红广告录音",
        "url": "http://www.luyin.org/post/2486.html",
        "suggest": [
            {
                "input": [
                    "广告"
                    ,
                    "火红"
                    ,
                    "制作"
                    ,
                    "叫卖"
                    ,
                    "灭蚊灯"
                    ,
                    "语音"
                    ,
                    "下载"
                    ,
                    "led"
                    ,
                    "录音"
                    ,
                    "灭蚊"
                    ,
                    "光催化"
                    ,
                    "催化"
                ],
                "weight": 10
            }
            ,
            {
                "input": [
                    "小商品"
                    ,
                    "广告"
                    ,
                    "各类"
                    ,
                    "火红"
                    ,
                    "叫卖"
                    ,
                    "商品"
                    ,
                    "小商"
                    ,
                    "录音"
                ],
                "weight": 8
            }
        ],
        "riqi": "2017-09-04T16:43:20",
        "description": "LED光催化灭蚊灯广告录音 是广告录音网-火红广告录音中一篇关于 各类小商品 的文章,欢迎您阅读和评论,专业叫卖录音-广告录音-语音广告制作"
    }
}

 image

用Django实现搜索的自动补全功能说明

1.将搜索框绑定一个事件,每输入一个字触发这个事件,获取到输入框里的内容,用ajax将输入的词请求到Django的逻辑处理函数。

2.在逻辑处理函数里,将请求词用elasticsearch(搜索引擎)的fuzzy模糊查询,查询suggest字段里存在请求词的数据,将查询到的数据添加到自动补全

html代码:

<!DOCTYPE html >
<html xmlns="http://www.w3.org/1999/xhtml">
{#引入静态文件路径#}
{% load staticfiles %}
<head>
<meta http-equiv="X-UA-Compatible" content="IE=emulateIE7" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>lcv-search 搜索引擎</title>
<link href="{% static 'css/style.css'%}" rel="stylesheet" type="text/css" />
<link href="{% static 'css/index.css'%}" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="container">
    <div id="bd">
        <div id="main">
            <h1 class="title">
                <div class="logo large"></div>
            </h1>
            <div class="nav ue-clear">
                <ul class="searchList">
                    <li class="searchItem current" data-type="article">文章</li>
                    <li class="searchItem" data-type="question">问答</li>
                    <li class="searchItem" data-type="job">职位</li>
                </ul>
            </div>
            <div class="inputArea">
                {% csrf_token %}
                <input type="text" class="searchInput" />
                <input type="button" class="searchButton" onclick="add_search()" />
                <ul class="dataList">
                    <li>如何学好设计</li>
                    <li>界面设计</li>
                    <li>UI设计培训要多少钱</li>
                    <li>设计师学习</li>
                    <li>哪里有好的网站</li>
                </ul>
            </div>

            <div class="historyArea">
                <p class="history">
                    <label>热门搜索:</label>

                </p>
                <p class="history mysearch">
                    <label>我的搜索:</label>
                    <span class="all-search">
                        <a href="javascript:;">专注界面设计网站</a>
                        <a href="javascript:;">用户体验</a>
                        <a href="javascript:;">互联网</a>
                        <a href="javascript:;">资费套餐</a>
                    </span>

                </p>
            </div>
        </div><!-- End of main -->
    </div><!--End of bd-->

    <div class="foot">
        <div class="wrap">
            <div class="copyright">Copyright &copy;uimaker.com 版权所有  E-mail:admin@uimaker.com</div>
        </div>
    </div>
</div>
</body>
<script type="text/javascript" data-original="{% static 'js/jquery.js'%}"></script>
<script type="text/javascript" data-original="{% static 'js/global.js'%}"></script>
<script type="text/javascript">
    var suggest_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>
<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>
</html>

Django路由映射

"""pachong URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^/pre>, views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^/pre>, Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app1 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^/pre>, views.indexluoji),
    url(r'^index/', views.indexluoji),
    url(r'^suggest//pre>, views.suggestluoji,name="suggest"),     # 搜索字段补全请求

]

Django静态文件配置

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
#配置静态文件前缀
STATIC_URL = '/static/'
#配置静态文件目录
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

备注:搜索自动补全fuzzy查询

#搜索自动补全fuzzy查询
POST lagou/biao/_search?pretty
{
  "suggest":{          #字段名称
    "my_suggest":{       #自定义变量
      "text":"广告",      #搜索词
      "completion":{
        "field":"suggest",  #搜索字段
        "fuzzy":{
          "fuzziness":1    #编辑距离
        }
      }
    }
  },
  "_source":"title"
}

Django逻辑处理文件

from django.shortcuts import render

# Create your views here.
from django.shortcuts import render,HttpResponse
from django.views.generic.base import View
from app1.models import lagouType   #导入操作elasticsearch(搜索引擎)类
import json

def indexluoji(request):
    print(request.method)  # 获取用户请求的路径
    return render(request, 'index.html')

def suggestluoji(request):                                      # 搜索自动补全逻辑处理
    key_words = request.GET.get('s', '')                        # 获取到请求词
    re_datas = []
    if key_words:
        s = lagouType.search()                                  # 实例化elasticsearch(搜索引擎)类的search查询
        s = s.suggest('my_suggest', key_words, completion={
            "field": "suggest", "fuzzy": {
                "fuzziness": 2
            },
            "size": 5
        })
        suggestions = s.execute_suggest()
        for match in suggestions.my_suggest[0].options:
            source = match._source
            re_datas.append(source["title"])
    return HttpResponse(json.dumps(re_datas), content_type="application/json")

image

最终完成

image

查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-11-23

46、elasticsearch(搜索引擎)scrapy写入数据到elasticsearch中

百度云搜索,搜各种资料:http://www.lqkweb.com
搜网盘,搜各种资料:http://www.swpan.cn

前面我们讲到的elasticsearch(搜索引擎)操作,如:增、删、改、查等操作都是用的elasticsearch的语言命令,就像sql命令一样,当然elasticsearch官方也提供了一个python操作elasticsearch(搜索引擎)的接口包,就像sqlalchemy操作数据库一样的ORM框,这样我们操作elasticsearch就不用写命令了,用elasticsearch-dsl-py这个模块来操作,也就是用python的方式操作一个类即可

elasticsearch-dsl-py下载

下载地址:https://github.com/elastic/el...

文档说明:http://elasticsearch-dsl.read...

首先安装好elasticsearch-dsl-py模块

1、elasticsearch-dsl模块使用说明

create_connection(hosts=['127.0.0.1']):连接elasticsearch(搜索引擎)服务器方法,可以连接多台服务器
class Meta:设置索引名称和表名称
索引类名称.init(): 生成索引和表以及字段
实例化索引类.save():将数据写入elasticsearch(搜索引擎)

elasticsearch_orm.py 操作elasticsearch(搜索引擎)文件

#!/usr/bin/env python
# -*- coding:utf8 -*-
from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \
    analyzer, InnerObjectWrapper, Completion, Keyword, Text, Integer

# 更多字段类型见第三百六十四节elasticsearch(搜索引擎)的mapping映射管理

from elasticsearch_dsl.connections import connections       # 导入连接elasticsearch(搜索引擎)服务器方法
connections.create_connection(hosts=['127.0.0.1'])

class lagouType(DocType):                                                   # 自定义一个类来继承DocType类
    # Text类型需要分词,所以需要知道中文分词器,ik_max_wordwei为中文分词器
    title = Text(analyzer="ik_max_word")                                    # 设置,字段名称=字段类型,Text为字符串类型并且可以分词建立倒排索引
    description = Text(analyzer="ik_max_word")
    keywords = Text(analyzer="ik_max_word")
    url = Keyword()                                                         # 设置,字段名称=字段类型,Keyword为普通字符串类型,不分词
    riqi = Date()                                                           # 设置,字段名称=字段类型,Date日期类型

    class Meta:                                                             # Meta是固定写法
        index = "lagou"                                                     # 设置索引名称(相当于数据库名称)
        doc_type = 'biao'                                                   # 设置表名称

if __name__ == "__main__":          # 判断在本代码文件执行才执行里面的方法,其他页面调用的则不执行里面的方法
    lagouType.init()                # 生成elasticsearch(搜索引擎)的索引,表,字段等信息

# 使用方法说明:
# 在要要操作elasticsearch(搜索引擎)的页面,导入此模块
# lagou = lagouType()           #实例化类
# lagou.title = '值'            #要写入字段=值
# lagou.description = '值'
# lagou.keywords = '值'
# lagou.url = '值'
# lagou.riqi = '值'
# lagou.save()                  #将数据写入elasticsearch(搜索引擎)

2、scrapy写入数据到elasticsearch中

爬虫文件

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from adc.items import LagouItem,LagouItemLoader  #导入items容器类,和ItemLoader类
import time

class LagouSpider(CrawlSpider):                     #创建爬虫类
    name = 'lagou'                                  #爬虫名称
    allowed_domains = ['www.luyin.org']             #起始域名
    start_urls = ['http://www.luyin.org/']          #起始url

    custom_settings = {
        "AUTOTHROTTLE_ENABLED": True,                             #覆盖掉settings.py里的相同设置,开启COOKIES
        "DOWNLOAD_DELAY":5
    }

    rules = (
        #配置抓取列表页规则
        Rule(LinkExtractor(allow=('ggwa/.*')), follow=True),

        #配置抓取内容页规则
        Rule(LinkExtractor(allow=('post/\d+.html.*')), callback='parse_job', follow=True),
    )

    def parse_job(self, response):                  #回调函数,注意:因为CrawlS模板的源码创建了parse回调函数,所以切记我们不能创建parse名称的函数
        atime = time.localtime(time.time())         #获取系统当前时间
        dqatime = "{0}-{1}-{2} {3}:{4}:{5}".format(
            atime.tm_year,
            atime.tm_mon,
            atime.tm_mday,
            atime.tm_hour,
            atime.tm_min,
            atime.tm_sec
        )  # 将格式化时间日期,单独取出来拼接成一个完整日期

        url = response.url

        item_loader = LagouItemLoader(LagouItem(), response=response)   # 将数据填充进items.py文件的LagouItem
        item_loader.add_xpath('title', '/html/head/title/text()')
        item_loader.add_xpath('description', '/html/head/meta[@name="Description"]/@content')
        item_loader.add_xpath('keywords', '/html/head/meta[@name="keywords"]/@content')
        item_loader.add_value('url', url)
        item_loader.add_value('riqi', dqatime)
        article_item = item_loader.load_item()
yield article_item

items.py文件

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
#items.py,文件是专门用于,接收爬虫获取到的数据信息的,就相当于是容器文件

import scrapy
from scrapy.loader.processors import MapCompose,TakeFirst
from scrapy.loader import ItemLoader                #导入ItemLoader类也就加载items容器类填充数据
from adc.models.elasticsearch_orm import lagouType  #导入elasticsearch操作模块

class LagouItemLoader(ItemLoader):                  #自定义Loader继承ItemLoader类,在爬虫页面调用这个类填充数据到Item类
    default_output_processor = TakeFirst()          #默认利用ItemLoader类,加载items容器类填充数据,是列表类型,可以通过TakeFirst()方法,获取到列表里的内容

def tianjia(value):                                 #自定义数据预处理函数
    return value                                    #将处理后的数据返给Item

class LagouItem(scrapy.Item):                       #设置爬虫获取到的信息容器类
    title = scrapy.Field(                           #接收爬虫获取到的title信息
        input_processor=MapCompose(tianjia),        #将数据预处理函数名称传入MapCompose方法里处理,数据预处理函数的形式参数value会自动接收字段title
    )
    description = scrapy.Field()
    keywords = scrapy.Field()
    url = scrapy.Field()
    riqi = scrapy.Field()

    def save_to_es(self):
        lagou = lagouType()                         # 实例化elasticsearch(搜索引擎对象)
        lagou.title = self['title']                 # 字段名称=值
        lagou.description = self['description']
        lagou.keywords = self['keywords']
        lagou.url = self['url']
        lagou.riqi = self['riqi']
        lagou.save()                                # 将数据写入elasticsearch(搜索引擎对象)
        return

pipelines.py文件

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
from adc.models.elasticsearch_orm import lagouType  #导入elasticsearch操作模块

class AdcPipeline(object):
    def process_item(self, item, spider):

        #也可以在这里将数据写入elasticsearch搜索引擎,这里的缺点是统一处理
        # lagou = lagouType()
        # lagou.title = item['title']
        # lagou.description = item['description']
        # lagou.keywords = item['keywords']
        # lagou.url = item['url']
        # lagou.riqi = item['riqi']
        # lagou.save()
        item.save_to_es()       #执行items.py文件的save_to_es方法将数据写入elasticsearch搜索引擎
        return item

settings.py文件,注册pipelines

# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'adc.pipelines.AdcPipeline': 300,
}

main.py爬虫启动文件

#!/usr/bin/env python
# -*- coding:utf8 -*-

from scrapy.cmdline import execute  #导入执行scrapy命令方法
import sys
import os

sys.path.append(os.path.join(os.getcwd())) #给Python解释器,添加模块新路径 ,将main.py文件所在目录添加到Python解释器

execute(['scrapy', 'crawl', 'lagou', '--nolog'])  #执行scrapy命令

# execute(['scrapy', 'crawl', 'lagou'])  #执行scrapy命令

运行爬虫

image

写入elasticsearch(搜索引擎)情况

image

补充:elasticsearch-dsl  的 增删改查

#!/usr/bin/env python
# -*- coding:utf8 -*-
from datetime import datetime
from elasticsearch_dsl import DocType, Date, Nested, Boolean, \
    analyzer, InnerObjectWrapper, Completion, Keyword, Text, Integer

# 更多字段类型见第三百六十四节elasticsearch(搜索引擎)的mapping映射管理

from elasticsearch_dsl.connections import connections       # 导入连接elasticsearch(搜索引擎)服务器方法
connections.create_connection(hosts=['127.0.0.1'])

class lagouType(DocType):                                                   # 自定义一个类来继承DocType类
    # Text类型需要分词,所以需要知道中文分词器,ik_max_wordwei为中文分词器
    title = Text(analyzer="ik_max_word")                                    # 设置,字段名称=字段类型,Text为字符串类型并且可以分词建立倒排索引
    description = Text(analyzer="ik_max_word")
    keywords = Text(analyzer="ik_max_word")
    url = Keyword()                                                         # 设置,字段名称=字段类型,Keyword为普通字符串类型,不分词
    riqi = Date()                                                           # 设置,字段名称=字段类型,Date日期类型

    class Meta:                                                             # Meta是固定写法
        index = "lagou"                                                     # 设置索引名称(相当于数据库名称)
        doc_type = 'biao'                                                   # 设置表名称

if __name__ == "__main__":          # 判断在本代码文件执行才执行里面的方法,其他页面调用的则不执行里面的方法
    lagouType.init()                # 生成elasticsearch(搜索引擎)的索引,表,字段等信息

# 使用方法说明:
# 在要要操作elasticsearch(搜索引擎)的页面,导入此模块
# lagou = lagouType()           #实例化类
# lagou.title = '值'            #要写入字段=值
# lagou.description = '值'
# lagou.keywords = '值'
# lagou.url = '值'
# lagou.riqi = '值'
# lagou.save()                  #将数据写入elasticsearch(搜索引擎)

1新增数据

from adc.models.elasticsearch_orm import lagouType  #导入刚才配置的elasticsearch操作模块

     lagou = lagouType()                         # 实例化elasticsearch(搜索引擎对象)
     lagou._id = 1             #自定义ID,很重要,以后都是根据ID来操作

        lagou.title = self['title']                 # 字段名称=值
        lagou.description = self['description']
        lagou.keywords = self['keywords']
        lagou.url = self['url']
        lagou.riqi = self['riqi']
        lagou.save()                                # 将数据写入elasticsearch(搜索引擎对象)

2删除指定数据

from adc.models.elasticsearch_orm import lagouType  #导入刚才配置的elasticsearch操作模块
sousuo_orm = lagouType()                    # 实例化
sousuo_orm.get(id=1).delete()               # 删除id等于1的数据

3修改指定的数据

from adc.models.elasticsearch_orm import lagouType  #导入刚才配置的elasticsearch操作模块

sousuo_orm = lagouType()                           # 实例化
sousuo_orm.get(id=1).update(title='123456789')     # 修改id等于1的数据

以上全部使用elasticsearch-dsl模块

注意下面使用的原生elasticsearch模块

删除指定使用,就是相当于删除指定数据库

使用原生elasticsearch模块删除指定索引

from elasticsearch import Elasticsearch                                     # 导入原生的elasticsearch(搜索引擎)接口
client = Elasticsearch(hosts=settings.Elasticsearch_hosts)                  # 连接原生的elasticsearch

# 使用原生elasticsearch模块删除指定索引
#要做容错处理,如果索引不存在会报错
            try:
                client.indices.delete(index='jxiou_zuopin')
            except Exception as e:
                pass

原生查询

from elasticsearch import Elasticsearch                 # 导入原生的elasticsearch(搜索引擎)接口
            client = Elasticsearch(hosts=Elasticsearch_hosts)       # 连接原生的elasticsearch

response = client.search(                               # 原生的elasticsearch接口的search()方法,就是搜索,可以支持原生elasticsearch语句查询
                index="jxiou_zuopin",                               # 设置索引名称
                doc_type="zuopin",                                  # 设置表名称
                body={                                              # 书写elasticsearch语句
                    "query": {
                        "multi_match": {                            # multi_match查询
                            "query": sousuoci,                      # 查询关键词
                            "fields": ["title"]                     # 查询字段
                        }
                    },
                    "from": (page - 1) * tiaoshu,                   # 从第几条开始获取
                    "size": tiaoshu,                                # 获取多少条数据
                    "highlight": {                                  # 查询关键词高亮处理
                        "pre_tags": ['<span class="gaoliang">'],    # 高亮开始标签
                        "post_tags": ['</span>'],                   # 高亮结束标签
                        "fields": {                                 # 高亮设置
                            "title": {}                             # 高亮字段
                        }
                    }
                }
            )
            # 开始获取数据
            total_nums = response["hits"]["total"]                  # 获取查询结果的总条数

            hit_list = []                                           # 设置一个列表来储存搜索到的信息,返回给html页面

            for hit in response["hits"]["hits"]:                                # 循环查询到的结果
                hit_dict = {}                                                   # 设置一个字典来储存循环结果
                if "title" in hit["highlight"]:                                 # 判断title字段,如果高亮字段有类容
                    hit_dict["title"] = "".join(hit["highlight"]["title"])      # 获取高亮里的title
                else:
                    hit_dict["title"] = hit["_source"]["title"]                 # 否则获取不是高亮里的title

                hit_dict["id"] = hit["_source"]["nid"]                          # 获取返回nid

                # 加密样音地址
                hit_dict["yangsrc"] = jia_mi(str(hit["_source"]["yangsrc"]))    # 获取返回yangsrc

                hit_list.append(hit_dict)
查看原文

赞 0 收藏 0 评论 0

天降攻城狮 发布了文章 · 2020-11-20

45、elasticsearch(搜索引擎)的bool组合查询

百度云搜索,搜各种资料:http://www.lqkweb.com
搜网盘,搜各种资料:http://www.swpan.cn

bool查询说明

filter:[],字段的过滤,不参与打分
must:[],如果有多个查询,都必须满足【并且】
should:[],如果有多个查询,满足一个或者多个都匹配【或者】
must_not:[],相反查询词一个都不满足的就匹配【取反,非】

# bool查询
# 老版本的filtered已经被bool替换
#用 bool 包括 must should must_not filter 来完成
#格式如下:

#bool:{
#     "filter":[],      字段的过滤,不参与打分
#     "must":[],        如果有多个查询,都必须满足【并且】
#     "should":[],      如果有多个查询,满足一个或者多个都匹配【或者】
#     "must_not":[],    相反查询词一个都不满足的就匹配【取反,非】
#}

建立测试数据

#建立测试数据
POST jobbole/job/_bulk
{"index":{"_id":1}}
{"salary":10,"title":"python"}
{"index":{"_id":2}}
{"salary":20,"title":"Scrapy"}
{"index":{"_id":3}}
{"salary":30,"title":"Django"}
{"index":{"_id":4}}
{"salary":40,"title":"Elasticsearch"}

image

bool组合查询——最简单的filter过滤查询之term查询,相当于等于

过滤查询到salary字段等于20的数据

可以看出执行两个两个步骤,先查到所有数据,然后在查到的所有数据过滤查询到salary字段等于20的数据

# bool查询
# 老版本的filtered已经被bool替换
#用 bool 包括 must should must_not filter 来完成
#格式如下:

#bool:{
#     "filter":[],      字段的过滤,不参与打分
#     "must":[],        如果有多个查询,都必须满足
#     "should":[],      如果有多个查询,满足一个或者多个都匹配
#     "must_not":[],    相反查询词一个都不满足的就匹配
#}

#简单过滤查询
#最简单的filter过滤查询
#如果我们要查salary字段等于20的数据
GET jobbole/job/_search
{
  "query": {
    "bool": {                   #bool组合查询
      "must":{                  #如果有多个查询词,都必须满足
        "match_all":{}          #查询所有字段
      },
      "filter": {               #filter过滤
        "term": {               #term查询,不会将我们的搜索词进行分词,将搜索词完全匹配的查询
          "salary": 20          #查询salary字段值为20
        }
      }
    }
  }
}

#简单过滤查询
#最简单的filter过滤查询
#如果我们要查salary字段等于20的数据
GET jobbole/job/_search
{
  "query": {
    "bool": {
      "must":{
        "match_all":{}
      },
      "filter": {
        "term": {
          "salary": 20
        }
      }
    }
  }
}

 image

bool组合查询——最简单的filter过滤查询之terms查询,相当于或

过滤查询到salary字段等于10或20的数据

# bool查询
# 老版本的filtered已经被bool替换
#用 bool 包括 must should must_not filter 来完成
#格式如下:

#bool:{
#     "filter":[],      字段的过滤,不参与打分
#     "must":[],        如果有多个查询,都必须满足
#     "should":[],      如果有多个查询,满足一个或者多个都匹配
#     "must_not":[],    相反查询词一个都不满足的就匹配
#}

#简单过滤查询
#最简单的filter过滤查询
#如果我们要查salary字段等于20的数据
#过滤salary字段值为10或者20的数据
GET jobbole/job/_search
{
  "query": {
    "bool": {
      "must":{
        "match_all":{}
      },
      "filter": {
        "terms": {
          "salary":[10,20]
        }
      }
    }
  }
}

注意:filter过滤里也可以用其他基本查询的

_analyze测试查看分词器解析的结果
analyzer设置分词器类型ik_max_word精细化分词,ik_smart非精细化分词
text设置词

#_analyze测试查看分词器解析的结果
#analyzer设置分词器类型ik_max_word精细化分词,ik_smart非精细化分词
#text设置词
GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "Python网络开发工程师"
}

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "Python网络开发工程师"
}

image

bool组合查询——组合复杂查询1
查询salary字段等于20或者title字段等于python、salary字段不等于30、并且salary字段不等于10的数据

# bool查询
# 老版本的filtered已经被bool替换
#用 bool 包括 must should must_not filter 来完成
#格式如下:

#bool:{
#     "filter":[],      字段的过滤,不参与打分
#     "must":[],        如果有多个查询,都必须满足【并且】
#     "should":[],      如果有多个查询,满足一个或者多个都匹配【或者】
#     "must_not":[],    相反查询词一个都不满足的就匹配【取反,非】
#}

# 查询salary字段等于20或者title字段等于python、salary字段不等于30、并且salary字段不等于10的数据
GET jobbole/job/_search
{
  "query": {
    "bool": {
      "should": [
        {"term":{"salary":20}},
        {"term":{"title":"python"}}
      ],
      "must_not": [
        {"term": {"salary":30}},
        {"term": {"salary":10}}]
    }
  }
}

bool组合查询——组合复杂查询2
查询salary字段等于20或者title字段等于python、salary字段不等于30、并且salary字段不等于10的数据

# bool查询
# 老版本的filtered已经被bool替换
#用 bool 包括 must should must_not filter 来完成
#格式如下:

#bool:{
#     "filter":[],      字段的过滤,不参与打分
#     "must":[],        如果有多个查询,都必须满足【并且】
#     "should":[],      如果有多个查询,满足一个或者多个都匹配【或者】
#     "must_not":[],    相反查询词一个都不满足的就匹配【取反,非】
#}

# 查询title字段等于python、或者、(title字段等于elasticsearch并且salary等于30)的数据
GET jobbole/job/_search
{
  "query": {
    "bool": {
      "should":[
        {"term":{"title":"python"}},
        {"bool": {
          "must": [
            {"term": {"title":"elasticsearch"}},
            {"term":{"salary":30}}
          ]
        }}
      ]
    }
  }
}

bool组合查询——过滤空和非空

#建立数据
POST bbole/jo/_bulk
{"index":{"_id":"1"}}
{"tags":["search"]}
{"index":{"_id":"2"}}
{"tags":["search","python"]}
{"index":{"_id":"3"}}
{"other_field":["some data"]}
{"index":{"_id":"4"}}
{"tags":null}
{"index":{"_id":"1"}}
{"tags":["search",null]}

处理null空值的方法

获取tags字段,值不为空并且值不为null的数据

# bool查询
# 老版本的filtered已经被bool替换
#用 bool 包括 must should must_not filter 来完成
#格式如下:

#bool:{
#     "filter":[],      字段的过滤,不参与打分
#     "must":[],        如果有多个查询,都必须满足【并且】
#     "should":[],      如果有多个查询,满足一个或者多个都匹配【或者】
#     "must_not":[],    相反查询词一个都不满足的就匹配【取反,非】
#}

#处理null空值的方法
#获取tags字段,值不为空并且值不为null的数据
GET bbole/jo/_search
{
  "query": {
    "bool": {
      "filter": {
        "exists": {
          "field": "tags"
        }
      }
    }
  }
}

获取tags字段值为空或者为null的数据,如果数据没有tags字段也会获取

# bool查询
# 老版本的filtered已经被bool替换
#用 bool 包括 must should must_not filter 来完成
#格式如下:

#bool:{
#     "filter":[],      字段的过滤,不参与打分
#     "must":[],        如果有多个查询,都必须满足【并且】
#     "should":[],      如果有多个查询,满足一个或者多个都匹配【或者】
#     "must_not":[],    相反查询词一个都不满足的就匹配【取反,非】
#}

#获取tags字段值为空或者为null的数据,如果数据没有tags字段也会获取
GET bbole/jo/_search
{
  "query": {
    "bool": {
      "must_not": {
        "exists": {
          "field": "tags"
        }
      }
    }
  }
}
查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 15 次点赞
  • 获得 2 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 2 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • sqlflow

    SQLflow:基于python开发的分布式机器学习平台, 支持通过写sql的方式,运行spark, 机器学习算法, 爬虫

注册于 2017-03-05
个人主页被 1.8k 人浏览