首页
AI导航
美图
服务
付费
树洞
留言
云主机
推荐
邻居
更多
我的书单
我的足迹
罗盘时钟
圈小猫
工作打分
本站统计
版本历史
推荐
txt阅读器
主机监控
M商城
网址导航
在线工具
证件照制作
Search
1
docker和docker-compose一键安装脚本
824 阅读
2
docker下运行grafana和grafana Image Renderer
664 阅读
3
grafana的Dashboard面板添加阈值报警
632 阅读
4
WooCommerce对接第三方支付插件开发
503 阅读
5
基于docker的部署fecmall开源电商系统
442 阅读
ChatGPT
虚拟化
数据库
运维
基础知识
监控预警
数据展示
运维工具
web安全
系统服务
开发
python
php
java
shell
go
html5
项目
博客
电商
工具
娱乐
影视
读书
读书笔记
综合
VPS报告
规范文档
知识总结
经验分享
关于本站
登录
Search
标签搜索
python
django
电商平台
运维工具
Joe主题
docker
zabbix
蓝鲸智云
运维
监控
typecho
grafana
wordpress
运维知识
mysql
php
elk
nginx
web安全
VPS测试
IT不难
累计撰写
245
篇文章
累计收到
209
条评论
首页
栏目
ChatGPT
虚拟化
数据库
运维
基础知识
监控预警
数据展示
运维工具
web安全
系统服务
开发
python
php
java
shell
go
html5
项目
博客
电商
工具
娱乐
影视
读书
读书笔记
综合
VPS报告
规范文档
知识总结
经验分享
关于本站
页面
美图
服务
留言
邻居
我的足迹
本站统计
版本历史
推荐
M商城
网址导航
搜索到
13
篇与
的结果
2023-02-21
通过Django管理周期性任务-feapder爬虫
前言{callout color="#f0ad4e"}一开始感兴趣的信息比较少,直接用crontab启动就满足要求了。后台爬虫越来越多,有的爬虫早就失效了,也没发现。用了 feapder 作者的管理系统 feaplat 。系统功能很全面,但是随着功能的完善,价格也越来越贵。个人实在承担不起,只能花时间自己搞一个简易版的了。{/callout}{message type="success" content="我自己感兴趣的信息收集回来通过Django管理,把爬虫功能顺便集成到里面了。"/}{card-default label="项目" width="75%"}{/card-default}功能实现模型设计隐藏内容,请前往内页查看详情后台管理{message type="success" content="默认就能用,通过admin.py可以自定义需要显示的内容。"/}# Register your models here. class SpiderInfofAdmin(admin.ModelAdmin): #后台展示字段 list_display = ['id', 'sname', 'filepath', 'workpath', 'image', 'addtime', 'snote'] #搜索字段 search_fields = ['sname'] class SpiderTaskAdmin(admin.ModelAdmin): #后台展示字段 list_display = ['id', 'sname', 'snote', 'addtime', 'runtime_show', 'total', 'repeat', 'valid', 'status_colored', 'operate'] #过滤字段 list_filter = ["status"] #搜索字段 search_fields = ['sname'] #只读字段 readonly_fields = ['id', 'addtime', 'runtime', 'total', 'repeat', 'valid', 'status'] #自定义动作 actions = ['schedule_switch']{card-default label="任务界面" width="75%"}{/card-default}异步任务{message type="success" content="异步任务和周期性任务通过celery实现"/}项目主settings.py添加内容INSTALLED_APPS = [ # 略 'django_celery_beat', #略 ] # Celery配置 # BROKER和BACKEND配置,这里用了本地的redis,其中1和2表示分别用redis的第一个和第二个db CELERY_BROKER_URL = 'redis://172.17.0.10:6379/1' CELERY_RESULT_BACKEND = 'redis://172.17.0.10:6379/2' # CELERY 时间 CELERY_TIMEZONE = TIME_ZONE DJANGO_CELERY_BEAT_TZ_AWARE = False #指定任务接收的内容序列化类型 CELERY_ACCEPT_CONTENT = ['application/json'] #任务和任务结果序列化方式 CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' #超过时间 CELERY_TASK_RESULT_EXPIRES = 12 * 30 #是否压缩 CELERY_MESSAGE_COMPRESSION = 'zlib' #并发数默 CELERYD_CONCURRENCY = 2 #celery worker 每次去redis取任务的数量认已CPU数量定 CELERYD_PREFETCH_MULTIPLIER = 2 #每个worker最多执行3个任务就摧毁,避免内存泄漏 CELERYD_MAX_TASKS_PER_CHILD = 3 #可以防止死锁 CELERYD_FORCE_EXECV = True #celery 关闭UTC时区 CELERY_ENABLE_UTC = False #celery 并发数设置,最多可以有20个任务同时运行 CELERYD_CONCURRENCY = 20 CELERYD_MAX_TASKS_PER_CHILD = 4 #celery开启数据库调度器,数据库修改后即时生效 CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler' #解决告警 DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'2.同目录下新增celery.pyimport os from celery import Celery,platforms from django.conf import settings # 设置环境变量 os.environ.setdefault('DJANGO_SETTINGS_MODULE','taskmon.settings') # 实例化 app = Celery('taskmon') # namespace='CELERY'作用是允许你在Django配置文件中对Celery进行配置 # 但所有Celery配置项必须以CELERY开头,防止冲突 app.config_from_object('django.conf:settings', namespace='CELERY') # 自动从Django的已注册app中发现任务 app.autodiscover_tasks() #允许root 用户运行celery platforms.C_FORCE_ROOT = True # 一个测试任务 @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))3.项目目录下tasks.py#操作docker from celery import shared_task from .utils import process_start @shared_task def sync_start_process(sname): """ 异步执行任务 """ process_start(sname)4.celery启动#任务调度 celery multi start worker -A taskmon -l info --logfile=/logs/celery_worker.log celery -A taskmon beat -l info --logfile=/logs/celery_beat.log{card-default label="运行日志" width="75%"}{/card-default}添加周期任务隐藏内容,请前往内页查看详情删除周期任务def remove_celery_task(sid): """ 删除计划任务 sid : 爬虫任务ID """ cname = str(sid) + '-' + '周期任务' #添加计划任务 with transaction.atomic(): save_id = transaction.savepoint() try: _p = PeriodicTask.objects.get(name=cname) if _p: _p.delete() print('{}删除计划任务成功'.format(cname)) return True except Exception as e: transaction.savepoint_rollback(save_id) print('{}删除计划任务失败,错误原因:'.format(cname) + str(e)) return False任务启动函数def process_start(sname): """ 执行任务并处理返回结果 sname: 任务名 cinfo: 启动容器所需的信息 """ con_name = 'spider_{}_1'.format(sname) containers = get_containers({"name":con_name}) if containers: print('有相同任务运行中...|{}|{}'.format(con_name, datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))) return False #查询库 spider_task = SpiderTask.objects.get(sname=sname) #构建docker启动信息 cinfo = { "name": con_name, "command": spider_task.command, #宿主机目录 "volumes": ['/opt/project/taskmon/myapp/spider/{}:{}'.format(spider_task.sinfo.filepath, spider_task.sinfo.workpath),], "shm_size": spider_task.sinfo.shm, "image": spider_task.sinfo.image, "working_dir": spider_task.sinfo.workpath, "remove": False, } #启动容器 result = run_container(cinfo) if result: #日志文件 log_path='/logs/{}_{}.log'.format(con_name, datetime.datetime.now().strftime("%H-%M-%S-%Y-%m-%d")) #保存日志 with open(log_path, 'wb') as fw: fw.write(result) #采集结果 d_nums = process_result(result) #更新 spider_task.total = d_nums[0] spider_task.repeat = d_nums[1] spider_task.valid = d_nums[2] spider_task.logpath = log_path spider_task.save() print('任务执行...|{}|{}'.format(con_name, datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")))容器启动函数def run_container(ddict): """ 运行容器 """ #print(ddict) container = client.containers.run( image=ddict['image'], name=ddict['name'], shm_size=ddict['shm_size'], volumes=ddict['volumes'], working_dir=ddict['working_dir'], remove=ddict['remove'], detach=True, command=ddict['command'] ) container.wait() result = container.logs() container.remove() return result结果处理函数{message type="success" content="统计每次处理收到的结果"/}def process_result(result): """ 处理返回结果 """ a = 0 b = 0 c = 0 lines = str(result, encoding = "utf-8").split('\n') for line in lines: if '待入库数据' in line: tmp_s = line.split('|')[3] nums = tmp_s.split(' ') a += int(nums[2]) b += int(nums[5]) c += int(nums[7]) return (a, b, c){card-default label="效果" width="80%"}{/card-default}相关文章Django后台展示(一) Django后台展示(二)FAQ自动添加周期任务后,启动报错{card-default label="报错" width="85%"}{/card-default}{message type="success" content="解决办法: 写入数据库django_celery_beat_periodictask表的args字段需要双引号括起来。"/}
2023年02月21日
20 阅读
0 评论
0 点赞
2023-02-21
Django后台展示(二)
说明{callout color="#f0ad4e"}需要通过后台直接周期任务运行的结果日志,这样就不需要每次登录服务器。{/callout}{card-default label="效果" width="80%"}{/card-default}代码接口代码def getlog(request): ''' 日志查看 ''' if request.method == 'GET': logpath = request.GET.get('path', default='') content = '无日志' if os.path.exists(logpath): with open(logpath, 'r') as f: content = f.read() return render(request, 'logview.html', {'logpath': logpath, 'content': content})模板文件{% block content %} <h2>{{ logpath }}</h2> <div style="background-color: black;color: azure" > <span style="font-size: 10px"><pre>{{ content }} </pre> </div> {% endblock %}
2023年02月21日
14 阅读
0 评论
0 点赞
2023-02-21
Django后台展示(一)
说明{callout color="#f0ad4e"}Django用的比较多,最近自己的taskmonitor项目添加了采集爬虫相关的内容。总结一下,其中的代码片段。{/callout}{card-default label="效果" width="85%"}{/card-default}代码片段改变状态颜色 @admin.display(description='调度状态', ordering='status') def status_colored(self, obj): colors = { 0: 'red', 1: 'green' } return format_html( '<p style="color:{};">{}</p>', colors[obj.status], STATUS_CHOICE[obj.status], )重写保存函数 #重写保存函数 def save_model(self, request, obj, form, change): #新增默认不启动计划任务,测试后调整调度状态 if change: if len(obj.crond.split(' ')) != 5: obj.status = 0 else: obj.status = 0 #保存 super(SpiderTaskAdmin, self).save_model(request, obj, form, change)任务调度开关 def schedule_switch(self, request, queryset): """ 任务调度开关 """ for obj in queryset: c_len= len(obj.crond.strip().split()) if c_len == 5: if obj.status == 1: obj.status = 0 res = remove_celery_task(obj.id) else: print(obj.status) obj.status = 1 res = add_celery_task(obj.id) if res: obj.save()自定义操作操作列设置 # 定义一些操作示例 @admin.display(description='手动操作', ordering='sname') def operate(self, obj): #容器名称 con_name = 'spider_{}_1'.format(obj.sname) #获取容器 containers = get_containers({"name":con_name}) #操作容器 if containers: uparas = '{}-正在运行...'.format(con_name) up_btn = "<button onclick='self.parent.app.$msgbox(\"{u_d}\")' class='el-button el-button--info el-button--small'>启动</button>" dparas = "'{}','{}'".format(obj.sname, '0') down_btn = "<button onclick='javascript:spidermanager({d_d})' class='el-button el-button--danger el-button--small'>停止</button>" else: uparas = "'{}','{}'".format(obj.sname, '1') up_btn = "<button onclick='javascript:spidermanager({u_d})' class='el-button el-button--success el-button--small'>启动</button>" dparas = '{}-不存在'.format(con_name) down_btn = "<button onclick='self.parent.app.$msgbox(\"{d_d}\")' class='el-button el-button--info el-button--small'>停止</button>" # 查看日志 if obj.logpath: log_data = {'name':'{}|日志'.format(con_name), 'icon': 'fas fa-user-tie', 'url':'/spider/getlog/?path={}'.format(obj.logpath)} log_btn = "<button onclick='self.parent.app.openTab({l_d})' class='el-button el-button--primary el-button--small'>最新日志</button>" else: log_data = '{}-最新日志无'.format(con_name) log_btn = "<button onclick='self.parent.app.$msgbox(\"{l_d}\")' class='el-button el-button--info el-button--small'>最新日志</button>" #拼接并返回 html_str = "<div>" + up_btn + down_btn + log_btn + "</div>" return format_html(html_str, u_d=uparas, d_d=dparas, l_d=log_data)自定义js class Media: js = ('js/common.js',)js代码//spidermanager函数传入cname和opera两个参数 //cname 容器名 //opera 启动、关闭 function spidermanager(sname, opera){ var url = "/spider/manager/?sname="+sname+"&opera="+String(opera); var Http = new XMLHttpRequest(); Http.open("GET", url, false); Http.send(null); console.log(Http.responseText); }接口代码def manager(request): ''' 容器操作 ''' if request.method == 'GET': opera = request.GET.get('opera', default='2') sname = request.GET.get('sname', default='') if not sname or opera == '2': messages.error(request, '参数非法') else: con_name = 'spider_{}_1'.format(sname) containers = get_containers({"name":con_name}) if containers: if opera == '1': messages.info(request, '容器:{} |已运行...'.format(con_name)) else: for container in containers: container.stop() messages.success(request, '容器:{} |成功停止...'.format(con_name)) else: if opera == '1': sync_start_process.delay(sname) messages.success(request, '容器:{} |成功启动...'.format(con_name)) else: messages.info(request, '容器:{} |未运行...'.format(con_name)) return HttpResponse('ok')
2023年02月21日
13 阅读
0 评论
0 点赞
2022-09-21
Django框架打印日志配置
setting.py{message type="success" content="主项目配置文件设置"/}# 日志配置 LOGGING = { 'version': 1, #使用的python内置的logging模块,那么python可能会对它进行升级,所以需要写一个版本号,目前就是1版本 'disable_existing_loggers': False, #是否去掉目前项目中其他地方中以及使用的日志功能,但是将来我们可能会引入第三方的模块,里面可能内置了日志功能,所以尽量不要关闭。 'formatters': { #日志记录格式 'standard': { #levelname等级,asctime记录时间,module表示日志发生的文件名称,lineno行号,message错误信息 'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s' }, 'simple': { 'format': '%(levelname)s %(module)s %(lineno)d %(message)s' }, }, 'filters': { #过滤器:可以对日志进行输出时的过滤用的 'require_debug_true': { #在debug=True下产生的一些日志信息,要不要记录日志,需要的话就在handlers中加上这个过滤器,不需要就不加 '()': 'django.utils.log.RequireDebugTrue', }, 'require_debug_false': { #和上面相反 '()': 'django.utils.log.RequireDebugFalse', }, }, 'handlers': { #日志处理方式,日志实例,向哪里输出 'console': { #在控制台输出时的实例 'level': 'DEBUG', #日志等级;debug是最低等级,那么只要比它高等级的信息都会被记录 'filters': ['require_debug_true'], #在debug=True下才会打印在控制台 'class': 'logging.StreamHandler', #使用的python的logging模块中的StreamHandler来进行输出 'formatter': 'simple' }, 'file': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', # 日志位置,日志文件名,日志保存目录必须手动创建 'filename': os.path.join(os.path.dirname('/var/log/promon/'), "promon.log"), #注意,你的文件应该有读写权限。 # 日志文件的最大值,这里我们设置300M 'maxBytes': 300 * 1024 * 1024, # B # 日志文件的数量,设置最大日志数量为10 'backupCount': 10, # 日志格式:详细格式 'formatter': 'standard', 'encoding': 'utf-8', # 设置默认编码,否则打印出来汉字乱码 }, }, # 日志对象 'loggers': { 'django': { #和django结合起来使用,将django中之前的日志输出内容的时候,按照我们的日志配置进行输出, 'handlers': ['console', 'file'], #将来项目上线,把console去掉 'propagate': True, #冒泡:是否将日志信息记录冒泡给其他的日志处理系统,工作中都是True,不然django这个日志系统捕获到日志信息之后,其他模块中可能也有日志记录功能的模块,就获取不到这个日志信息了 }, } }引用#日志 import logging logger = logging.getLogger('django')打印日志logger.warn('warn') logger.warn('info') logger.warn('error')
2022年09月21日
28 阅读
0 评论
1 点赞
2022-08-12
百度分享链接可用性批量检查
前言{callout color="#f0ad4e"}前一段时间收集了一些百度分享的资源,在整理的过程中过发现好多都失效了。写一个模块,自动检查是否可用。不可用的打一个标记,然后就不处理了。{/callout}相关文章: wordpress直接通过数据库导出文章标题、分类信息到xls表格实现{message type="success" content="Django 添加自定义动作,并编写检查函数"/}class ResourceAdmin(admin.ModelAdmin): """ 管理类 """ ... #自定义动作 actions = ['check_url'] def check_url(self, request, queryset): """ 检查分享链接有效性,并更新状态 """ for obj in queryset: tmp_li = obj.rurl.split('"') if len(tmp_li) > 11: if not check_url_available(tmp_li[7]): obj.rstatus = 2 obj.save() ...{message type="success" content="检查可用性函数"/}import re import time import random from feapder import Request def check_url_available(link): """ 检查百度分享是否失效 """ if not re.match(r'^https?:/{2}\w.+$', link): return False res = Request(link, render=False).get_response() count = 0 for k in res.bs4().find_all('div', class_='share-error-left'): count += 1 if count > 0: return False time.sleep(random.randint(1, 5)) return True
2022年08月12日
25 阅读
2 评论
1 点赞
2022-08-01
利用Django和feapder定制开发商品价格监控系统
前言{message type="success" content="最近想升级一下电脑硬件,又不是很了解当前电脑硬件的价格趋势。登录一些比价网站,商品太多了,找起来好麻烦。一些高级的功能还要收费。干脆自己写一个吧。想要的功能很简单:"/}{callout color="#f0ad4e"}添加感兴趣的商品ID,自动获取商品信息添加是否获取价格和当前优惠活动开关,若开启,每天获取一次当前商品价格和活动将获取的商品价格可视化展示{/callout}{card-default label="数据管理" width="95%"}{/card-default}{card-describe title="主要技术"}Django:作为基础框架,用来管理商品信息和价格数据feapder:用来采集商品价格数据并写入数据库simpleui:Django后台ui美化pyecharts:数据可视化展示{/card-describe}Django 平台models.py{message type="success" content="数据模型设计"/}from django.db import models # Create your models here. #状态 NO = 0 YES = 1 STATUS_CHOICE = { NO: '否', YES: '是', } class MallInfo(models.Model): '''商品信息''' sid = models.AutoField(primary_key=True, verbose_name='编号') status_choices = ((k, v) for k,v in STATUS_CHOICE.items()) sku = models.CharField(max_length=32, verbose_name='商品id') name = models.CharField(max_length=255, verbose_name='商品名', default='xxxx') src = models.CharField(max_length=20, verbose_name='来源', default='jd') url = models.CharField(max_length=255, verbose_name='链接', default='xxxx') addtime = models.DateTimeField(auto_now_add=True, verbose_name='添加时间') status = models.SmallIntegerField(default=NO, choices=status_choices, verbose_name='是否监控') # admin显示订单的id def __str__(self): return self.name class Meta: db_table = 'mall_info' verbose_name = '商品信息' verbose_name_plural = '商品信息' class PriceInfo(models.Model): '''历史价格''' sid = models.AutoField(primary_key=True, verbose_name='编号') sku = models.CharField(max_length=32, verbose_name='商品id') price = models.IntegerField(default=0, verbose_name='价格') note = models.CharField(max_length=255, default='无', verbose_name='活动') addtime = models.DateTimeField(auto_now_add=True, verbose_name='日期') # admin显示订单的id def __str__(self): return str(self.sid) class Meta: db_table = 'price_info' verbose_name = '商品价格' verbose_name_plural = '商品价格'admin.py{message type="success" content="后台数据展示"/}from django.contrib import admin from mall.models import MallInfo, PriceInfo from django.utils.html import format_html from bs4 import BeautifulSoup import requests # Register your models here. class MallInfoAdmin(admin.ModelAdmin): list_display = ['sku', 'name_and_url', 'show_history', 'src', 'addtime', 'status'] #进入编辑的字段 list_display_links = ['sku'] #只读字段 readonly_fields = ['url'] #标题带链接 def name_and_url(self, obj): return format_html("<a href='{url}' target='_blank'>{name}</a>", url=obj.url, name=obj.name) #字段描述 name_and_url.short_description = "商品名称" def show_history(self, obj): return format_html("<a href='/mall/echarts/?sku={sku}' target='_blank'>历史价格</a>", sku=obj.sku) show_history.short_description = "历史价格" #重写保存函数 def save_model(self, request, obj, form, change): def get_name_by_sku(): """根据sku获取名称""" url = 'https://item.jd.com/%s.html' % (obj.sku) try: resp = requests.get(url) soup = BeautifulSoup(resp.text, 'html.parser') name = soup.find(class_='sku-name') return name.text.strip() except Exception as e: print(e) return '0000' if not change: # 新增记录 obj.name = get_name_by_sku() obj.url = 'https://item.jd.com/%s.html' % (obj.sku) super(MallInfoAdmin, self).save_model(request, obj, form, change) class PriceInfoAdmin(admin.ModelAdmin): list_display = ['sku', 'price', 'note', 'addtime'] #只读字段 readonly_fields = ['sku', 'price', 'note', 'addtime'] admin.site.register(MallInfo, MallInfoAdmin) #admin.site.register(PriceInfo, PriceInfoAdmin){card-default label="商品编辑" width="95%"}{/card-default}views.py{message type="success" content="api接口和页面视图函数"/}from django.shortcuts import render from mall.models import MallInfo, PriceInfo from django.http import HttpResponse from django.template import Template, Context from rest_framework.views import APIView import json from pyecharts.charts import Bar from pyecharts import options as opts from .utils import * # Create your views here. JsonResponse = json_response JsonError = json_error def get_skus_need_monitor(request): """ 获取需要监控价格的商品列表 """ resp = {} skus = [] malls = MallInfo.objects.filter(status=1) if malls: for mall in malls: skus.append(mall.sku) return JsonResponse(skus) def bar_base(sku) -> Bar: """ 图表制作 """ x_date = [] y_price = [] mall = MallInfo.objects.filter(sku=sku).last() prices = PriceInfo.objects.filter(sku=sku).order_by('-sid')[:15] if prices: for price in prices[::-1]: x_date.append(price.addtime.strftime('%Y-%m-%d')) y_price.append(price.price) b = (Bar() .add_xaxis(x_date) .add_yaxis("sku:{}".format(sku), y_price, ) .set_global_opts(title_opts=opts.TitleOpts(title="商品历史价格曲线", subtitle="{}".format(mall.name)), xaxis_opts=opts.AxisOpts(axislabel_opts={"interval":"0","rotate":45}), datazoom_opts=[opts.DataZoomOpts(), opts.DataZoomOpts(type_="inside")], ) .dump_options_with_quotes() ) return b class get_mall_price_api(APIView): """ 历史价格获取价格数据api """ def get(self, request, *args, **kwargs): sku = request.GET.get("sku") return JsonResponse(json.loads(bar_base(sku))) class echartsView(APIView): """ 历史价格渲染页面 """ def get(self, request, *args, **kwargs): sku = request.GET.get("sku") p_max = PriceInfo.objects.filter(sku=sku).order_by('-price')[0].price p_min = PriceInfo.objects.filter(sku=sku).order_by('price')[0].price p_now = PriceInfo.objects.filter(sku=sku).last().price n_note = PriceInfo.objects.filter(sku=sku).last().note #多重查询条件 l_note = PriceInfo.objects.filter(sku=sku).exclude(note='无').order_by('-sid') t = Template(open("./templates/echarts.html").read()) c = Context({'sku': sku, 'p_max': p_max, 'p_min': p_min, 'n_note': n_note, 'l_note':l_note, 'p_now':p_now}) html = t.render(c) return HttpResponse(html)echarts.html{message type="success" content="页面模板"/}<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>商品历史价格曲线</title> <script src="https://cdn.bootcss.com/jquery/3.0.0/jquery.min.js"></script> <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts.min.js"></script> </head> <body> <div style="position:absolute; top:10; left:10; width:1200px; height:95%;"> <div id="line" style="width:1100px;height:93%"></div> <div style="margin-top:20px"> <span>历史高价: <a style='color:red'>{{p_max}}</a></span> <span>历史低价: <a style='color:green'>{{p_min}}</a> </span> <span>当前价格: <a style='color:orange'>{{p_now}}</a> </span> <span>最新活动: <a style='color:blue'>{{n_note}}</a> </span> </div> </div> <div style="margin-left:1020px; height:865px; overflow:auto;"> <table style="maxHeight:1200px;" border="1" cellpadding="3" cellspacing="0"> <caption> 历史活动 </caption> <tr> <td>日期</td><td>内容</td> <tr> {% for i in l_note %} <tr> <td>{{ i.addtime }}</td> <td> {{ i.note }}</td> </tr> {% endfor %} </table> </div> <script> var chart = echarts.init(document.getElementById('line'), 'white', {renderer: 'canvas'}); $( function () { fetchData(chart); } ); function fetchData() { $.ajax({ type: "GET", url: "/mall/getprices/?sku={{sku}}", dataType: 'json', success: function (result) { chart.setOption(result.data); } }); } </script> </body> </html>{card-default label="历史价格" width="95%"}{/card-default}feadper 价格采集crawl_mall_spider.py隐藏内容,请前往内页查看详情
2022年08月01日
54 阅读
1 评论
2 点赞
2022-07-21
wordpress商品信息整理并通过Django管理
前言{callout color="#f0ad4e"}通过上一篇文章: wordpress直接通过数据库导出文章标题、分类信息到xls表格 ,将数据导入到excel表格中了。在处理的过程中发现仍然不是很方便,一是数据量有点大,每次打开更新需要的的时间有点久。另外无法统计分析。于是想把它输入到自己的数据库中,方便处理查看查询。{/callout}Django添加新模块resource{message type="success" content="models.py 建立数据库模型"/}from django.db import models #状态 U = 0 Y = 1 N = 2 STATUS_CHOICE = { U: '未处理', Y: '可用', N: '不可用', } # Create your models here. class Resource(models.Model): ''' 任务模型类 ''' id = models.AutoField(primary_key=True) rid = models.CharField(max_length=16, verbose_name='编号', default='0') rtitle = models.CharField(max_length=256, verbose_name='标题') rcontent = models.TextField(max_length=2048*8, verbose_name='说明') rparent1 = models.CharField(max_length=128, verbose_name='一级分类', default='0') rparent2 = models.CharField(max_length=128, verbose_name='二级分类', default='1') rurl = models.CharField(max_length=256, verbose_name='下载链接', default='0') rpwd = models.CharField(max_length=256, verbose_name='解压密码', default='0') status_choices = ((k, v) for k,v in STATUS_CHOICE.items()) rstatus = models.SmallIntegerField(default='0', choices=status_choices, verbose_name='状态') # admin显示订单的id def __str__(self): return self.rtitle class Meta: db_table = 'code_resource' verbose_name = '源码资源' verbose_name_plural = '源码资源'{message type="success" content="更新数据库"/}# 修改项目settings.py,添加模块 INSTALLED_APPS = [ ... 'resource', ... ], # 更新 python3 manage.py makemigrations python3 manage.py migrate{message type="success" content="查看建库语句"/}show create table code_resource;待处理资源wordpress数据库操作{message type="success" content="创建code_resource表"/}CREATE TABLE `code_resource` ( `id` int(11) NOT NULL AUTO_INCREMENT, `rid` varchar(16) COLLATE utf8_bin NOT NULL, `rtitle` varchar(256) COLLATE utf8_bin NOT NULL, `rcontent` longtext COLLATE utf8_bin NOT NULL, `rparent1` varchar(128) COLLATE utf8_bin NOT NULL, `rparent2` varchar(128) COLLATE utf8_bin NOT NULL, `rurl` varchar(256) COLLATE utf8_bin NOT NULL, `rpwd` varchar(256) COLLATE utf8_bin NOT NULL, `rstatus` smallint(6) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=60031 DEFAULT CHARSET=utf8 COLLATE=utf8_bin隐藏内容,请前往内页查看详情{message type="success" content="数据迁移处理"/}# 导出 mysqldump -uroot -pxxxx -h 127.0.0.1 yonp code_resource > code_resource.sql # 导入 mysql -uroot -pxxxx taskmonitor < code_resource.sql数据展示{message type="success" content="修改Django项目resource模块的admin.py文件"/}隐藏内容,请前往内页查看详情{card-default label="效果" width="90%"}{/card-default}FAQdjango 数据库更新抱错后,重新执行# 确保存在文件 resource/migrations/__init__.py # 登录数据库,清理resource模块记录 select * from django_migrations;
2022年07月21日
27 阅读
0 评论
0 点赞
2022-07-18
通过Django和Vue.js快速构建项目
前言{card-describe title="项目特点"}vueJS MVVM框架数据双向绑定单文件组件清晰的生命周期学习曲线平滑{/card-describe}{message type="success" content="M(Django)+C(Django)+MVVM(VueJS)=M+MVVM+C=MMVVCM"/}构建过程创建Django项目django-admin startproject ulb_manager python3 manage.py startapp backendvue创建一个前端项目vue-init webpack frontend # 构建 npm install npm run build配置Django使用Django的通用视图 TemplateView#配置 根 urls.py (即 ulb_manager/urls.py) 添加两行 url(r'^$', TemplateView.as_view(template_name="index.html")), url(r'^api/', include('backend.urls', namespace='api'))配置Django项目的模板搜索路径#打开 settings.py (ulb_manager/settings.py),找到TEMPLATES配置项,修改如下: 'DIRS': ['frontend/dist'],配置静态文件搜索路径#打开 settings.py (ulb_manager/settings.py),找到 STATICFILES_DIRS 配置项,配置如下: # Add for vuejs STATICFILES_DIRS = [ os.path.join(BASE_DIR, "frontend/dist/static"), ]开发环境{callout color="#f0ad4e"}使用VueJS的开发环境脱离了Django环境,访问Django的API,出现了跨域问题,有两种解决办法a.在VueJS层上做转发 (proxyTable)b.在Django层注入 header{/callout}#django 端配置 pip3 install django-cors-headers #修改配置文件 vim task_webserver/settings.py ... # 解决跨域问题,注意与common.CommonMiddleware的顺序 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # 增加跨域忽略 CORS_ALLOW_CREDENTIALS = True #线上设为False
2022年07月18日
37 阅读
0 评论
4 点赞
2022-07-17
Django框架使用过程中的技巧总结
Django服务健康检查模块配置# 进入项目目录,激活python 虚拟环境 source py3/bin/activate # 安装模块 pip install django-health-check # 修改django配置,INSTALLED_APPS模块添加 vim webserver/webserver/settings.py 'health_check', 'health_check.db', 'health_check.storage', # 添加路径,更新配置 vim webserver/webserver/urls.py url(r'^task/', include(('task.urls', 'task'), namespace='task')), url(r'^ht/', include('health_check.urls')), # 安装支持包 python -m pip install --upgrade djangorestframework python -m pip install --upgrade django-cors-headers # 更新 requirements.txt pip freeze > requirements.txt # 更新配置文件 vim task_webserver/settings.py CORS_ORIGIN_WHITELIST = ( 'http://127.0.0.1:8080', 'http://localhost:8080', #凡是出现在白名单中的域名,都可以访问后端接口 ) # 更新数据库 python manage.py makemigrations python manage.py migrate # 更新nginx 配置 location ^~ /ht/ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-NginX-Proxy true; proxy_pass http://webserver/ht/; } # 启动服务,测试Django 1.11 升级为 Django 3.2.4# 升级后安装数据库支持 pip3 install mysqlclient # 报错 /usr/bin/ld: 找不到 -lmariadb # 软件升级 yum install MariaDB-shared # 修改配置 vim gamestore/settings.py DEFAULT_AUTO_FIELD='django.db.models.AutoField' # 更新数据表结构 python manage.py migrate # centos7.9 mysql5.6版本执行 yum install mysql-devel gcc gcc-devel python-develDjango使用loguru 记录日志# setting.py 关闭默认日志记录器 LOGGING_CONFIG=None # 新日志模块 from loguru import logger logger.add("/var/log/gamestore/order.log", retention='10 days', level="DEBUG") # 需要记录日志的文件,import 直接使用 from loguru import logger 网站性能分析通过听云 python 探针统计数据# 安装听云 source py3/bin/activate pip install tingyun # 更新 requirements.txt pip freeze > requirements.txt # 配置 tingyun-admin generate-config f4993d3e7d5622e553131b262f650e4d support/tingyun.conf # 启动 TING_YUN_CONFIG_FILE=../support/tingyun.conf tingyun-admin run-program python manage.py runserver 127.0.0.1:8013通过newrelic 分析网站性能pip install newrelic # 下载配置文件 newrelic.ini # 手动启动 NEW_RELIC_CONFIG_FILE=../support/newrelic.ini newrelic-admin run-program python manage.py runserver 127.0.0.1:8013根据已有数据库生成模型类# price_info 为表名,不加默认生成所有 python manage.py inspectdb price_info
2022年07月17日
75 阅读
0 评论
0 点赞
2022-07-17
bookstore书城项目部署记录
{card-default label="书城首页" width="85%"}{/card-default}前言{callout color="#f0ad4e"}此项目说明文档很详细,附有教程。适合初学者学习django开发。项目地址: bookstore 说明文档 {/callout}部署下载项目git clone https://github.com/confucianzuoyuan/bookstore.git安装python虚拟环境# 安装 yum install python3 python3-devel python3-pip # 激活 pip3 install virtualenv virtualenv -p python3 py3 https://pypi.tuna.tsinghua.edu.cn/simple/ source py3/bin/activate # 安装模块 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/创建数据库CREATE DATABASE `bookstore` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; create user 'bkuser'@'%' IDENTIFIED BY 'bkxxx123'; grant all privileges on bookstore.* to 'bkuser'@'%'; flush privileges;.开发模式启动# 更新数据视图 python manage.py makemigrations python manage.py migrate # 启动 python manage.py runserver 172.16.4.10:8011 nginx 配置server { listen 80; server_name www.bookstore.com; #换成自己的域名 location / { proxy_pass http://172.16.4.10:8011; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }访问首页http://www.bookstore.com/后台# 添加超级管理员 python manage.py createsuperuserhttp://www.bookstore.com/admin/ {card-default label="后台" width="85%"}{/card-default}FAQnginx启动报错# 修改systemd配置延迟启动 mkdir -p /etc/systemd/system/nginx.service.d # 配置内容 vim /etc/systemd/system/nginx.service.d/override.conf [Service] ExecStartPost=/bin/sleep 0.1 # 重启服务 systemctl daemon-reload systemctl restart nginx
2022年07月17日
32 阅读
0 评论
0 点赞
1
2