上一篇簡單說了下 ES 在 Python 的增刪改查,手把手教你使用Flask搭建ES搜尋引擎(預備篇)。
現在正式進入主題:開始使用 Flask 搭建 ES 搜索。
import osDB_USERNAME = 'root'DB_PASSWORD = None DB_HOST = '127.0.0.1'DB_PORT = '3306'DB_NAME = 'flask_es'
class Config: SECRET_KEY ="隨機字符" SQLALCHEMY_COMMIT_ON_TEARDOWN = True SQLALCHEMY_TRACK_MODIFICATIONS = True DEBUG = True SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://%s:%s@%s:%s/%s' % (DB_USERNAME, DB_PASSWORD,DB_HOST, DB_PORT, DB_NAME)
MAIL_SERVER = 'smtp.qq.com' MAIL_POST = 465 MAIL_USERNAME = '3417947630@qq.com' MAIL_PASSWORD = '郵箱授權碼' FLASK_MAIL_SUBJECT_PREFIX='M_KEPLER' FLASK_MAIL_SENDER=MAIL_USERNAME MAIL_USE_TLS = False MAIL_DEBUG = False ENABLE_THREADS=True這是一份相對簡單的 Flask Config 文件,當然對於當前項目來說資料庫的連接不是必要的,我只是用 Mysql 來作為輔助用,小夥伴們沒有必要配置連接資料庫,有 ES 足以。然後郵箱通知這個看個人需求
日誌模塊在工程應用中是必不可少的一環,根據不同的生產環境來輸出日誌文件是非常有必要的。用句江湖上的話來說: "如果沒有日誌文件,你死都不知道怎麼死的 "import osimport loggingimport logging.config as log_confimport datetimeimport coloredlogs
coloredlogs.DEFAULT_FIELD_STYLES = {'asctime': {'color': 'green'}, 'hostname': {'color': 'magenta'}, 'levelname': {'color': 'magenta', 'bold': False}, 'name': {'color': 'green'}}
log_dir = os.path.dirname(os.path.dirname(__file__)) + '/logs'if not os.path.exists(log_dir): os.mkdir(log_dir)today = datetime.datetime.now().strftime("%Y-%m-%d")
log_path = os.path.join(log_dir, today + ".log")
log_config = { 'version': 1.0,
'formatters': { 'colored_console': { 'format': "%(asctime)s - %(name)s - %(levelname)s - %(message)s", 'datefmt': '%H:%M:%S' }, 'detail': { 'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s', 'datefmt': "%Y-%m-%d %H:%M:%S" }, },
'handlers': { 'console': { 'class': 'logging.StreamHandler', 'level': 'DEBUG', 'formatter': 'colored_console' }, 'file': { 'class': 'logging.handlers.RotatingFileHandler', 'maxBytes': 1024 * 1024 * 1024, 'backupCount': 1, 'filename': log_path, 'level': 'INFO', 'formatter': 'detail', 'encoding': 'utf-8', }, },
'loggers': { 'logger': { 'handlers': ['console'], 'level': 'DEBUG', },
}}
log_conf.dictConfig(log_config)log_v = logging.getLogger('log')
coloredlogs.install(level='DEBUG', logger=log_v)
這裡準備好了一份我常用的日誌配置文件,可作為常用的日誌格式,直接調用即可,根據不同的等級來輸出到終端或 .log 文件,拿走不謝。
對於 Flask 項目而言, 藍圖和路由會讓整個項目更具觀賞性(當然指的是代碼的閱讀)。
這裡我採用兩個分支來作為數據支撐,一個是 Math 入口,另一個是 Baike 入口,數據的來源是基於上一篇的百度百科爬蟲所得,根據 深度優先 的爬取方式抓取後放入 ES 中。from flask import Flaskfrom flask_sqlalchemy import SQLAlchemyfrom app.config.config import Configfrom flask_mail import Mailfrom flask_wtf.csrf import CSRFProtect
app = Flask(__name__,template_folder='templates',static_folder='static')app.config.from_object(Config)
db = SQLAlchemy(app)db.init_app(app)
csrf = CSRFProtect(app)mail = Mail(app)from app.home.baike import baike as baike_blueprintfrom app.home.math import math as math_blueprintfrom app.home.home import home as home_blueprint
app.register_blueprint(home_blueprint)app.register_blueprint(math_blueprint,url_prefix="/math")app.register_blueprint(baike_blueprint,url_prefix="/baike")from flask import Blueprintbaike = Blueprint("baike", __name__)from app.home.baike import viewsfrom flask import Blueprintmath = Blueprint("math", __name__)
from app.home.math import viewsimport osfrom flask_paginate import Pagination, get_page_parameterfrom app.Logger.logger import log_vfrom app.elasticsearchClass import elasticSearch
from app.home.forms import SearchForm
from app.home.baike import baikefrom flask import request, jsonify, render_template, redirect
baike_es = elasticSearch(index_type="baike_data",index_name="baike")
@baike.route("/")def index(): searchForm = SearchForm() return render_template('baike/index.html', searchForm=searchForm)
@baike.route("/search", methods=['GET', 'POST'])def baikeSearch(): search_key = request.args.get("b", default=None) if search_key: searchForm = SearchForm() log_v.error("[+] Search Keyword: " + search_key) match_data = baike_es.search(search_key,count=30)
PER_PAGE = 10 page = request.args.get(get_page_parameter(), type=int, default=1) start = (page - 1) * PER_PAGE end = start + PER_PAGE total = 30 print("最大數據總量:", total) pagination = Pagination(page=page, start=start, end=end, total=total) context = { 'match_data': match_data["hits"]["hits"][start:end], 'pagination': pagination, 'uid_link': "/baike/" } return render_template('data.html', q=search_key, searchForm=searchForm, **context) return redirect('home.index')
@baike.route('/<uid>')def baikeSd(uid): base_path = os.path.abspath('app/templates/s_d/') old_file = os.listdir(base_path)[0] old_path = os.path.join(base_path, old_file) file_path = os.path.abspath('app/templates/s_d/{}.html'.format(uid)) if not os.path.exists(file_path): log_v.debug("[-] File does not exist, renaming !!!") os.rename(old_path, file_path) match_data = baike_es.id_get_doc(uid=uid) return render_template('s_d/{}.html'.format(uid), match_data=match_data)
可以看到我們成功的將 elasticSearch 類初始化並且進行了數據搜索。我們使用了 Flask 的分頁插件進行分頁並進行了單頁數量的限制,根據 Uid 來跳轉到詳情頁中。@baike.route('/<uid>')def baikeSd(uid): base_path = os.path.abspath('app/templates/s_d/') old_file = os.listdir(base_path)[0] old_path = os.path.join(base_path, old_file) file_path = os.path.abspath('app/templates/s_d/{}.html'.format(uid)) if not os.path.exists(file_path): log_v.debug("[-] File does not exist, renaming !!!") os.rename(old_path, file_path) match_data = baike_es.id_get_doc(uid=uid) return render_template('s_d/{}.html'.format(uid), match_data=match_data)
以此來保證存放詳情頁面的模板中始終只保留一個 html 文件。
一如既往的採用 flask_script 作為項目的啟動方案,確實方便。from app import appfrom flask_script import Manager, Server
manage = Manager(app)
manage.add_command("runserver", Server(use_debugger=True))
if __name__ == "__main__": manage.run()python manage.py runserver就可以啟動項目,默認埠 5000,訪問 http://127.0.0.1:5000import multiprocessing
from gevent import monkeymonkey.patch_all()
workers = multiprocessing.cpu_count() * 2 + 1
debug = True
reload = True
loglevel = 'debug'
threads = 2
bind = '0.0.0.0:5001'
daemon = 'false'
worker_class = 'gevent'
worker_connections = 2000
pidfile = 'log/gunicorn.pid'logfile = 'log/debug.log'
accesslog = 'log/gunicorn_acess.log'errorlog = 'log/gunicorn_error.log'gunicorn -c gconfig.py manage:apphttps://github.com/GZKY-PY/Flask-ES- 合作、交流、轉載請添加微信 moonhmily1 -