KindEditor富文本编辑框和BeautifulSoup的基本使用
KindEditor富文本编辑框
1、进入官网
2、下载
- 官网下载:http://kindeditor.net/down.php
- 本地下载:https://files.cnblogs.com/files/wupeiqi/kindeditor_a5.zip
3、文件夹说明
├── asp asp示例 ├── asp.net asp.net示例 ├── attached 空文件夹,放置关联文件attached ├── examples HTML示例 ├── jsp java示例 ├── kindeditor-all-min.js 全部JS(压缩) ├── kindeditor-all.js 全部JS(未压缩) ├── kindeditor-min.js 仅KindEditor JS(压缩) ├── kindeditor.js 仅KindEditor JS(未压缩) ├── lang 支持语言 ├── license.txt License ├── php PHP示例 ├── plugins KindEditor内部使用的插件 └── themes KindEditor主题
4、基本使用
<textarea name="content" id="content"></textarea> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/plugins/kind-editor/kindeditor-all.js"></script> <script> $(function () { initKindEditor(); }); function initKindEditor() { var kind = KindEditor.create('#content', { width: '100%', // 文本框宽度(可以百分比或像素) height: '300px', // 文本框高度(只能像素) minWidth: 200, // 最小宽度(数字) minHeight: 400 // 最小高度(数字) }); } </script>
5、详细参数
http://kindeditor.net/docs/option.html
6、上传文件示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div> <h1>文章内容</h1> {{ request.POST.content|safe }} </div> <form method="POST"> <h1>请输入内容:</h1> {% csrf_token %} <div style="width: 500px; margin: 0 auto;"> <textarea name="content" id="content"></textarea> </div> <input type="submit" value="提交"/> </form> <script src="/static/jquery-1.12.4.js"></script> <script src="/static/plugins/kind-editor/kindeditor-all.js"></script> <script> $(function () { initKindEditor(); }); function initKindEditor() { var a = 'kind'; var kind = KindEditor.create('#content', { width: '100%', // 文本框宽度(可以百分比或像素) height: '300px', // 文本框高度(只能像素) minWidth: 200, // 最小宽度(数字) minHeight: 400, // 最小高度(数字) uploadJson: '/kind/upload_img/', extraFileUploadParams: { 'csrfmiddlewaretoken': '{{ csrf_token }}' }, fileManagerJson: '/kind/file_manager/', allowPreviewEmoticons: true, allowImageUpload: true }); } </script> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import os import json import time from django.shortcuts import render from django.shortcuts import HttpResponse def index(request): """ 首页 :param request: :return: """ return render(request, 'index.html') def upload_img(request): """ 文件上传 :param request: :return: """ dic = { 'error': 0, 'url': '/static/imgs/20130809170025.png', 'message': '错误了...' } return HttpResponse(json.dumps(dic)) def file_manager(request): """ 文件管理 :param request: :return: """ dic = {} root_path = '/Users/wupeiqi/PycharmProjects/editors/static/' static_root_path = '/static/' request_path = request.GET.get('path') if request_path: abs_current_dir_path = os.path.join(root_path, request_path) move_up_dir_path = os.path.dirname(request_path.rstrip('/')) dic['moveup_dir_path'] = move_up_dir_path + '/' if move_up_dir_path else move_up_dir_path else: abs_current_dir_path = root_path dic['moveup_dir_path'] = '' dic['current_dir_path'] = request_path dic['current_url'] = os.path.join(static_root_path, request_path) file_list = [] for item in os.listdir(abs_current_dir_path): abs_item_path = os.path.join(abs_current_dir_path, item) a, exts = os.path.splitext(item) is_dir = os.path.isdir(abs_item_path) if is_dir: temp = { 'is_dir': True, 'has_file': True, 'filesize': 0, 'dir_path': '', 'is_photo': False, 'filetype': '', 'filename': item, 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path))) } else: temp = { 'is_dir': False, 'has_file': False, 'filesize': os.stat(abs_item_path).st_size, 'dir_path': '', 'is_photo': True if exts.lower() in ['.jpg', '.png', '.jpeg'] else False, 'filetype': exts.lower().strip('.'), 'filename': item, 'datetime': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(os.path.getctime(abs_item_path))) } file_list.append(temp) dic['file_list'] = file_list return HttpResponse(json.dumps(dic))
7、BeautifulSoup的基本使用XSS过滤特殊标签
处理依赖
pip3 install beautifulsoup4 安装beautifulsoup
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/usr/bin/env python # -*- coding:utf-8 -*- from bs4 import BeautifulSoup class XSSFilter(object): __instance = None def __init__(self): # XSS白名单 self.valid_tags = { "font": ['color', 'size', 'face', 'style'], 'b': [], 'div': [], "span": [], "table": [ 'border', 'cellspacing', 'cellpadding' ], 'th': [ 'colspan', 'rowspan' ], 'td': [ 'colspan', 'rowspan' ], "a": ['href', 'target', 'name'], "img": ['src', 'alt', 'title'], 'p': [ 'align' ], "pre": ['class'], "hr": ['class'], 'strong': [] } @classmethod def instance(cls): if not cls.__instance: obj = cls() cls.__instance = obj return cls.__instance def process(self, content): soup = BeautifulSoup(content, 'lxml') # 遍历所有HTML标签 for tag in soup.find_all(recursive=True): # 判断标签名是否在白名单中 if tag.name not in self.valid_tags: tag.hidden = True if tag.name not in ['html', 'body']: tag.hidden = True tag.clear() continue # 当前标签的所有属性白名单 attr_rules = self.valid_tags[tag.name] keys = list(tag.attrs.keys()) for key in keys: if key not in attr_rules: del tag[key] return soup.renderContents() if __name__ == '__main__': html = """<p class="title"> <b>The Dormouse's story</b> </p> <p class="story"> <div name='root'> Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a> <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>; and they lived at the bottom of a well. <script>alert(123)</script> </div> </p> <p class="story">...</p>""" v = XSSFilter.instance().process(html) print(v)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/usr/bin/env python # -*- coding:utf-8 -*- from bs4 import BeautifulSoup class XSSFilter(object): __instance = None def __init__(self): # XSS白名单 self.valid_tags = { "font": ['color', 'size', 'face', 'style'], 'b': [], 'div': [], "span": [], "table": [ 'border', 'cellspacing', 'cellpadding' ], 'th': [ 'colspan', 'rowspan' ], 'td': [ 'colspan', 'rowspan' ], "a": ['href', 'target', 'name'], "img": ['src', 'alt', 'title'], 'p': [ 'align' ], "pre": ['class'], "hr": ['class'], 'strong': [] } def __new__(cls, *args, **kwargs): """ 单例模式 :param cls: :param args: :param kwargs: :return: """ if not cls.__instance: obj = object.__new__(cls, *args, **kwargs) cls.__instance = obj return cls.__instance def process(self, content): soup = BeautifulSoup(content, 'lxml') # 遍历所有HTML标签 for tag in soup.find_all(recursive=True): # 判断标签名是否在白名单中 if tag.name not in self.valid_tags: tag.hidden = True if tag.name not in ['html', 'body']: tag.hidden = True tag.clear() continue # 当前标签的所有属性白名单 attr_rules = self.valid_tags[tag.name] keys = list(tag.attrs.keys()) for key in keys: if key not in attr_rules: del tag[key] return soup.renderContents() if __name__ == '__main__': html = """<p class="title"> <b>The Dormouse's story</b> </p> <p class="story"> <div name='root'> Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister c1" style='color:red;background-color:green;' id="link1"><!-- Elsie --></a> <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tilffffffffffffflie</a>; and they lived at the bottom of a well. <script>alert(123)</script> </div> </p> <p class="story">...</p>""" obj = XSSFilter() v = obj.process(html) print(v) 基于__new__实现单例模式示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
content = """ <p id='i1'> <script>alert(123)</script> bingabcd </p> 把整个HTML转成对象与对象之间的关系了 <p id='i2'> <div> <p>bingabcd</p> </div> <img id='i3' src="/static/images\Koala.jpg" alt="" /> </p> """ from bs4 import BeautifulSoup # valid_tag = ['p','img','div'] valid_tag = {#白名单 'p':['class','id'], 'img':['src'], 'div':['class']#允许标签有什么属性 } soup = BeautifulSoup(content,'html.parser')#创建一个soup对象,,,#html.parser:是HTML内置的解析器 tags = soup.find_all()#遍历所有的标签 for tag in tags: if tag.name not in valid_tag:#如果标签不在valid_tag列表里 # tag.clear()#把script里的内容删掉了,但是不会删除script标签 tag.decompose()#删除内容和script标签 # print(tag.name) #p script p div p img if tag.attrs: for k in list(tag.attrs.keys()): if k not in valid_tag[tag.name]: del tag.attrs[k]# content_str = soup.decode() print(content_str) """ <p id="i1"> <script></script> bingabcd </p> 把整个HTML转成对象与对象之间的关系了 <p id="i2"> <div> <p>bingabcd</p> </div> <img alt="" id="i3" src="/static/images\Koala.jpg"/> </p> """ # v = soup.find(name='p',attrs={'id':'i2'}) # print(v) """ <p id="i2"> <img alt="" id="i3" src="/static/images\Koala.jpg"/> </p> """ #BeautifulSoup会根据这个解析器把这个HTML解析成一个一个的对象 # tag_img = soup.find(name='img')#找到HTML中第一个img标签 # print(tag_img)#<img alt="" src="/static/images\Koala.jpg"/> # tag_p = soup.find(name='p') # print(tag_p)# """ <p> <script>alert(123)</script> bingabcd </p> """ # v = soup.find_all(name='p') # print(v)#找到一个列表,一个标签对象一个元素 """ [<p id="i1"> <script>alert(123)</script> bingabcd </p>, <p id="i2"> <img alt="" id="i3" src="/static/images\Koala.jpg"/> </p>] """ # tag = soup.find(name='p') # sc = tag.find('script') # print(sc)#<script>alert(123)</script>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#防止XSS攻击的组件,就是利用BeautifulSoup过滤特殊字符 from bs4 import BeautifulSoup def xss(old): valid_tag = { 'p':['class','id'], 'img':['src'], 'div':['class'] }#设置一个白名单 soup = BeautifulSoup(old,'html.parser') tags = soup.find_all() for tag in tags: if tag.name not in valid_tag: tag.decompose()#删除特殊标签和特殊字符,比如script if tag.attrs: for k in list(tag.attrs.key()): if k not in valid_tag[tag.name]: del tag.attrs[k] content_str = soup.decode() return content_str
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from django.forms import Form from django.forms import fields from django.forms import widgets from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from app01 import models class ArticleForm(Form): title = fields.CharField(max_length=64)#标题 content = fields.CharField( widget=widgets.Textarea(attrs={'id':'i1'})#widget用于生成标签 ) def clean_content(self):#定义钩子函数 old = self.cleaned_data['content'] from utils.xss import xss#导入xss组件 return xss(old)#必须有返回值,具体原理看源码 # from bs4 import BeautifulSoup # soup = BeautifulSoup(old, 'html.parser') # 创建一个soup对象,,,#html.parser:是HTML内置的解析器 # valid_tag = { # 'p': ['class', 'id'], # 'img': ['src'], # 'div': ['class'] #设置白名单, 允许标签有什么属性 # } # tags = soup.find_all() # 遍历所有的标签 # for tag in tags: # if tag.name not in valid_tag: # 如果标签不在valid_tag列表里 # # tag.clear()#把script里的内容删掉了,但是不会删除script标签 # tag.decompose() # 删除内容和script标签 # # print(tag.name) #p script p div p img # if tag.attrs: # for k in list(tag.attrs.keys()): # if k not in valid_tag[tag.name]: # del tag.attrs[k] # # content_str = soup.decode() # return content_str
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def wangzhe(request): """ 发布文章 :param request: :return: """ if request.method == "GET": obj = ArticleForm() return render(request,'wangzhe.html',{'obj':obj}) else: obj = ArticleForm(request.POST) if obj.is_valid():#先验证正则表达式,然后执行钩子函数,执行完,再执行整体 # content = request.POST.get('content') content = obj.cleaned_data['content']#取到的content一定是替换完毕的content global CONTENT CONTENT = content print(content) return HttpResponse('ok')
用textarea变成富文本编辑框
代码示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def see(request): """ 查看用户发来的网页内容,see.html要做一下配置:{{ con|safe }} :param request: :return: """ return render(request,'see.html',{'con':CONTENT})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
CONTENT = "" def wangzhe(request): """ 发布文章 :param request: :return: """ if request.method == "GET": return render(request,'wangzhe.html') else: content = request.POST.get('content') global CONTENT CONTENT = content print(content) return HttpResponse('ok')
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form method="POST" action="/wangzhe.html"> {% csrf_token %} <div> <div>文章内容</div> <div> <textarea id="i1" name="content"></textarea> </div> </div> <input type="submit" value="提交" /> </form> <script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script> <script> KindEditor.create("#i1",{ width:"800px", height:"600px", resizeType:1 }) </script> </body> </html>
常用参数:
1.resizeType
2或1或0,2时可以拖动改变宽度和高度,1时只能改变高度,0时不能拖动。
- 数据类型: Int
- 默认值: 2
2.uploadJson
指定上传文件的服务器端程序。
- 数据类型: String
- 默认值: basePath + ‘php/upload_json.php’
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form method="POST" action="/wangzhe.html"> {% csrf_token %} <div> <div>文章内容</div> <div> <textarea id="i1" name="content"></textarea> </div> </div> <input type="submit" value="提交" /> </form> <script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script> <script> KindEditor.create("#i1",{ width:"1000px", height:"600px", resizeType:1, uploadJson:'/upload_img.html', extraFileUploadParams:{ "csrfmiddlewaretoken":"{{ csrf_token }}" } }) </script> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def upload_img(request): """ 接收用户发来的图片 :param request: :return: """ import os file_obj = request.FILES.get('imgFile') file_path = os.path.join('static/images',file_obj.name) with open(file_path,'wb') as f: for chunk in file_obj.chunks(): f.write(chunk) dic = { 'error': 0, 'url': '/'+file_path, # 'url': '/static/imgs/20130809170025.png', 'message': '错误了...' } import json return HttpResponse(json.dumps(dic)) # print(request.POST,request.FILES)#<QueryDict: {'csrfmiddlewaretoken': ['iGwBmAXvo9mc9cbfzYH4uz5g5UgWVObyG2zGuxOBUO3dWjcLoXq0UJHWrExUuDMl'], 'localUrl': ['C:\\fakepath\\Koala.jpg']}> <MultiValueDict: {'imgFile': [<InMemoryUploadedFile: Koala.jpg (image/jpeg)>]}>
你现在所遭遇的每一个不幸,都来自一个不肯努力的曾经。大数据SRE(运维开发)学习交流群239963844
posted on 2017-07-21 17:20 bigdata_devops 阅读(333) 评论(0) 编辑 收藏 举报