mirror of
https://github.com/d0zingcat/RSSHub-python.git
synced 2026-05-17 23:16:51 +00:00
add cninfo announcement
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
[run]
|
[run]
|
||||||
source = rsshub
|
source = rsshub
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
FLASK_ENV=development
|
FLASK_ENV=development
|
||||||
FLASK_APP=rsshub
|
FLASK_APP=rsshub
|
||||||
FLASK_DEBUG=1
|
FLASK_DEBUG=1
|
||||||
32
.gitignore
vendored
32
.gitignore
vendored
@@ -1,17 +1,17 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
.pytest_cache
|
.pytest_cache
|
||||||
|
|
||||||
# Distribution / packaging
|
# Distribution / packaging
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
*.egg-info/
|
*.egg-info/
|
||||||
.idea
|
.idea
|
||||||
venv
|
venv
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
.vscode
|
.vscode
|
||||||
.coverage
|
.coverage
|
||||||
htmlcov/
|
htmlcov/
|
||||||
data-dev.db
|
data-dev.db
|
||||||
@@ -1,70 +1,70 @@
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import click
|
import click
|
||||||
from flask import Flask, render_template
|
from flask import Flask, render_template
|
||||||
from flask.cli import with_appcontext
|
from flask.cli import with_appcontext
|
||||||
from rsshub.config import config
|
from rsshub.config import config
|
||||||
from rsshub.extensions import *
|
from rsshub.extensions import *
|
||||||
from rsshub.blueprints.main import bp as main_bp
|
from rsshub.blueprints.main import bp as main_bp
|
||||||
from rsshub.utils import XMLResponse
|
from rsshub.utils import XMLResponse
|
||||||
|
|
||||||
|
|
||||||
def create_app(config_name=None):
|
def create_app(config_name=None):
|
||||||
if config_name is None:
|
if config_name is None:
|
||||||
config_name = os.getenv('FLASK_CONFIG', 'development')
|
config_name = os.getenv('FLASK_CONFIG', 'development')
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_object(config[config_name])
|
app.config.from_object(config[config_name])
|
||||||
app.response_class = XMLResponse
|
app.response_class = XMLResponse
|
||||||
|
|
||||||
register_blueprints(app)
|
register_blueprints(app)
|
||||||
register_extensions(app)
|
register_extensions(app)
|
||||||
register_errors(app)
|
register_errors(app)
|
||||||
register_context_processors(app)
|
register_context_processors(app)
|
||||||
register_cli(app)
|
register_cli(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
def register_extensions(app):
|
def register_extensions(app):
|
||||||
bootstrap.init_app(app)
|
bootstrap.init_app(app)
|
||||||
debugtoolbar.init_app(app)
|
debugtoolbar.init_app(app)
|
||||||
moment.init_app(app)
|
moment.init_app(app)
|
||||||
|
|
||||||
|
|
||||||
def register_blueprints(app):
|
def register_blueprints(app):
|
||||||
app.register_blueprint(main_bp)
|
app.register_blueprint(main_bp)
|
||||||
|
|
||||||
|
|
||||||
def register_errors(app):
|
def register_errors(app):
|
||||||
@app.errorhandler(400)
|
@app.errorhandler(400)
|
||||||
def bad_request(e):
|
def bad_request(e):
|
||||||
return render_template('errors/400.html'), 400
|
return render_template('errors/400.html'), 400
|
||||||
|
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
return render_template('errors/404.html'), 404
|
return render_template('errors/404.html'), 404
|
||||||
|
|
||||||
@app.errorhandler(500)
|
@app.errorhandler(500)
|
||||||
def internal_server_error(e):
|
def internal_server_error(e):
|
||||||
return render_template('errors/500.html'), 500
|
return render_template('errors/500.html'), 500
|
||||||
|
|
||||||
|
|
||||||
def register_context_processors(app):
|
def register_context_processors(app):
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def inject_date_now():
|
def inject_date_now():
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
return {'now': now}
|
return {'now': now}
|
||||||
|
|
||||||
|
|
||||||
def register_cli(app):
|
def register_cli(app):
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def ptshell():
|
def ptshell():
|
||||||
"""Use ptpython as shell."""
|
"""Use ptpython as shell."""
|
||||||
try:
|
try:
|
||||||
from ptpython.repl import embed
|
from ptpython.repl import embed
|
||||||
if not app.config['TESTING']:
|
if not app.config['TESTING']:
|
||||||
embed(app.make_shell_context())
|
embed(app.make_shell_context())
|
||||||
except ImportError:
|
except ImportError:
|
||||||
click.echo('ptpython not installed! Use the default shell instead.')
|
click.echo('ptpython not installed! Use the default shell instead.')
|
||||||
|
|||||||
@@ -1,52 +1,59 @@
|
|||||||
from flask import Blueprint, render_template, request
|
from flask import Blueprint, render_template, request
|
||||||
|
|
||||||
bp = Blueprint('main', __name__)
|
bp = Blueprint('main', __name__)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/')
|
@bp.route('/')
|
||||||
def index():
|
def index():
|
||||||
return render_template('main/index.html')
|
return render_template('main/index.html')
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/feeds')
|
@bp.route('/feeds')
|
||||||
def feeds():
|
def feeds():
|
||||||
return render_template('main/feeds.html')
|
return render_template('main/feeds.html')
|
||||||
|
|
||||||
|
|
||||||
@bp.app_template_global()
|
@bp.app_template_global()
|
||||||
def filter_content(ctx):
|
def filter_content(ctx):
|
||||||
include_title = request.args.get('include_title')
|
include_title = request.args.get('include_title')
|
||||||
include_description = request.args.get('include_description')
|
include_description = request.args.get('include_description')
|
||||||
exclude_title = request.args.get('exclude_title')
|
exclude_title = request.args.get('exclude_title')
|
||||||
exclude_description = request.args.get('exclude_description')
|
exclude_description = request.args.get('exclude_description')
|
||||||
limit = request.args.get('limit', type=int)
|
limit = request.args.get('limit', type=int)
|
||||||
items = ctx['items'].copy()
|
items = ctx['items'].copy()
|
||||||
items = [item for item in items if include_title in item['title']] if include_title else items
|
items = [item for item in items if include_title in item['title']] if include_title else items
|
||||||
items = [item for item in items if include_description in item['description']] if include_description else items
|
items = [item for item in items if include_description in item['description']] if include_description else items
|
||||||
items = [item for item in items if exclude_title not in item['title']] if exclude_title else items
|
items = [item for item in items if exclude_title not in item['title']] if exclude_title else items
|
||||||
items = [item for item in items if exclude_description not in item['description']] if exclude_description else items
|
items = [item for item in items if exclude_description not in item['description']] if exclude_description else items
|
||||||
items = items[:limit] if limit else items
|
items = items[:limit] if limit else items
|
||||||
ctx = ctx.copy()
|
ctx = ctx.copy()
|
||||||
ctx['items'] = items
|
ctx['items'] = items
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
#---------- feed路由从这里开始 -----------#
|
#---------- feed路由从这里开始 -----------#
|
||||||
@bp.route('/chuansongme/articles/<string:category>')
|
@bp.route('/cninfo/announcement/<string:stock_id>/<string:category>')
|
||||||
@bp.route('/chuansongme/articles')
|
@bp.route('/cninfo/announcement')
|
||||||
def chuansongme_articles(category=''):
|
def cninfo_announcement(stock_id='', category=''):
|
||||||
from rsshub.spiders.chuansongme.articles import ctx
|
from rsshub.spiders.cninfo.announcement import ctx
|
||||||
return render_template('main/atom.xml', **filter_content(ctx(category)))
|
return render_template('main/atom.xml', **filter_content(ctx(stock_id,category)))
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/ctolib/topics/<string:category>')
|
@bp.route('/chuansongme/articles/<string:category>')
|
||||||
@bp.route('/ctolib/topics')
|
@bp.route('/chuansongme/articles')
|
||||||
def ctolib_topics(category=''):
|
def chuansongme_articles(category=''):
|
||||||
from rsshub.spiders.ctolib.topics import ctx
|
from rsshub.spiders.chuansongme.articles import ctx
|
||||||
return render_template('main/atom.xml', **filter_content(ctx(category)))
|
return render_template('main/atom.xml', **filter_content(ctx(category)))
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/infoq/recommend')
|
@bp.route('/ctolib/topics/<string:category>')
|
||||||
def infoq_recommend():
|
@bp.route('/ctolib/topics')
|
||||||
from rsshub.spiders.infoq.recommend import ctx
|
def ctolib_topics(category=''):
|
||||||
return render_template('main/atom.xml', **filter_content(ctx()))
|
from rsshub.spiders.ctolib.topics import ctx
|
||||||
|
return render_template('main/atom.xml', **filter_content(ctx(category)))
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/infoq/recommend')
|
||||||
|
def infoq_recommend():
|
||||||
|
from rsshub.spiders.infoq.recommend import ctx
|
||||||
|
return render_template('main/atom.xml', **filter_content(ctx()))
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||||
|
|
||||||
|
|
||||||
class BaseConfig:
|
class BaseConfig:
|
||||||
SITE_NAME = 'RSSHub'
|
SITE_NAME = 'RSSHub'
|
||||||
GITHUB_USERNAME = 'alphardex'
|
GITHUB_USERNAME = 'alphardex'
|
||||||
EMAIL = '2582347430@qq.com'
|
EMAIL = '2582347430@qq.com'
|
||||||
SECRET_KEY = os.environ.get('SECRET_KEY') or 'f43hrt53et53'
|
SECRET_KEY = os.environ.get('SECRET_KEY') or 'f43hrt53et53'
|
||||||
DEBUG_TB_INTERCEPT_REDIRECTS = False
|
DEBUG_TB_INTERCEPT_REDIRECTS = False
|
||||||
|
|
||||||
|
|
||||||
class DevelopmentConfig(BaseConfig):
|
class DevelopmentConfig(BaseConfig):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TestingConfig(BaseConfig):
|
class TestingConfig(BaseConfig):
|
||||||
TESTING = True
|
TESTING = True
|
||||||
|
|
||||||
|
|
||||||
class ProductionConfig(BaseConfig):
|
class ProductionConfig(BaseConfig):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
'development': DevelopmentConfig,
|
'development': DevelopmentConfig,
|
||||||
'testing': TestingConfig,
|
'testing': TestingConfig,
|
||||||
'production': ProductionConfig
|
'production': ProductionConfig
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from flask_bootstrap import Bootstrap
|
from flask_bootstrap import Bootstrap
|
||||||
from flask_debugtoolbar import DebugToolbarExtension
|
from flask_debugtoolbar import DebugToolbarExtension
|
||||||
from flask_moment import Moment
|
from flask_moment import Moment
|
||||||
|
|
||||||
|
|
||||||
bootstrap = Bootstrap()
|
bootstrap = Bootstrap()
|
||||||
debugtoolbar = DebugToolbarExtension()
|
debugtoolbar = DebugToolbarExtension()
|
||||||
moment = Moment()
|
moment = Moment()
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
from rsshub.utils import fetch
|
from rsshub.utils import fetch
|
||||||
|
|
||||||
domain = 'https://chuansongme.com'
|
domain = 'https://chuansongme.com'
|
||||||
|
|
||||||
|
|
||||||
def parse(post):
|
def parse(post):
|
||||||
item = {}
|
item = {}
|
||||||
item['title'] = post.css('a.question_link::text').extract()[-1].strip()
|
item['title'] = post.css('a.question_link::text').extract()[-1].strip()
|
||||||
link = f"{domain}{post.css('a.question_link::attr(href)').extract_first()}"
|
link = f"{domain}{post.css('a.question_link::attr(href)').extract_first()}"
|
||||||
item['link'] = link
|
item['link'] = link
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def ctx(category=''):
|
def ctx(category=''):
|
||||||
tree = fetch(f"{domain}/{category}")
|
tree = fetch(f"{domain}/{category}")
|
||||||
posts = tree.css('.feed_body .pagedlist_item')
|
posts = tree.css('.feed_body .pagedlist_item')
|
||||||
return {
|
return {
|
||||||
'title': '传送门',
|
'title': '传送门',
|
||||||
'link': domain,
|
'link': domain,
|
||||||
'description': '传送门:微信公众号订阅',
|
'description': '传送门:微信公众号订阅',
|
||||||
'author': 'alphardex',
|
'author': 'alphardex',
|
||||||
'items': list(map(parse, posts))
|
'items': list(map(parse, posts))
|
||||||
}
|
}
|
||||||
49
rsshub/spiders/cninfo/announcement.py
Normal file
49
rsshub/spiders/cninfo/announcement.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import requests
|
||||||
|
from rsshub.utils import DEFAULT_HEADERS
|
||||||
|
|
||||||
|
domain = 'http://www.cninfo.com.cn'
|
||||||
|
|
||||||
|
|
||||||
|
def parse(post):
|
||||||
|
item = {}
|
||||||
|
item['title'] = post['secName'] + '(' + post['secCode'] + ')' + ': ' + post['announcementTitle']
|
||||||
|
item['description'] = item['title']
|
||||||
|
item['link'] = 'http://static.cninfo.com.cn/' + post['adjunctUrl']
|
||||||
|
item['pubDate'] = post['announcementTime']
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
|
def ctx(stock_id='', category=''):
|
||||||
|
stock_id = '' if stock_id == 'all' else stock_id
|
||||||
|
stock_name = ''
|
||||||
|
stock_list = requests.get('http://www.cninfo.com.cn/new/data/szse_stock.json', headers=DEFAULT_HEADERS).json()['stockList']
|
||||||
|
for stock in stock_list:
|
||||||
|
if stock['code'] == stock_id :
|
||||||
|
stock_id = stock['orgId']
|
||||||
|
stock_name = stock['zwjc']
|
||||||
|
break
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
nowtime = datetime.datetime.now()
|
||||||
|
deltaday=datetime.timedelta(days=1)
|
||||||
|
start_date = datetime.datetime.strftime(nowtime- 5 * deltaday, '%Y-%m-%d')
|
||||||
|
end_date = datetime.datetime.strftime(nowtime + 2 * deltaday, '%Y-%m-%d')
|
||||||
|
seDate = start_date + '~' + end_date
|
||||||
|
|
||||||
|
searchkey = ''
|
||||||
|
if '_' in category:
|
||||||
|
searchkey = category.split('_')[-1]
|
||||||
|
category = category.split('_')[0]
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_HEADERS.update({'Referer': domain})
|
||||||
|
posts = requests.post(f'{domain}/new/hisAnnouncement/query', \
|
||||||
|
data={'pageSize': '30','tabName':'fulltext', 'plate': '', 'category':f'category_{category}_szsh', \
|
||||||
|
'secid': stock_id,'seDate':'', 'seDate': seDate, 'searchkey': searchkey }, headers=DEFAULT_HEADERS).json()['announcements']
|
||||||
|
return {
|
||||||
|
'title': f'{stock_name}-{category}-公告-巨潮资讯',
|
||||||
|
'link': f'{domain}/new/commonUrl/pageOfSearch?url=disclosure/list/search&checkedCategory=category_{category}_szsh&searchkey={searchkey}',
|
||||||
|
'description': f'{stock_name}关于{category}的公告-巨潮资讯',
|
||||||
|
'author': 'hillerliao',
|
||||||
|
'items': list(map(parse, posts))
|
||||||
|
}
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
from rsshub.utils import fetch
|
from rsshub.utils import fetch
|
||||||
|
|
||||||
domain = 'https://www.ctolib.com'
|
domain = 'https://www.ctolib.com'
|
||||||
|
|
||||||
|
|
||||||
def parse(post):
|
def parse(post):
|
||||||
item = {}
|
item = {}
|
||||||
item['title'] = post.css('a.title::text').extract_first()
|
item['title'] = post.css('a.title::text').extract_first()
|
||||||
item['description'] = post.css('p.abstract::text').extract_first()
|
item['description'] = post.css('p.abstract::text').extract_first()
|
||||||
item['link'] = f"{domain}{post.css('a.title::attr(href)').extract_first()}"
|
item['link'] = f"{domain}{post.css('a.title::attr(href)').extract_first()}"
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def ctx(category=''):
|
def ctx(category=''):
|
||||||
tree = fetch(f'{domain}/python/topics/{category}')
|
tree = fetch(f'{domain}/python/topics/{category}')
|
||||||
posts = tree.css('ul.note-list li')
|
posts = tree.css('ul.note-list li')
|
||||||
return {
|
return {
|
||||||
'title': 'CTOLib码库',
|
'title': 'CTOLib码库',
|
||||||
'link': domain,
|
'link': domain,
|
||||||
'description': 'Python开发社区',
|
'description': 'Python开发社区',
|
||||||
'author': 'alphardex',
|
'author': 'alphardex',
|
||||||
'items': list(map(parse, posts))
|
'items': list(map(parse, posts))
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,24 @@
|
|||||||
import requests
|
import requests
|
||||||
from rsshub.utils import DEFAULT_HEADERS
|
from rsshub.utils import DEFAULT_HEADERS
|
||||||
|
|
||||||
domain = 'https://www.infoq.cn'
|
domain = 'https://www.infoq.cn'
|
||||||
|
|
||||||
|
|
||||||
def parse(post):
|
def parse(post):
|
||||||
item = {}
|
item = {}
|
||||||
item['title'] = post['article_title']
|
item['title'] = post['article_title']
|
||||||
item['description'] = f"{post['article_summary']}<br><img referrerpolicy='no-referrer' src={post.get('article_cover')}>"
|
item['description'] = f"{post['article_summary']}<br><img referrerpolicy='no-referrer' src={post.get('article_cover')}>"
|
||||||
item['link'] = f"{domain}/article/{post['uuid']}"
|
item['link'] = f"{domain}/article/{post['uuid']}"
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
||||||
def ctx():
|
def ctx():
|
||||||
DEFAULT_HEADERS.update({'Referer': 'https://www.infoq.cn'}) # 必须设置Referer,不然会451错误
|
DEFAULT_HEADERS.update({'Referer': 'https://www.infoq.cn'}) # 必须设置Referer,不然会451错误
|
||||||
posts = requests.post(f'{domain}/public/v1/my/recommond', data={'size': 20}, headers=DEFAULT_HEADERS).json()['data']
|
posts = requests.post(f'{domain}/public/v1/my/recommond', data={'size': 20}, headers=DEFAULT_HEADERS).json()['data']
|
||||||
return {
|
return {
|
||||||
'title': 'infoq',
|
'title': 'infoq',
|
||||||
'link': domain,
|
'link': domain,
|
||||||
'description': 'InfoQ - 促进软件开发领域知识与创新的传播',
|
'description': 'InfoQ - 促进软件开发领域知识与创新的传播',
|
||||||
'author': 'alphardex',
|
'author': 'alphardex',
|
||||||
'items': list(map(parse, posts))
|
'items': list(map(parse, posts))
|
||||||
}
|
}
|
||||||
@@ -1,48 +1,48 @@
|
|||||||
/* global */
|
/* global */
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jumbotron {
|
.jumbotron {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding-top: 38px;
|
padding-top: 38px;
|
||||||
padding-bottom: 38px;
|
padding-bottom: 38px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip {
|
.tip {
|
||||||
/* from github.com */
|
/* from github.com */
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: #fafbfc;
|
background-color: #fafbfc;
|
||||||
border: 1px solid #e1e4e8;
|
border: 1px solid #e1e4e8;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
box-shadow: inset 0 0 10px rgba(27, 31, 35, 0.05);
|
box-shadow: inset 0 0 10px rgba(27, 31, 35, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide {
|
.hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline {
|
.inline {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-footer {
|
.page-footer {
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* footer */
|
/* footer */
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
margin: 30px 0;
|
margin: 30px 0;
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
border-top: 1px solid #e5e5e5;
|
border-top: 1px solid #e5e5e5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
{% block title %}400 错误{% endblock %}
|
{% block title %}400 错误{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<h1>400 Bad Request</h1>
|
<h1>400 Bad Request</h1>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
{% block title %}404 错误{% endblock %}
|
{% block title %}404 错误{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<h1>404 Not Found</h1>
|
<h1>404 Not Found</h1>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
{% block title %}500 错误{% endblock %}
|
{% block title %}500 错误{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<h1>服务器出错</h1>
|
<h1>服务器出错</h1>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,70 +1,70 @@
|
|||||||
{% from 'bootstrap/nav.html' import render_nav_item %}
|
{% from 'bootstrap/nav.html' import render_nav_item %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<title>{% block title %}{% endblock title %}</title>
|
<title>{% block title %}{% endblock title %}</title>
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
||||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
{{ bootstrap.load_css() }}
|
{{ bootstrap.load_css() }}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||||
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
{% endblock styles %}
|
{% endblock styles %}
|
||||||
{% endblock head %}
|
{% endblock head %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{% block nav %}
|
{% block nav %}
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="{{url_for('main.index')}}">{{ config['SITE_NAME'] }}</a>
|
<a class="navbar-brand" href="{{url_for('main.index')}}">{{ config['SITE_NAME'] }}</a>
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown"
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown"
|
||||||
aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
|
aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="navbarNavDropdown">
|
<div class="collapse navbar-collapse" id="navbarNavDropdown">
|
||||||
<ul class="nav navbar-nav ml-auto">
|
<ul class="nav navbar-nav ml-auto">
|
||||||
{{render_nav_item('main.feeds', 'Feeds')}}
|
{{render_nav_item('main.feeds', 'Feeds')}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
{% endblock nav %}
|
{% endblock nav %}
|
||||||
<main class="container">
|
<main class="container">
|
||||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for category, message in messages %}
|
{% for category, message in messages %}
|
||||||
<div class="alert alert-dismissable alert-{{ category }}" role="alert">
|
<div class="alert alert-dismissable alert-{{ category }}" role="alert">
|
||||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||||
{{ message }}
|
{{ message }}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
<footer>
|
<footer>
|
||||||
<p class="float-left">
|
<p class="float-left">
|
||||||
<small>©
|
<small>©
|
||||||
Made by <a href="https://github.com/{{config['GITHUB_USERNAME']}}" target="_blank">{{config['GITHUB_USERNAME']}}</a>
|
Made by <a href="https://github.com/{{config['GITHUB_USERNAME']}}" target="_blank">{{config['GITHUB_USERNAME']}}</a>
|
||||||
with <span class="fa fa-heart"></span>
|
with <span class="fa fa-heart"></span>
|
||||||
</small>
|
</small>
|
||||||
</p>
|
</p>
|
||||||
<p class="float-right">
|
<p class="float-right">
|
||||||
<small><a href="mailto:{{ config['EMAIL'] }}">Contact</a></small>
|
<small><a href="mailto:{{ config['EMAIL'] }}">Contact</a></small>
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
{% endblock footer %}
|
{% endblock footer %}
|
||||||
</main>
|
</main>
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
{{ bootstrap.load_js() }}
|
{{ bootstrap.load_js() }}
|
||||||
{{ moment.include_moment() }}
|
{{ moment.include_moment() }}
|
||||||
{{ moment.locale('zh-cn') }}
|
{{ moment.locale('zh-cn') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||||
<generator>{{config['SITE_NAME']}}</generator>
|
<generator>{{config['SITE_NAME']}}</generator>
|
||||||
<webMaster>{{config['EMAIL']}}</webMaster>
|
<webMaster>{{config['EMAIL']}}</webMaster>
|
||||||
<language>zh-cn</language>
|
<language>zh-cn</language>
|
||||||
<id>{{link}}</id>
|
<id>{{link}}</id>
|
||||||
<title><![CDATA[{{title|safe}}]]></title>
|
<title><![CDATA[{{title|safe}}]]></title>
|
||||||
<link href="{{link}}"/>
|
<link href="{{link}}"/>
|
||||||
<author>
|
<author>
|
||||||
<name><![CDATA[{{author|safe}}]]></name>
|
<name><![CDATA[{{author|safe}}]]></name>
|
||||||
</author>
|
</author>
|
||||||
{% for item in items %}
|
{% for item in items %}
|
||||||
<entry>
|
<entry>
|
||||||
<id>{{item.link}}</id>
|
<id>{{item.link}}</id>
|
||||||
<title><![CDATA[{{item.title|safe}}]]></title>
|
<title><![CDATA[{{item.title|safe}}]]></title>
|
||||||
<published>{{item.pubDate|default(now)}}</published>
|
<published>{{item.pubDate|default(now)}}</published>
|
||||||
<updated>{{item.pubDate|default(now)}}</updated>
|
<updated>{{item.pubDate|default(now)}}</updated>
|
||||||
<link href="{{item.link}}"/>
|
<link href="{{item.link}}"/>
|
||||||
<content type="html" src="{{item.link}}"><![CDATA[{{item.description|safe}}]]></content>
|
<content type="html" src="{{item.link}}"><![CDATA[{{item.description|safe}}]]></content>
|
||||||
</entry>
|
</entry>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</feed>
|
</feed>
|
||||||
@@ -1,67 +1,77 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
{% block title %}All Feeds{% endblock title %}
|
{% block title %}All Feeds{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card text-left">
|
<div class="card text-left">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title">传送门</h4>
|
<h4 class="card-title">传送门</h4>
|
||||||
<h6 class="text-muted">文章 <a href="https://github.com/alphardex" target="_blank" class="badge badge-secondary">by alphardex</a></h6>
|
<h6 class="text-muted">文章 <a href="https://github.com/alphardex" target="_blank" class="badge badge-secondary">by alphardex</a></h6>
|
||||||
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/chuansongme/articles" target="_blank">https://rsshub-python.herokuapp.com/chuansongme/articles</a></p>
|
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/chuansongme/articles" target="_blank">https://rsshub-python.herokuapp.com/chuansongme/articles</a></p>
|
||||||
<p class="card-text">路由:<code>/chuansongme/articles/:category</code></p>
|
<p class="card-text">路由:<code>/chuansongme/articles/:category</code></p>
|
||||||
<p class="card-text">参数:category [默认为“最新”]</p>
|
<p class="card-text">参数:category [默认为“最新”]</p>
|
||||||
<table class="table table-bordered table-sm">
|
<table class="table table-bordered table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{% for th in ['精选','区块链','汽车','创意科技','媒体达人','电影音乐','娱乐休闲','生活旅行','学习工具','历史读书','金融理财','美食菜谱'] %}
|
{% for th in ['精选','区块链','汽车','创意科技','媒体达人','电影音乐','娱乐休闲','生活旅行','学习工具','历史读书','金融理财','美食菜谱'] %}
|
||||||
<th>{{th}}</th>
|
<th>{{th}}</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
{% for td in ['select', 'blockchain', 'auto', 'ideatech', 'newsmedia', 'moviemusic', 'fun', 'lifejourney', 'utility', 'hisbook', 'finance', 'food']%}
|
{% for td in ['select', 'blockchain', 'auto', 'ideatech', 'newsmedia', 'moviemusic', 'fun', 'lifejourney', 'utility', 'hisbook', 'finance', 'food']%}
|
||||||
<td>{{td}}</td>
|
<td>{{td}}</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="card text-left">
|
<div class="card text-left">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title">CTOLib</h4>
|
<h4 class="card-title">CTOLib</h4>
|
||||||
<h6 class="text-muted">话题 <a href="https://github.com/alphardex" target="_blank" class="badge badge-secondary">by alphardex</a></h6>
|
<h6 class="text-muted">话题 <a href="https://github.com/alphardex" target="_blank" class="badge badge-secondary">by alphardex</a></h6>
|
||||||
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/ctolib/topics" target="_blank">https://rsshub-python.herokuapp.com/ctolib/topics</a></p>
|
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/ctolib/topics" target="_blank">https://rsshub-python.herokuapp.com/ctolib/topics</a></p>
|
||||||
<p class="card-text">路由:<code>/ctolib/topics/:category</code></p>
|
<p class="card-text">路由:<code>/ctolib/topics/:category</code></p>
|
||||||
<p class="card-text">参数:category [默认为“默认排序”]</p>
|
<p class="card-text">参数:category [默认为“默认排序”]</p>
|
||||||
<table class="table table-bordered table-sm">
|
<table class="table table-bordered table-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{% for th in ['最新发布', '优质主题'] %}
|
{% for th in ['最新发布', '优质主题'] %}
|
||||||
<th>{{th}}</th>
|
<th>{{th}}</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
{% for td in ['last', 'popular']%}
|
{% for td in ['last', 'popular']%}
|
||||||
<td>{{td}}</td>
|
<td>{{td}}</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="card text-left">
|
<div class="card text-left">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title">InfoQ</h4>
|
<h4 class="card-title">InfoQ</h4>
|
||||||
<h6 class="text-muted">推荐内容 <a href="https://github.com/alphardex" target="_blank" class="badge badge-secondary">by alphardex</a></h6>
|
<h6 class="text-muted">推荐内容 <a href="https://github.com/alphardex" target="_blank" class="badge badge-secondary">by alphardex</a></h6>
|
||||||
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/infoq/recommend" target="_blank">https://rsshub-python.herokuapp.com/infoq/recommend</a></p>
|
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/infoq/recommend" target="_blank">https://rsshub-python.herokuapp.com/infoq/recommend</a></p>
|
||||||
<p class="card-text">路由:<code>/infoq/recommend</code></p>
|
<p class="card-text">路由:<code>/infoq/recommend</code></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
|
<div class="card text-left">
|
||||||
|
<div class="card-body">
|
||||||
|
<h4 class="card-title">巨潮资讯</h4>
|
||||||
|
<h6 class="text-muted">公司公告 <a href="https://github.com/hillerliao" target="_blank" class="badge badge-secondary">by hillerliao</a></h6>
|
||||||
|
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/cninfo/announcement/all/gqjl" target="_blank">https://rsshub-python.herokuapp.com/cninfo/announcement/all/gqjl</a></p>
|
||||||
|
<p class="card-text">举例:<a href="https://rsshub-python.herokuapp.com/cninfo/announcement/all/gqbd_预披露" target="_blank">https://rsshub-python.herokuapp.com/cninfo/announcement/all/gqbd_预披露</a>,股权变动类公告中标题含有「预披露」的公告</p>
|
||||||
|
<p class="card-text">路由:<code>/cninfo/announcement/:stock_id/:category</code></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
{% block title %}Welcome to RSShub!{% endblock title %}
|
{% block title %}Welcome to RSShub!{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="jumbotron">
|
<div class="jumbotron">
|
||||||
<h1 class="display-4">Welcome to RSSHub!</h1>
|
<h1 class="display-4">Welcome to RSSHub!</h1>
|
||||||
<p class="lead">If you see this page, the RSSHub is successfully installed and working.</p>
|
<p class="lead">If you see this page, the RSSHub is successfully installed and working.</p>
|
||||||
<p>
|
<p>
|
||||||
<a class="btn btn-primary btn-lg" role="button" target="_blank" href="https://github.com/alphardex/RSSHub-python">View Source</a>
|
<a class="btn btn-primary btn-lg" role="button" target="_blank" href="https://github.com/alphardex/RSSHub-python">View Source</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
from flask import Response
|
from flask import Response
|
||||||
import requests
|
import requests
|
||||||
from parsel import Selector
|
from parsel import Selector
|
||||||
|
|
||||||
DEFAULT_HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
|
DEFAULT_HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
|
||||||
|
|
||||||
|
|
||||||
class XMLResponse(Response):
|
class XMLResponse(Response):
|
||||||
def __init__(self, response, **kwargs):
|
def __init__(self, response, **kwargs):
|
||||||
if 'mimetype' not in kwargs and 'contenttype' not in kwargs:
|
if 'mimetype' not in kwargs and 'contenttype' not in kwargs:
|
||||||
if response.startswith('<?xml'):
|
if response.startswith('<?xml'):
|
||||||
kwargs['mimetype'] = 'application/xml'
|
kwargs['mimetype'] = 'application/xml'
|
||||||
return super().__init__(response, **kwargs)
|
return super().__init__(response, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def fetch(url: str, headers: dict=DEFAULT_HEADERS, proxies: dict=None):
|
def fetch(url: str, headers: dict=DEFAULT_HEADERS, proxies: dict=None):
|
||||||
try:
|
try:
|
||||||
res = requests.get(url, headers=headers, proxies=proxies)
|
res = requests.get(url, headers=headers, proxies=proxies)
|
||||||
res.raise_for_status()
|
res.raise_for_status()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'[Err] {e}')
|
print(f'[Err] {e}')
|
||||||
else:
|
else:
|
||||||
html = res.text
|
html = res.text
|
||||||
tree = Selector(text=html)
|
tree = Selector(text=html)
|
||||||
return tree
|
return tree
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import unittest
|
import unittest
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
from rsshub import create_app
|
from rsshub import create_app
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(unittest.TestCase):
|
class BaseTestCase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
app = create_app('testing')
|
app = create_app('testing')
|
||||||
self.context = app.test_request_context()
|
self.context = app.test_request_context()
|
||||||
self.context.push()
|
self.context.push()
|
||||||
self.client = app.test_client()
|
self.client = app.test_client()
|
||||||
self.runner = app.test_cli_runner()
|
self.runner = app.test_cli_runner()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.context.pop()
|
self.context.pop()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from tests.base import BaseTestCase
|
from tests.base import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
class CLITestCase(BaseTestCase):
|
class CLITestCase(BaseTestCase):
|
||||||
def test_ptshell(self):
|
def test_ptshell(self):
|
||||||
result = self.runner.invoke(args=['ptshell'])
|
result = self.runner.invoke(args=['ptshell'])
|
||||||
self.assertNotIn('ptpython not installed! Use the default shell instead.', result.output)
|
self.assertNotIn('ptpython not installed! Use the default shell instead.', result.output)
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
from flask import current_app, abort
|
from flask import current_app, abort
|
||||||
from tests.base import BaseTestCase
|
from tests.base import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
class ErrorsTestCase(BaseTestCase):
|
class ErrorsTestCase(BaseTestCase):
|
||||||
def test_400(self):
|
def test_400(self):
|
||||||
@current_app.route('/400')
|
@current_app.route('/400')
|
||||||
def bad_request():
|
def bad_request():
|
||||||
abort(400)
|
abort(400)
|
||||||
|
|
||||||
response = self.client.get('/400')
|
response = self.client.get('/400')
|
||||||
data = response.get_data(as_text=True)
|
data = response.get_data(as_text=True)
|
||||||
self.assertIn('400 Bad Request', data)
|
self.assertIn('400 Bad Request', data)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|
||||||
def test_404(self):
|
def test_404(self):
|
||||||
response = self.client.get('/nothing')
|
response = self.client.get('/nothing')
|
||||||
data = response.get_data(as_text=True)
|
data = response.get_data(as_text=True)
|
||||||
self.assertIn('404 Not Found', data)
|
self.assertIn('404 Not Found', data)
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_500(self):
|
def test_500(self):
|
||||||
@current_app.route('/500')
|
@current_app.route('/500')
|
||||||
def internal_server_error_for_test():
|
def internal_server_error_for_test():
|
||||||
abort(500)
|
abort(500)
|
||||||
|
|
||||||
response = self.client.get('/500')
|
response = self.client.get('/500')
|
||||||
data = response.get_data(as_text=True)
|
data = response.get_data(as_text=True)
|
||||||
self.assertIn('服务器出错', data)
|
self.assertIn('服务器出错', data)
|
||||||
self.assertEqual(response.status_code, 500)
|
self.assertEqual(response.status_code, 500)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from flask import url_for
|
from flask import url_for
|
||||||
from tests.base import BaseTestCase
|
from tests.base import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
class MainTestCase(BaseTestCase):
|
class MainTestCase(BaseTestCase):
|
||||||
def test_index(self):
|
def test_index(self):
|
||||||
response = self.client.get(url_for('main.index'))
|
response = self.client.get(url_for('main.index'))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|||||||
Reference in New Issue
Block a user