├── .gitignore
├── .nojekyll
├── CNAME
├── LICENSE
├── MANIFEST.in
├── README.md
├── _config.yml
├── demo
├── css
│ └── app.css
├── img
│ ├── bg.png
│ ├── footer.png
│ ├── header.png
│ ├── icon-01.png
│ ├── icon-02.png
│ ├── icon-03.png
│ ├── icon-04.png
│ ├── icon-05.png
│ ├── icon-06.png
│ ├── icon-07.png
│ ├── icon-bg.png
│ └── thumb.jpg
├── index.html
└── js
│ ├── countUp.min.js
│ ├── echarts-map-china.js
│ ├── echarts-theme-shine.js
│ ├── echarts.min.js
│ └── jquery-3.3.1.min.js
├── demo_proj
├── manage.py
├── ncov
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── requirements.txt
├── django_covid19
├── __init__.py
├── admin.py
├── apps.py
├── data
│ ├── CountryCodes.csv
│ └── CountryCodes.json
├── filters.py
├── fixtures
│ ├── city.json
│ ├── country.json
│ ├── initial_data.json
│ ├── province.json
│ └── statistics.json
├── locale
│ └── zh_Hans
│ │ └── LC_MESSAGES
│ │ └── django.po
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ ├── crawl.py
│ │ └── import_crc.py
├── migrations
│ └── __init__.py
├── models.py
├── serializers.py
├── settings.py
├── signals.py
├── spider
│ └── nCoV
│ │ ├── __init__.py
│ │ ├── items.py
│ │ ├── middlewares.py
│ │ ├── pipelines.py
│ │ ├── settings.py
│ │ └── spiders
│ │ ├── __init__.py
│ │ ├── covidtracking.py
│ │ └── dxy.py
├── tests.py
├── urls.py
└── views.py
├── docs
├── .nojekyll
├── CNAME
├── README.md
├── images
│ ├── dashboard.png
│ └── docs.png
└── index.html
├── index.html
├── requirements.txt
├── setup.cfg
├── setup.py
└── tox.ini
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | demo_pro/__pycache__/
104 | django_covid19/__pycache__/
105 | django_covid19/migrations/
106 | django_covid19/spider/nCoV/__pycache__/
107 | *.sqlite3
108 | *.db
109 | static/
110 |
--------------------------------------------------------------------------------
/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/.nojekyll
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | ncov.leafcoder.cn
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 leafcoder
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include LICENSE
2 | include README.md
3 | include requirements.txt
4 |
5 | recursive-include django_covid19 *
6 | recursive-include docs *
7 | recursive-include demo *
8 | recursive-include demo_proj manage.py
9 | recursive-include demo_proj requirements.txt
10 | recursive-include demo_proj/ncov *
11 |
12 | recursive-exclude demo_proj db.sqlite3
13 | recursive-exclude demo_proj/ncov/__pycache__ *
14 | recursive-exclude django_covid19/migrations *
15 | recursive-exclude django_covid19/__pycache__ *
16 | recursive-exclude django_covid19/management/__pycache__ *
17 | recursive-exclude django_covid19/management/commands/__pycache__ *
18 | recursive-exclude django_covid19/spider/nCoV/__pycache__ *
19 | recursive-exclude django_covid19/spider/nCoV/spiders/__pycache__ *
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
26 |
27 | 由于现在疫情高发地已从国内转向国外,所以本项目也会逐渐增加*数据源*以便提供关于*国外某国某州(某省)*的疫情数据接口。
28 |
29 | 现已新增美国各州最新疫情以及各州每日疫情统计接口,可前往 [中国各省、美国各州接口](http://ncov.leafcoder.cn/docs/#/?id=province) 查看接口文档。
30 |
31 | # 项目文档
32 |
33 | 本项目使用开源文档工具 [docsify](https://docsify.js.org) 编写了一份开发文档。
34 |
35 | 文档将如何安装部署本项目作了详细的描述,开发者可根据自身需求搭建一个属于个人
36 | 的 *新冠肺炎实时接口*,并通过项目提供的爬虫工具实时、定时的更新疫情数据,追踪
37 | 疫情的最新情况。
38 |
39 | 如果开发者本身没有个人的云服务器用来部署本项目,也可以直接调用本项目已部署好
40 | 的实时接口,可用于科研、娱乐、教学等各方面。
41 |
42 | [](http://ncov.leafcoder.cn/docs/)
43 |
44 | # 安装
45 |
46 | 可以通过 `pip` 命令安装:
47 |
48 | pip install django_covid19
49 |
50 | # 初始化数据
51 |
52 | 初始化国家和地区编码数据;
53 |
54 | ./manage.py loaddata initial_data
55 |
56 | # 在线大屏
57 |
58 | 根据已部署的疫情在线接口,并结合使用开源数据大屏项目中的示例代码,本项目提
59 | 供了一个使用本项目接口的数据大屏示例。
60 |
61 | [](http://ncov.leafcoder.cn/demo)
62 |
63 | # 问题相关
64 |
65 | 有任何问题欢迎在 github 中提 issue,或者在文档页面的最后提交[评论](http://ncov.leafcoder.cn/docs/#/?id=detail-1),我会尽快解答。
66 |
67 | * 推荐使用评论方式提问;
68 | * 推荐使用 isuss 提交 bug;
69 |
70 | # 致谢
71 |
72 | * [ccjhpu](https://github.com/ccjhpu):在 [issues-8](https://github.com/leafcoder/django-covid19/issues/8) 中提出了加入各国各州的需求以及数据来源。
73 |
74 | # 致各位
75 |
76 | 如果本项目对你有所帮助,请在[此处](http://ncov.leafcoder.cn/docs/#/?id=detail-1)留下你的项目地址。
77 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/demo/css/app.css:
--------------------------------------------------------------------------------
1 | @charset "utf-8";
2 |
3 | /* global */
4 | * {margin:0;padding:0;box-sizing:border-box;}
5 | html, body {
6 | width:100%;
7 | height:100%;
8 | min-width:1200px;
9 | min-height:600px;
10 | overflow:hidden;
11 | }
12 | body {
13 | position:relative;
14 | font-family:"Microsoft Yahei", Arial, sans-serif;
15 | background:rgb(40, 30, 47) url("../img/bg.png") repeat;
16 | }
17 |
18 | /* layout */
19 | #header {
20 | position:relative;
21 | height:72px;
22 | background:url("../img/header.png") 0 0 / 100% 100% no-repeat;
23 | overflow:hidden;
24 | }
25 | .header-title {line-height:64px;text-align:center;font-size:34px;font-weight:400;color:#fff;}
26 | .header-info {position:absolute;top:32px;font-size:18px;color:#73aae5;}
27 | .header-info-l {left:20px;}
28 | .header-info-r {right:20px;}
29 | #footer {
30 | position:absolute;
31 | bottom:0;
32 | left:0;
33 | right:0;
34 | height:28px;
35 | background:url("../img/footer.png") 0 0 / 100% 100% no-repeat;
36 | }
37 | #container {position:absolute;top:72px;bottom:22px;left:0;right:0;}
38 |
39 | #flexCon {
40 | height:100%;
41 | display:-webkit-flex;
42 | display:-ms-flexbox;
43 | display:flex;
44 | -webkit-flex-direction:column;
45 | -ms-flex-direction:column;
46 | flex-direction:column;
47 | }
48 | .flex-row {
49 | -webkit-flex:1;
50 | -ms-flex:1;
51 | flex:1;
52 | display:-webkit-flex;
53 | display:-ms-flexbox;
54 | display:flex;
55 | }
56 | .flex-cell {-webkit-flex:1;-ms-flex:1;flex:1;padding:15px;}
57 | .flex-cell-l,
58 | .flex-cell-r {-webkit-flex:2;-ms-flex:2;flex:2;}
59 | .flex-cell-c {-webkit-flex:3;-ms-flex:3;flex:3;}
60 | .flex-cell-lc {-webkit-flex:5;-ms-flex:5;flex:5;}
61 |
62 | .chart-wrapper {position:relative;height:100%;}
63 | .chart-title {height:32px;font-size:22px;font-weight:normal;color:#9aa8d4;}
64 | .chart-div {position:absolute;top:32px;bottom:0;left:0;right:0;}
65 |
66 | .data-t {table-layout:fixed;width:100%;height:100%;border-collapse:collapse;}
67 | .data-t th,
68 | .data-t td {min-height:48px;}
69 | .data-t th {width:60px;text-align:center;background:url("../img/icon-bg.png") center / 100% no-repeat;}
70 | .data-t th img {width:30px;height:30px;}
71 | .data-t td {padding-left:15px;}
72 | .data-t p {margin:5px 0;line-height:1;font-size:14px;color:#b0c2f9;}
73 | .data-t p span {font-size:32px;font-weight:bold;color:#fff;}
74 |
75 | /* media query */
76 | @media (max-width:1900px) {
77 | #header {height:48px;}
78 | .header-title {line-height:42px;font-size:24px;}
79 | .header-info {top:17px;font-size:14px;}
80 | .header-info-l {left:15px;}
81 | .header-info-r {right:15px;}
82 | .flex-cell {padding:10px;}
83 | .chart-title {height:24px;font-size:18px;}
84 | .chart-div {top:24px;}
85 | .data-t p span {font-size:24px;}
86 | #footer {height:16px;}
87 | #container {top:48px;bottom:12px;}
88 | }
89 |
90 | /* chart-loader */
91 | .chart-loader {
92 | position:absolute;
93 | top:0;
94 | left:0;
95 | z-index:99;
96 | width:100%;
97 | height:100%;
98 | background:rgba(255, 255, 255, 0);
99 | transition:all .8s;
100 | }
101 | .chart-loader .loader {
102 | position:absolute;
103 | left:50%;
104 | top:50%;
105 | width:60px;
106 | height:60px;
107 | margin:-30px 0 0 -30px;
108 | border:3px solid transparent;
109 | border-top-color:#3498db;
110 | border-radius:50% !important;
111 | -webkit-animation:spin 2s linear infinite;
112 | animation:spin 2s linear infinite;
113 | }
114 | .chart-loader .loader:before {
115 | content:"";
116 | position:absolute;
117 | top:3px;
118 | left:5px;
119 | right:5px;
120 | bottom:5px;
121 | border:3px solid transparent;
122 | border-top-color:#e74c3c;
123 | border-radius:50% !important;
124 | -webkit-animation:spin 3s linear infinite;
125 | animation:spin 3s linear infinite;
126 | }
127 | .chart-loader .loader:after {
128 | content:"";
129 | position:absolute;
130 | top:9px;
131 | left:10px;
132 | right:10px;
133 | bottom:10px;
134 | border:3px solid transparent;
135 | border-top-color:#f9c922;
136 | border-radius:50% !important;
137 | -webkit-animation:spin 1.5s linear infinite;
138 | animation:spin 1.5s linear infinite;
139 | }
140 | .chart-done .chart-loader {display:none;}
141 | @-webkit-keyframes spin {
142 | 0% {
143 | -webkit-transform: rotate(0deg);
144 | -ms-transform: rotate(0deg);
145 | transform: rotate(0deg)
146 | }
147 | 100% {
148 | -webkit-transform: rotate(360deg);
149 | -ms-transform: rotate(360deg);
150 | transform: rotate(360deg)
151 | }
152 | }
153 | @keyframes spin {
154 | 0% {
155 | -webkit-transform: rotate(0deg);
156 | -ms-transform: rotate(0deg);
157 | transform: rotate(0deg)
158 | }
159 | 100% {
160 | -webkit-transform: rotate(360deg);
161 | -ms-transform: rotate(360deg);
162 | transform: rotate(360deg)
163 | }
164 | }
--------------------------------------------------------------------------------
/demo/img/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/bg.png
--------------------------------------------------------------------------------
/demo/img/footer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/footer.png
--------------------------------------------------------------------------------
/demo/img/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/header.png
--------------------------------------------------------------------------------
/demo/img/icon-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-01.png
--------------------------------------------------------------------------------
/demo/img/icon-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-02.png
--------------------------------------------------------------------------------
/demo/img/icon-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-03.png
--------------------------------------------------------------------------------
/demo/img/icon-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-04.png
--------------------------------------------------------------------------------
/demo/img/icon-05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-05.png
--------------------------------------------------------------------------------
/demo/img/icon-06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-06.png
--------------------------------------------------------------------------------
/demo/img/icon-07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-07.png
--------------------------------------------------------------------------------
/demo/img/icon-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/icon-bg.png
--------------------------------------------------------------------------------
/demo/img/thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo/img/thumb.jpg
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 新冠肺炎(2019-nCoV)疫情大屏
8 |
9 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
现存确诊数排行前 10 位的国家
36 |
39 |
40 |
41 |
42 |
43 |
国内各省、自治区、直辖市疫情
44 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
576 |
577 |
578 |
--------------------------------------------------------------------------------
/demo/js/countUp.min.js:
--------------------------------------------------------------------------------
1 | !function(a,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n(require,exports,module):a.CountUp=n()}(this,function(a,n,t){var e=function(a,n,t,e,i,r){function o(a){var n,t,e,i,r,o,s=a<0;if(a=Math.abs(a).toFixed(l.decimals),a+="",n=a.split("."),t=n[0],e=n.length>1?l.options.decimal+n[1]:"",l.options.useGrouping){for(i="",r=0,o=t.length;rl.endVal,l.frameVal=l.startVal,l.initialized=!0,!0):(l.error="[CountUp] startVal ("+n+") or endVal ("+t+") is not a number",!1)):(l.error="[CountUp] target is null or undefined",!1))},l.printValue=function(a){var n=l.options.formattingFn(a);"INPUT"===l.d.tagName?this.d.value=n:"text"===l.d.tagName||"tspan"===l.d.tagName?this.d.textContent=n:this.d.innerHTML=n},l.count=function(a){l.startTime||(l.startTime=a),l.timestamp=a;var n=a-l.startTime;l.remaining=l.duration-n,l.options.useEasing?l.countDown?l.frameVal=l.startVal-l.options.easingFn(n,0,l.startVal-l.endVal,l.duration):l.frameVal=l.options.easingFn(n,l.startVal,l.endVal-l.startVal,l.duration):l.countDown?l.frameVal=l.startVal-(l.startVal-l.endVal)*(n/l.duration):l.frameVal=l.startVal+(l.endVal-l.startVal)*(n/l.duration),l.countDown?l.frameVal=l.frameVall.endVal?l.endVal:l.frameVal,l.frameVal=Math.round(l.frameVal*l.dec)/l.dec,l.printValue(l.frameVal),nl.endVal,l.rAF=requestAnimationFrame(l.count))}},l.initialize()&&l.printValue(l.startVal)};return e});
--------------------------------------------------------------------------------
/demo/js/echarts-theme-shine.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {if (typeof define === 'function' && define.amd) {
2 | // AMD. Register as an anonymous module.
3 | define(['exports', 'echarts'], factory);
4 | } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
5 | // CommonJS
6 | factory(exports, require('echarts'));
7 | } else {
8 | // Browser globals
9 | factory({}, root.echarts);
10 | }
11 | }(this, function (exports, echarts) {
12 | var log = function (msg) {
13 | if (typeof console !== 'undefined') {
14 | console && console.error && console.error(msg);
15 | }
16 | };
17 | if (!echarts) {
18 | log('ECharts is not Loaded');
19 | return;
20 | }
21 |
22 | var colorPalette = [
23 | '#c12e34','#e6b600','#0098d9','#2b821d',
24 | '#005eaa','#339ca8','#cda819','#32a487'
25 | ];
26 |
27 | var theme = {
28 |
29 | color: colorPalette,
30 |
31 | title: {
32 | textStyle: {
33 | fontWeight: 'normal'
34 | }
35 | },
36 |
37 | visualMap: {
38 | color:['#1790cf','#a2d4e6']
39 | },
40 |
41 | toolbox: {
42 | iconStyle: {
43 | normal: {
44 | borderColor: '#06467c'
45 | }
46 | }
47 | },
48 |
49 | tooltip: {
50 | backgroundColor: 'rgba(0,0,0,0.6)'
51 | },
52 |
53 | dataZoom: {
54 | dataBackgroundColor: '#dedede',
55 | fillerColor: 'rgba(154,217,247,0.2)',
56 | handleColor: '#005eaa'
57 | },
58 |
59 | timeline: {
60 | lineStyle: {
61 | color: '#005eaa'
62 | },
63 | controlStyle: {
64 | normal: {
65 | color: '#005eaa',
66 | borderColor: '#005eaa'
67 | }
68 | }
69 | },
70 |
71 | candlestick: {
72 | itemStyle: {
73 | normal: {
74 | color: '#c12e34',
75 | color0: '#2b821d',
76 | lineStyle: {
77 | width: 1,
78 | color: '#c12e34',
79 | color0: '#2b821d'
80 | }
81 | }
82 | }
83 | },
84 |
85 | graph: {
86 | color: colorPalette
87 | },
88 |
89 | map: {
90 | label: {
91 | normal: {
92 | textStyle: {
93 | color: '#c12e34'
94 | }
95 | },
96 | emphasis: {
97 | textStyle: {
98 | color: '#c12e34'
99 | }
100 | }
101 | },
102 | itemStyle: {
103 | normal: {
104 | borderColor: '#eee',
105 | areaColor: '#ddd'
106 | },
107 | emphasis: {
108 | areaColor: '#e6b600'
109 | }
110 | }
111 | },
112 |
113 | gauge: {
114 | axisLine: {
115 | show: true,
116 | lineStyle: {
117 | color: [[0.2, '#2b821d'],[0.8, '#005eaa'],[1, '#c12e34']],
118 | width: 5
119 | }
120 | },
121 | axisTick: {
122 | splitNumber: 10,
123 | length:8,
124 | lineStyle: {
125 | color: 'auto'
126 | }
127 | },
128 | axisLabel: {
129 | textStyle: {
130 | color: 'auto'
131 | }
132 | },
133 | splitLine: {
134 | length: 12,
135 | lineStyle: {
136 | color: 'auto'
137 | }
138 | },
139 | pointer: {
140 | length: '90%',
141 | width: 3,
142 | color: 'auto'
143 | },
144 | title: {
145 | textStyle: {
146 | color: '#333'
147 | }
148 | },
149 | detail: {
150 | textStyle: {
151 | color: 'auto'
152 | }
153 | }
154 | }
155 | };
156 | echarts.registerTheme('shine', theme);
157 | }));
--------------------------------------------------------------------------------
/demo_proj/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 | # import django_covid19 from parent dir
7 | sys.path.insert(0, '..')
8 |
9 |
10 | def main():
11 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ncov.settings')
12 | try:
13 | from django.core.management import execute_from_command_line
14 | except ImportError as exc:
15 | raise ImportError(
16 | "Couldn't import Django. Are you sure it's installed and "
17 | "available on your PYTHONPATH environment variable? Did you "
18 | "forget to activate a virtual environment?"
19 | ) from exc
20 | execute_from_command_line(sys.argv)
21 |
22 |
23 | if __name__ == '__main__':
24 | main()
25 |
--------------------------------------------------------------------------------
/demo_proj/ncov/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/demo_proj/ncov/__init__.py
--------------------------------------------------------------------------------
/demo_proj/ncov/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for ncov project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.2.10.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.2/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.2/ref/settings/
11 | """
12 |
13 | # insert project path here
14 | import sys; sys.path.insert(0, '..')
15 |
16 | import os
17 |
18 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
19 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
20 |
21 |
22 | # Quick-start development settings - unsuitable for production
23 | # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
24 |
25 | # SECURITY WARNING: keep the secret key used in production secret!
26 | SECRET_KEY = 'jua+&*ti%!$hnt6zxndu09jw&oai1d+wb^znq&$kb&9_j6v60!'
27 |
28 | # SECURITY WARNING: don't run with debug turned on in production!
29 | DEBUG = True
30 |
31 | ALLOWED_HOSTS = ['*']
32 |
33 |
34 | # Application definition
35 |
36 | INSTALLED_APPS = [
37 | 'django.contrib.admin',
38 | 'django.contrib.auth',
39 | 'django.contrib.contenttypes',
40 | 'django.contrib.sessions',
41 | 'django.contrib.messages',
42 | 'django.contrib.staticfiles',
43 | # set by user
44 | 'corsheaders',
45 | 'django_crontab',
46 | 'rest_framework',
47 | 'django_filters',
48 | 'django_covid19'
49 | ]
50 |
51 | MIDDLEWARE = [
52 | 'django.middleware.security.SecurityMiddleware',
53 | 'django.contrib.sessions.middleware.SessionMiddleware',
54 | 'corsheaders.middleware.CorsMiddleware', # 新增跨域部分
55 | 'django.middleware.common.CommonMiddleware',
56 | 'django.middleware.csrf.CsrfViewMiddleware',
57 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
58 | 'django.contrib.messages.middleware.MessageMiddleware',
59 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
60 | ]
61 |
62 | ROOT_URLCONF = 'ncov.urls'
63 |
64 | TEMPLATES = [
65 | {
66 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
67 | 'DIRS': [],
68 | 'APP_DIRS': True,
69 | 'OPTIONS': {
70 | 'context_processors': [
71 | 'django.template.context_processors.debug',
72 | 'django.template.context_processors.request',
73 | 'django.contrib.auth.context_processors.auth',
74 | 'django.contrib.messages.context_processors.messages',
75 | ],
76 | },
77 | },
78 | ]
79 |
80 | WSGI_APPLICATION = 'ncov.wsgi.application'
81 |
82 |
83 | # Database
84 | # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
85 |
86 | DATABASES = {
87 | 'default': {
88 | 'ENGINE': 'django.db.backends.sqlite3',
89 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
90 | }
91 | }
92 |
93 |
94 | # Password validation
95 | # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
96 |
97 | AUTH_PASSWORD_VALIDATORS = [
98 | {
99 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
100 | },
101 | {
102 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
103 | },
104 | {
105 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
106 | },
107 | {
108 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
109 | },
110 | ]
111 |
112 |
113 | # Internationalization
114 | # https://docs.djangoproject.com/en/2.2/topics/i18n/
115 |
116 | LANGUAGE_CODE = 'zh-Hans'
117 |
118 | TIME_ZONE = 'UTC'
119 |
120 | USE_I18N = True
121 |
122 | USE_L10N = True
123 |
124 | USE_TZ = True
125 |
126 |
127 | # Static files (CSS, JavaScript, Images)
128 | # https://docs.djangoproject.com/en/2.2/howto/static-files/
129 |
130 | STATIC_URL = '/static/'
131 |
132 |
133 | # Setting by customer
134 |
135 | REST_FRAMEWORK = {
136 | 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
137 | 'DEFAULT_RENDERER_CLASSES': (
138 | 'rest_framework.renderers.JSONRenderer',
139 | )
140 | }
141 |
142 | CACHES = {
143 | 'default': {
144 | 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
145 | 'LOCATION': '/var/tmp/ncov_cache',
146 | 'TIMEOUT': 3600,
147 | 'OPTIONS': {
148 | 'MAX_ENTRIES': 20000
149 | }
150 | }
151 | }
152 |
153 | # 跨域增加忽略
154 | CORS_ALLOW_CREDENTIALS = True
155 | CORS_ORIGIN_ALLOW_ALL = True
156 |
157 | CORS_ALLOW_METHODS = (
158 | 'DELETE',
159 | 'GET',
160 | 'OPTIONS',
161 | 'PATCH',
162 | 'POST',
163 | 'PUT',
164 | 'VIEW',
165 | )
166 |
167 | CORS_ALLOW_HEADERS = (
168 | 'XMLHttpRequest',
169 | 'X_FILENAME',
170 | 'accept-encoding',
171 | 'authorization',
172 | 'content-type',
173 | 'dnt',
174 | 'origin',
175 | 'user-agent',
176 | 'x-csrftoken',
177 | 'x-requested-with',
178 | 'Pragma',
179 | )
180 |
181 | # 静态文件目录
182 | STATIC_ROOT = os.path.join(BASE_DIR, 'static')
183 |
184 | CRONTAB_LOCK_JOBS = True
185 | CRONJOBS = (
186 | # 每分钟抓取丁香园数据一次
187 | ('*/1 * * * *', 'django.core.management.call_command', ['crawl', 'dxy']),
188 |
189 | # 每隔1小时开始抓取 covidtracking 数据一次
190 | ('*/60 * * * *', 'django.core.management.call_command', ['crawl', 'covidtracking']),
191 | )
192 |
193 | # scrapy 日志文件路径
194 | SCRAPY_LOG_FILE = '/var/tmp/django-covid19-spider.log'
--------------------------------------------------------------------------------
/demo_proj/ncov/urls.py:
--------------------------------------------------------------------------------
1 | """ncov URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.2/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import include, path
18 | from django.views.static import serve
19 | from django.conf import settings
20 | from django.conf.urls import url
21 |
22 |
23 | urlpatterns = [
24 | path('admin/', admin.site.urls),
25 | path('api/', include('django_covid19.urls', namespace='django_covid19')),
26 | url(r'^static/(?P.*)$', serve, {'document_root': settings.STATIC_ROOT})
27 | ]
--------------------------------------------------------------------------------
/demo_proj/ncov/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for ncov project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ncov.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/demo_proj/requirements.txt:
--------------------------------------------------------------------------------
1 | attrs==19.3.0
2 | Automat==20.2.0
3 | cffi==1.14.0
4 | constantly==15.1.0
5 | cryptography==3.3.2
6 | cssselect==1.1.0
7 | Django==2.2.20
8 | django-cors-headers==3.3.0
9 | django-covid19
10 | django-crontab==0.7.1
11 | django-filter==2.2.0
12 | django-mysql==3.5.0
13 | djangorestframework==3.11.2
14 | hyperlink==19.0.0
15 | idna==2.9
16 | incremental==17.5.0
17 | lxml==4.6.3
18 | parsel==1.6.0
19 | Protego==0.1.16
20 | pyasn1==0.4.8
21 | pyasn1-modules==0.2.8
22 | pycparser==2.20
23 | PyDispatcher==2.0.5
24 | PyHamcrest==2.0.2
25 | pyOpenSSL==19.1.0
26 | pytz==2020.1
27 | queuelib==1.5.0
28 | Scrapy==2.0.1
29 | scrapy-djangoitem==1.1.1
30 | service-identity==18.1.0
31 | six==1.15.0
32 | sqlparse==0.3.1
33 | Twisted==20.3.0
34 | w3lib==1.22.0
35 | zope.interface==5.1.0
36 |
--------------------------------------------------------------------------------
/django_covid19/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'django_covid19.apps.DjangoCovid19Config'
--------------------------------------------------------------------------------
/django_covid19/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.urls import reverse
3 | from django.utils.html import format_html
4 | from django.utils.safestring import mark_safe
5 | from django.utils.translation import ugettext_lazy as _
6 |
7 | from . import models
8 | import json
9 | # Register your models here.
10 |
11 |
12 | class BaseAdmin(admin.ModelAdmin):
13 |
14 | list_per_page = 50
15 |
16 | list_max_show_all = 200
17 |
18 | show_full_result_count = False
19 |
20 | preserve_filters = True
21 |
22 |
23 | @admin.register(models.Statistics)
24 | class StatisticsAdmin(BaseAdmin):
25 |
26 | list_display = (
27 | 'id', 'jsonGlobalStatistics', 'jsonDomesticStatistics',
28 | 'jsonInternationalStatistics', 'modifyTime', 'crawlTime'
29 | )
30 | search_fields = ('crawlTime', 'modifyTime')
31 |
32 | def jsonGlobalStatistics(self, obj):
33 | return self.to_json(obj.globalStatistics)
34 | jsonGlobalStatistics.short_description = _('globalStatistics')
35 | jsonGlobalStatistics.admin_order_field = 'globalStatistics'
36 |
37 | def jsonDomesticStatistics(self, obj):
38 | return self.to_json(obj.domesticStatistics)
39 | jsonDomesticStatistics.short_description = _('domesticStatistics')
40 | jsonDomesticStatistics.admin_order_field = 'domesticStatistics'
41 |
42 | def jsonInternationalStatistics(self, obj):
43 | return self.to_json(obj.internationalStatistics)
44 | jsonInternationalStatistics.short_description \
45 | = _('internationalStatistics')
46 | jsonInternationalStatistics.admin_order_field \
47 | = 'internationalStatistics'
48 |
49 | def to_json(self, data):
50 | try:
51 | data = json.loads(data)
52 | except:
53 | return
54 | result = []
55 | for k, v in sorted(data.items()):
56 | result.append(format_html('{}: {}', k, v))
57 | return mark_safe(format_html(
58 | '{}
', format_html('
'.join(result))))
59 |
60 | @admin.register(models.City)
61 | class CityAdmin(BaseAdmin):
62 |
63 | list_display = (
64 | 'countryCode', 'provinceName', 'provinceCode', 'cityName',
65 | 'currentConfirmedCount', 'confirmedCount', 'suspectedCount',
66 | 'curedCount', 'deadCount', 'createTime', 'modifyTime'
67 | )
68 | search_fields = (
69 | 'cityName', 'countryCode', 'provinceCode', 'provinceName'
70 | )
71 |
72 |
73 | @admin.register(models.Province)
74 | class ProvinceAdmin(BaseAdmin):
75 |
76 | list_display = (
77 | 'countryCode', 'provinceName',
78 | 'currentConfirmedCount', 'confirmedCount', 'suspectedCount',
79 | 'curedCount', 'deadCount', 'createTime', 'modifyTime'
80 | )
81 | search_fields = ('provinceName', 'countryCode')
82 |
83 |
84 | @admin.register(models.Country)
85 | class CountryAdmin(BaseAdmin):
86 |
87 | list_display = (
88 | 'continents', 'countryCode', 'countryName', 'countryFullName',
89 | 'currentConfirmedCount', 'confirmedCount', 'suspectedCount',
90 | 'curedCount', 'deadCount', 'createTime', 'modifyTime'
91 | )
92 | search_fields = (
93 | 'continents', 'countryFullName', 'countryCode', 'countryName'
94 | )
95 |
96 |
97 | @admin.register(models.CountryCode)
98 | class CountryCodeAdmin(BaseAdmin):
99 |
100 | list_display = (
101 | 'numericCode', 'countryCode', 'shortCountryCode', 'countryName',
102 | 'englishCountryName', 'englishCountryFullName', 'comment'
103 | )
104 | search_fields = (
105 | 'numericCode', 'countryCode', 'shortCountryCode', 'countryName',
106 | 'englishCountryName', 'englishCountryFullName', 'comment'
107 | )
108 |
109 |
110 |
--------------------------------------------------------------------------------
/django_covid19/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 | from django.utils.translation import ugettext_lazy as _
3 |
4 |
5 | class DjangoCovid19Config(AppConfig):
6 |
7 | name = 'django_covid19'
8 | verbose_name = _('django_covid19')
9 |
10 | def ready(self):
11 | import django_covid19.signals
--------------------------------------------------------------------------------
/django_covid19/data/CountryCodes.csv:
--------------------------------------------------------------------------------
1 | serialNumber,countryName,englishCountryName,englishCountryFullName,shortCountryCode,countryCode,numericCode,comment
2 | 1,阿富汗,Afghanistan,the Islamic Republic of Afghanistan,AF,AFG,4,
3 | 2,奥兰群岛,Aland Islands,,AX,ALA,248,ISO 3166-1:2006新增
4 | 3,阿尔巴尼亚,Albania,the Republic of Albania,AL,ALB,8,
5 | 4,阿尔及利亚,Algeria,the People's Democratic Republic of Algeria,DZ,DZA,12,
6 | 5,美属萨摩亚,American Samoa,,AS,ASM,16,
7 | 6,安道尔,Andorra,the Principality of Andorra,AD,AND,20,
8 | 7,安哥拉,Angola,the Republic of Angola,AO,AGO,24,
9 | 8,安圭拉,Anguilla,,AI,AIA,660,
10 | 9,南极洲,Antarctica,,AQ,ATA,10,
11 | 10,安提瓜和巴布达,Antigua and Barbuda,,AG,ATG,28,
12 | 11,阿根廷,Argentina,the Argentine Republic,AR,ARG,32,
13 | 12,亚美尼亚,Armenia,the Republic of Armenia,AM,ARM,51,
14 | 13,阿鲁巴,Aruba,,AW,ABW,533,
15 | 14,澳大利亚,Australia,,AU,AUS,36,
16 | 15,奥地利,Austria,the Republic of Austria,AT,AUT,40,
17 | 16,阿塞拜疆,Azerbaijan,the Republic of Azerbaijan,AZ,AZE,31,
18 | 17,巴哈马,Bahamas (The),the Commonwealth of The Bahamas,BS,BHS,44,
19 | 18,巴林,Bahrain,the Kingdom of Bahrain,BH,BHR,48,
20 | 19,孟加拉国,Bangladesh,the People's Republic of Bangladesh,BD,BGD,50,
21 | 20,巴巴多斯,Barbados,,BB,BRB,52,
22 | 21,白俄罗斯,Belarus,the Republic of Belarus,BY,BLR,112,
23 | 22,比利时,Belgium,the Kingdom of Belgium,BE,BEL,56,
24 | 23,伯利兹,Belize,,BZ,BLZ,84,
25 | 24,贝宁,Benin,the Republic of Benin,BJ,BEN,204,
26 | 25,百慕大,Bermuda,,BM,BMU,60,
27 | 26,不丹,Bhutan,the Kingdom of Bhutan,BT,BTN,64,
28 | 27,玻利维亚,Bolivia,the Republic of Bolivia,BO,BOL,68,
29 | 28,波黑,Bosnia and Herzegovina,,BA,BIH,70,
30 | 29,博茨瓦纳,Botswana,the Republic of Botswana,BW,BWA,72,
31 | 30,布维岛,Bouvet Island,,BV,BVT,74,
32 | 31,巴西,Brazil,the Federative Republic of Brazil,BR,BRA,76,
33 | 32,英属印度洋领地,British Indian Ocean Territory (the),,IO,IOT,86,
34 | 33,文莱,Brunei Darussalam,,BN,BRN,96,
35 | 34,保加利亚,Bulgaria,the Republic of Bulgaria,BG,BGR,100,
36 | 35,布基纳法索,Burkina Faso,Burkina Faso,BF,BFA,854,
37 | 36,布隆迪,Burundi,the Republic of Burundi,BI,BDI,108,
38 | 37,柬埔寨,Cambodia,the Kingdom of Cambodia,KH,KHM,116,
39 | 38,喀麦隆,Cameroon,the Republic of Cameroon,CM,CMR,120,
40 | 39,加拿大,Canada,,CA,CAN,124,
41 | 40,佛得角,Cape Verde,the Republic of Cape Verde,CV,CPV,132,
42 | 41,开曼群岛,Cayman Islands (the),,KY,CYM,136,
43 | 42,中非,Central African Republic (the),the Central African Republic,CF,CAF,140,
44 | 43,乍得,Chad,the Republic of Chad,TD,TCD,148,
45 | 44,智利,Chile,the Republic of Chile,CL,CHL,152,
46 | 45,中国,China,the People's Republic of China,CN,CHN,156,
47 | 46,圣诞岛,Christmas Island,,CX,CXR,162,
48 | 47,科科斯(基林)群岛,Cocos (Keeling) Islands (the),,CC,CCK,166,
49 | 48,哥伦比亚,Colombia,the Republic of Colombia,CO,COL,170,
50 | 49,科摩罗,Comoros,the Union of the Comoros,KM,COM,174,
51 | 50,刚果(布),Congo,the Republic of the Congo,CG,COG,178,
52 | 51,刚果(金),Congo (the Democratic Republic of the),the Democratic Republic of the Congo,CD,COD,180,
53 | 52,库克群岛,Cook Islands (the),,CK,COK,184,
54 | 53,哥斯达黎加,Costa Rica,the Republic of Costa Rica,CR,CRI,188,
55 | 54,科特迪瓦,Côte d'Ivoire,the Republic of Côte d'Ivoire,CI,CIV,384,
56 | 55,克罗地亚,Croatia,the Republic of Croatia,HR,HRV,191,
57 | 56,古巴,Cuba,the Republic of Cuba,CU,CUB,192,
58 | 57,塞浦路斯,Cyprus,the Republic of Cyprus,CY,CYP,196,
59 | 58,捷克,Czech Republic (the),the Czech Republic,CZ,CZE,203,
60 | 59,丹麦,Denmark,the Kingdom of Denmark,DK,DNK,208,
61 | 60,吉布提,Djibouti,the Republic of Djibouti,DJ,DJI,262,
62 | 61,多米尼克,Dominica,the Commonwealth of Dominica,DM,DMA,212,
63 | 62,多米尼加,Dominican Republic (the),the Dominican Republic,DO,DOM,214,
64 | 63,厄瓜多尔,Ecuador,the Republic of Ecuador,EC,ECU,218,
65 | 64,埃及,Egypt,the Arab Republic of Egypt,EG,EGY,818,
66 | 65,萨尔瓦多,El Salvador,the Republic of El Salvador,SV,SLV,222,
67 | 66,赤道几内亚,Equatorial Guinea,the Republic of Equatorial Guinea,GQ,GNQ,226,
68 | 67,厄立特里亚,Eritrea,,ER,ERI,232,
69 | 68,爱沙尼亚,Estonia,the Republic of Estonia,EE,EST,233,
70 | 69,埃塞俄比亚,Ethiopia,the Federal Democratic Republic of Ethiopia,ET,ETH,231,
71 | 70,福克兰群岛(马尔维纳斯),Falkland Islands (the) [Malvinas],,FK,FLK,238,
72 | 71,法罗群岛,Faroe Islands (the),,FO,FRO,234,
73 | 72,斐济,Fiji,the Republic of the Fiji Islands,FJ,FJI,242,
74 | 73,芬兰,Finland,the Republic of Finland,FI,FIN,246,
75 | 74,法国,France,the French Republic,FR,FRA,250,
76 | 75,法属圭亚那,French Guiana,,GF,GUF,254,
77 | 76,法属波利尼西亚,French Polynesia,,PF,PYF,258,
78 | 77,法属南部领地,French Southern Territories (the),,TF,ATF,260,
79 | 78,加蓬,Gabon,the Gabonese Republic,GA,GAB,266,
80 | 79,冈比亚,Gambia (The),the Republic of The Gambia,GM,GMB,270,
81 | 80,格鲁吉亚,Georgia,,GE,GEO,268,
82 | 81,德国,Germany,he Federal Republic of Germany,DE,DEU,276,
83 | 82,加纳,Ghana,the Republic of Ghana,GH,GHA,288,
84 | 83,直布罗陀,Gibraltar,,GI,GIB,292,
85 | 84,希腊,Greece,the Hellenic Republic,GR,GRC,300,
86 | 85,格陵兰,Greenland,,GL,GRL,304,
87 | 86,格林纳达,Grenada,,GD,GRD,308,
88 | 87,瓜德罗普,Guadeloupe,,GP,GLP,312,
89 | 88,关岛,Guam,,GU,GUM,316,
90 | 89,危地马拉,Guatemala,the Republic of Guatemala,GT,GTM,320,
91 | 90,格恩西岛,Guernsey,,GG,GGY,831,ISO 3166-1:2006新增
92 | 91,几内亚,Guinea,the Republic of Guinea,GN,GIN,324,
93 | 92,几内亚比绍,Guinea-Bissau,the Republic of Guinea-Bissau,GW,GNB,624,
94 | 93,圭亚那,Guyana,the Republic of Guyana,GY,GUY,328,
95 | 94,海地,Haiti,the Republic of Haiti,HT,HTI,332,
96 | 95,赫德岛和麦克唐纳岛,Heard Island and McDonald Islands,,HM,HMD,334,
97 | 96,梵蒂冈,Holy See (the) [Vatican City State],,VA,VAT,336,ISO 3166.1:2006调整英文名称,代码未变
98 | 97,洪都拉斯,Honduras,the Republic of Honduras,HN,HND,340,
99 | 98,香港,Hong Kong,the Hong Kong Special Administrative Region of China,HK,HKG,344,
100 | 99,匈牙利,Hungary,the Republic of Hungary,HU,HUN,348,
101 | 100,冰岛,Iceland,the Republic of Iceland,IS,ISL,352,
102 | 101,印度,India,the Republic of India,IN,IND,356,
103 | 102,印度尼西亚,Indonesia,the Republic of Indonesia,ID,IDN,360,
104 | 103,伊朗,Iran (the Islamic Republic of),the Islamic Republic of Iran,IR,IRN,364,
105 | 104,伊拉克,Iraq,the Republic of Iraq,IQ,IRQ,368,
106 | 105,爱尔兰,Ireland,,IE,IRL,372,
107 | 106,英国属地曼岛,Isle of Man,,IM,IMN,833,ISO 3166-1:2006新增
108 | 107,以色列,Israel,the State of Israel,IL,ISR,376,
109 | 108,意大利,Italy,the Republic of Italy,IT,ITA,380,
110 | 109,牙买加,Jamaica,,JM,JAM,388,
111 | 110,日本,Japan,,JP,JPN,392,
112 | 111,泽西岛,Jersey,,JE,JEY,832,ISO 3166-1:2006新增
113 | 112,约旦,Jordan,the Hashemite Kingdom of Jordan,JO,JOR,400,
114 | 113,哈萨克斯坦,Kazakhstan,the Republic of Kazakhstan,KZ,KAZ,398,
115 | 114,肯尼亚,Kenya,the Republic of Kenya,KE,KEN,404,
116 | 115,基里巴斯,Kiribati,the Republic of Kiribati,KI,KIR,296,
117 | 116,朝鲜,Korea (the Democratic People's Republic of),the Democratic People's Republic of Korea,KP,PRK,408,
118 | 117,韩国,Korea (the Republic of),the Republic of Korea,KR,KOR,410,
119 | 118,科威特,Kuwait,he State of Kuwait,KW,KWT,414,
120 | 119,吉尔吉斯斯坦,Kyrgyzstan,the Kyrgyz Republic,KG,KGZ,417,
121 | 120,老挝,Lao People's Democratic Republic (the),the Lao People's Democratic Republic,LA,LAO,418,
122 | 121,拉脱维亚,Latvia,the Republic of Latvia,LV,LVA,428,
123 | 122,黎巴嫩,Lebanon,the Lebanese Republic,LB,LBN,422,
124 | 123,莱索托,Lesotho,the Kingdom of Lesotho,LS,LSO,426,
125 | 124,利比里亚,Liberia,the Republic of Liberia,LR,LBR,430,
126 | 125,利比亚,Libyan Arab Jamahiriya (the),the Socialist People's Libyan Arab Jamahiriya,LY,LBY,434,
127 | 126,列支敦士登,Liechtenstein,the Principality of Liechtenstein,LI,LIE,438,
128 | 127,立陶宛,Lithuania,the Republic of Lithuania,LT,LTU,440,
129 | 128,卢森堡,Luxembourg,the Grand Duchy of Luxembourg,LU,LUX,442,
130 | 129,澳门,Macao,Macao Special Administrative Region of China,MO,MAC,446,
131 | 130,前南马其顿,Macedonia (the former Yugoslav Republic of),the former Yugoslav Republic of Macedonia,MK,MKD,807,
132 | 131,马达加斯加,Madagascar,the Republic of Madagascar,MG,MDG,450,
133 | 132,马拉维,Malawi,the Republic of Malawi,MW,MWI,454,
134 | 133,马来西亚,Malaysia,,MY,MYS,458,
135 | 134,马尔代夫,Maldives,the Republic of Maldives,MV,MDV,462,
136 | 135,马里,Mali,the Republic of Mali,ML,MLI,466,
137 | 136,马耳他,Malta,the Republic of Malta,MT,MLT,470,
138 | 137,马绍尔群岛,Marshall Islands (the),the Republic of the Marshall Islands,MH,MHL,584,
139 | 138,马提尼克,Martinique,,MQ,MTQ,474,
140 | 139,毛利塔尼亚,Mauritania,the Islamic Republic of Mauritania,MR,MRT,478,
141 | 140,毛里求斯,Mauritius,the Republic of Mauritius,MU,MUS,480,
142 | 141,马约特,Mayotte,,YT,MYT,175,
143 | 142,墨西哥,Mexico,the United Mexican States,MX,MEX,484,
144 | 143,密克罗尼西亚联邦,Micronesia (the Federated States of),the Federated States of Micronesia,FM,FSM,583,
145 | 144,摩尔多瓦,Moldova (the Republic of),the Republic of Moldova,MD,MDA,498,
146 | 145,摩纳哥,Monaco,the Principality of Monaco,MC,MCO,492,
147 | 146,蒙古,Mongolia,,MN,MNG,496,
148 | 147,黑山,Montenegro,he Republic of Montenegro,ME,MNE,499,ISO 3166.1:2006新增
149 | 148,蒙特塞拉特,Montserrat,,MS,MSR,500,
150 | 149,摩洛哥,Morocco,the Kingdom of Morocco,MA,MAR,504,
151 | 150,莫桑比克,Mozambique,the Republic of Mozambique,MZ,MOZ,508,
152 | 151,缅甸,Myanmar,the Union of Myanmar,MM,MMR,104,
153 | 152,纳米比亚,Namibia,the Republic of Namibia,NA,NAM,516,
154 | 153,瑙鲁,Nauru,the Republic of Nauru,NR,NRU,520,
155 | 154,尼泊尔,Nepal,Nepal,NP,NPL,524,
156 | 155,荷兰,Netherlands (the),the Kingdom of the Netherlands,NL,NLD,528,
157 | 156,荷属安的列斯,Netherlands Antilles (the),,AN,ANT,530,
158 | 157,新喀里多尼亚,New Caledonia,,NC,NCL,540,
159 | 158,新西兰,New Zealand,,NZ,NZL,554,
160 | 159,尼加拉瓜,Nicaragua,the Republic of Nicaragua,NI,NIC,558,
161 | 160,尼日尔,Niger (the),the Republic of the Niger,NE,NER,562,
162 | 161,尼日利亚,Nigeria,the Federal Republic of Nigeria,NG,NGA,566,
163 | 162,纽埃,Niue,the Republic of Niue,NU,NIU,570,
164 | 163,诺福克岛,Norfolk Island,,NF,NFK,574,
165 | 164,北马里亚纳,Northern Mariana Islands (the),the Commonwealth of the Northern Mariana Islands,MP,MNP,580,
166 | 165,挪威,Norway,the Kingdom of Norway,NO,NOR,578,
167 | 166,阿曼,Oman,the Sultanate of Oman,OM,OMN,512,
168 | 167,巴基斯坦,Pakistan,the Islamic Republic of Pakistan,PK,PAK,586,
169 | 168,帕劳,Palau,the Republic of Palau,PW,PLW,585,
170 | 169,巴勒斯坦,Palestinian Territory (the Occupied),the Occupied Palestinian Territory,PS,PSE,275,
171 | 170,巴拿马,Panama,the Republic of Panama,PA,PAN,591,
172 | 171,巴布亚新几内亚,Papua New Guinea,,PG,PNG,598,
173 | 172,巴拉圭,Paraguay,the Republic of Paraguay,PY,PRY,600,
174 | 173,秘鲁,Peru,the Republic of Peru,PE,PER,604,
175 | 174,菲律宾,Philippines (the),the Republic of the Philippines,PH,PHL,608,
176 | 175,皮特凯恩,Pitcairn,,PN,PCN,612,
177 | 176,波兰,Poland,the Republic of Poland,PL,POL,616,
178 | 177,葡萄牙,Portugal,the Portuguese Republic,PT,PRT,620,
179 | 178,波多黎各,Puerto Rico,,PR,PRI,630,
180 | 179,卡塔尔,Qatar,the State of Qatar,QA,QAT,634,
181 | 180,留尼汪,Réunion,,RE,REU,638,
182 | 181,罗马尼亚,Romania,,RO,ROU,642,
183 | 182,俄罗斯联邦,Russian Federation (the),the Russian Federation,RU,RUS,643,
184 | 183,卢旺达,Rwanda,the Republic of Rwanda,RW,RWA,646,
185 | 184,圣赫勒拿,Saint Helena,,SH,SHN,654,
186 | 185,圣基茨和尼维斯,Saint Kitts and Nevis,,KN,KNA,659,
187 | 186,圣卢西亚,Saint Lucia,,LC,LCA,662,
188 | 187,圣皮埃尔和密克隆,Saint Pierre and Miquelon,,PM,SPM,666,
189 | 188,圣文森特和格林纳丁斯,Saint Vincent and the Grenadines,,VC,VCT,670,
190 | 189,萨摩亚,Samoa,the Independent State of Samoa,WS,WSM,882,
191 | 190,圣马力诺,San Marino,the Republic of San Marino,SM,SMR,674,
192 | 191,圣多美和普林西比,Sao Tome and Principe,the Democratic Republic of Sao Tome and Principe,ST,STP,678,
193 | 192,沙特阿拉伯,Saudi Arabia,the Kingdom of Saudi Arabia,SA,SAU,682,
194 | 193,塞内加尔,Senegal,the Republic of Senegal,SN,SEN,686,
195 | 194,塞尔维亚,Serbia,the Republic of Serbia,RS,SRB,688,ISO 3166.1-2006新增
196 | 195,塞舌尔,Seychelles,the Republic of Seychelles,SC,SYC,690,
197 | 196,塞拉利昂,Sierra Leone,the Republic of Sierra Leone,SL,SLE,694,
198 | 197,新加坡,Singapore,the Republic of Singapore,SG,SGP,702,
199 | 198,斯洛伐克,Slovakia,the Slovak Republic,SK,SVK,703,
200 | 199,斯洛文尼亚,Slovenia,the Republic of Slovenia,SI,SVN,705,
201 | 200,所罗门群岛,Solomon Islands (the),,SB,SLB,90,
202 | 201,索马里,Somalia,the Somali Republic,SO,SOM,706,
203 | 202,南非,South Africa,the Republic of South Africa,ZA,ZAF,710,
204 | 203,南乔治亚岛和南桑德韦奇岛,South Georgia and the South Sandwich Islands,,GS,SGS,239,
205 | 204,西班牙,Spain,the Kingdom of Spain,ES,ESP,724,
206 | 205,斯里兰卡,Sri Lanka,the Democratic Socialist Republic of Sri Lanka,LK,LKA,144,
207 | 206,苏丹,Sudan (the),the Republic of the Sudan,SD,SDN,736,
208 | 207,苏里南,Suriname,the Republic of Suriname,SR,SUR,740,
209 | 208,斯瓦尔巴岛和扬马延岛,Svalbard and Jan Mayen,,SJ,SJM,744,
210 | 209,斯威士兰,Swaziland,the Kingdom of Swaziland,SZ,SWZ,748,
211 | 210,瑞典,Sweden,the Kingdom of Sweden,SE,SWE,752,
212 | 211,瑞士,Switzerland,the Swiss Confederation,CH,CHE,756,
213 | 212,叙利亚,Syrian Arab Republic (the),the Syrian Arab Republic,SY,SYR,760,
214 | 213,台湾,Taiwan (Province of China),,TW,TWN,158,
215 | 214,塔吉克斯坦,Tajikistan,the Republic of Tajikistan,TJ,TJK,762,
216 | 215,坦桑尼亚,"Tanzania,United Republic of",the United Republic of Tanzania,TZ,TZA,834,
217 | 216,泰国,Thailand,the Kingdom of Thailand,TH,THA,764,
218 | 217,东帝汶,Timor-Leste,the Democratic Republic of Timor-Leste,TL,TLS,626,ISO 3166.1-2006调整了英文名称和字母代码(原代码为TP\TMP)
219 | 218,多哥,Togo,the Togolese Republic,TG,TGO,768,
220 | 219,托克劳,Tokelau,,TK,TKL,772,
221 | 220,汤加,Tonga,the Kingdom of Tonga,TO,TON,776,
222 | 221,特立尼达和多巴哥,Trinidad and Tobago,the Republic of Trinidad and Tobago,TT,TTO,780,
223 | 222,突尼斯,Tunisia,the Republic of Tunisia,TN,TUN,788,
224 | 223,土耳其,Turkey,the Republic of Turkey,TR,TUR,792,
225 | 224,土库曼斯坦,Turkmenistan,,TM,TKM,795,
226 | 225,特克斯和凯科斯群岛,Turks and Caicos Islands (the),,TC,TCA,796,
227 | 226,图瓦卢,Tuvalu,,TV,TUV,798,
228 | 227,乌干达,Uganda,the Republic of Uganda,UG,UGA,800,
229 | 228,乌克兰,Ukraine,,UA,UKR,804,
230 | 229,阿联酋,United Arab Emirates (the),the United Arab Emirates,AE,ARE,784,
231 | 230,英国,United Kingdom (the),the United Kingdom of Great Britain and Northern Ireland,GB,GBR,826,
232 | 231,美国,United States (the),the United States of America,US,USA,840,
233 | 232,美国本土外小岛屿,United States Minor Outlying Islands (the),,UM,UMI,581,
234 | 233,乌拉圭,Uruguay,the Eastern Republic of Uruguay,UY,URY,858,
235 | 234,乌兹别克斯坦,Uzbekistan,the Republic of Uzbekistan,UZ,UZB,860,
236 | 235,瓦努阿图,Vanuatu,the Republic of Vanuatu,VU,VUT,548,
237 | 236,委内瑞拉,Venezuela,the Bolivarian Republic of Venezuela,VE,VEN,862,
238 | 237,越南,Viet Nam,the Socialist Republic of Viet Nam,VN,VNM,704,
239 | 238,英属维尔京群岛,Virgin Islands (British),British Virgin Islands (the),VG,VGB,92,
240 | 239,美属维尔京群岛,Virgin Islands (U.S.),the Virgin Islands of the United States,VI,VIR,850,
241 | 240,瓦利斯和富图纳,Wallis and Futuna,Wallis and Futuna Islands,WF,WLF,876,
242 | 241,西撒哈拉,Western Sahara,,EH,ESH,732,
243 | 242,也门,Yemen,the Republic of Yemen,YE,YEM,887,
244 | 243,赞比亚,Zambia,the Republic of Zambia,ZM,ZMB,894,
245 | 244,津巴布韦,Zimbabwe,the Republic of Zimbabwe,ZW,ZWE,716,
246 |
--------------------------------------------------------------------------------
/django_covid19/filters.py:
--------------------------------------------------------------------------------
1 | import django_filters
2 | from django.db.models import Q
3 | from . import models
4 |
5 |
6 | class CharInFilter(django_filters.BaseInFilter, django_filters.CharFilter):
7 | pass
8 |
9 |
10 | class CityFilter(django_filters.rest_framework.FilterSet):
11 |
12 | provinceNames = CharInFilter(
13 | field_name='provinceName', lookup_expr='in')
14 | provinceCodes = CharInFilter(
15 | field_name='provinceCode', lookup_expr='in')
16 | cityNames = CharInFilter(
17 | field_name='cityName', lookup_expr='in')
18 |
19 | class Meta:
20 | model = models.City
21 | fields = ['provinceName', 'provinceCode', 'cityName']
22 |
23 |
24 | class ProvinceFilter(django_filters.rest_framework.FilterSet):
25 |
26 | provinceNames = CharInFilter(
27 | field_name='provinceName', lookup_expr='in')
28 | provinceCodes = CharInFilter(
29 | field_name='provinceCode', lookup_expr='in')
30 |
31 | class Meta:
32 | model = models.Province
33 | fields = ['provinceName', 'provinceCode']
34 |
35 |
36 | class CountryFilter(django_filters.rest_framework.FilterSet):
37 |
38 | continents = CharInFilter(
39 | field_name='continents', lookup_expr='in')
40 | countryCodes = CharInFilter(
41 | field_name='countryCode', lookup_expr='in')
42 | countryNames = CharInFilter(
43 | field_name='countryName', lookup_expr='in')
44 |
45 | class Meta:
46 | model = models.Country
47 | fields = [
48 | 'continents', 'countryCode', 'countryName'
49 | ]
50 |
51 |
52 | class CountryCodeFilter(django_filters.rest_framework.FilterSet):
53 |
54 | numericCodes = CharInFilter(
55 | field_name='numericCode', lookup_expr='in')
56 | countryCodes = CharInFilter(
57 | field_name='countryCode', lookup_expr='in')
58 | shortCountryCodes = CharInFilter(
59 | field_name='shortCountryCode', lookup_expr='in')
60 |
61 | class Meta:
62 | model = models.CountryCode
63 | fields = [
64 | 'numericCode', 'countryCode', 'shortCountryCode'
65 | ]
66 |
--------------------------------------------------------------------------------
/django_covid19/fixtures/statistics.json:
--------------------------------------------------------------------------------
1 | [{"model": "django_covid19.statistics", "pk": 1, "fields": {"globalStatistics": "{\"suspectedCount\": 0, \"confirmedIncr\": 0, \"curedCount\": 3113897, \"confirmedCount\": 7062689, \"seriousCount\": 0, \"deadIncr\": 0, \"currentConfirmedCount\": 3543595, \"suspectedIncr\": 0, \"deadCount\": 405197, \"curedIncr\": 0, \"currentConfirmedIncr\": 0}", "domesticStatistics": "{\"suspectedCount\": 1780, \"confirmedIncr\": 0, \"curedCount\": 79874, \"confirmedCount\": 84637, \"seriousCount\": 201, \"deadIncr\": 0, \"currentConfirmedCount\": 118, \"suspectedIncr\": 0, \"deadCount\": 4645, \"curedIncr\": 0, \"currentConfirmedIncr\": 0}", "internationalStatistics": "{\"suspectedCount\": 4, \"confirmedIncr\": -441, \"curedCount\": 3034023, \"confirmedCount\": 6978052, \"seriousCount\": 0, \"deadIncr\": 0, \"currentConfirmedCount\": 3543477, \"suspectedIncr\": 0, \"deadCount\": 400552, \"curedIncr\": -9623, \"currentConfirmedIncr\": 9799}", "remarks": "[\"\\u6613\\u611f\\u4eba\\u7fa4\\uff1a\\u4eba\\u7fa4\\u666e\\u904d\\u6613\\u611f\\u3002\\u8001\\u5e74\\u4eba\\u53ca\\u6709\\u57fa\\u7840\\u75be\\u75c5\\u8005\\u611f\\u67d3\\u540e\\u75c5\\u60c5\\u8f83\\u91cd\\uff0c\\u513f\\u7ae5\\u53ca\\u5a74\\u5e7c\\u513f\\u4e5f\\u6709\\u53d1\\u75c5\", \"\\u6f5c\\u4f0f\\u671f\\uff1a\\u4e00\\u822c\\u4e3a 3\\uff5e7 \\u5929\\uff0c\\u6700\\u957f\\u4e0d\\u8d85\\u8fc7 14 \\u5929\\uff0c\\u6f5c\\u4f0f\\u671f\\u5185\\u53ef\\u80fd\\u5b58\\u5728\\u4f20\\u67d3\\u6027\\uff0c\\u5176\\u4e2d\\u65e0\\u75c7\\u72b6\\u75c5\\u4f8b\\u4f20\\u67d3\\u6027\\u975e\\u5e38\\u7f55\\u89c1\", \"\\u5bbf\\u4e3b\\uff1a\\u91ce\\u751f\\u52a8\\u7269\\uff0c\\u53ef\\u80fd\\u4e3a\\u4e2d\\u534e\\u83ca\\u5934\\u8760\"]", "notes": "[\"\\u75c5\\u6bd2\\uff1aSARS-CoV-2\\uff0c\\u5176\\u5bfc\\u81f4\\u75be\\u75c5\\u547d\\u540d COVID-19\", \"\\u4f20\\u67d3\\u6e90\\uff1a\\u65b0\\u51a0\\u80ba\\u708e\\u7684\\u60a3\\u8005\\u3002\\u65e0\\u75c7\\u72b6\\u611f\\u67d3\\u8005\\u4e5f\\u53ef\\u80fd\\u6210\\u4e3a\\u4f20\\u67d3\\u6e90\\u3002\", \"\\u4f20\\u64ad\\u9014\\u5f84\\uff1a\\u7ecf\\u547c\\u5438\\u9053\\u98de\\u6cab\\u3001\\u63a5\\u89e6\\u4f20\\u64ad\\u662f\\u4e3b\\u8981\\u7684\\u4f20\\u64ad\\u9014\\u5f84\\u3002\\u6c14\\u6eb6\\u80f6\\u4f20\\u64ad\\u548c\\u6d88\\u5316\\u9053\\u7b49\\u4f20\\u64ad\\u9014\\u5f84\\u5c1a\\u5f85\\u660e\\u786e\\u3002\"]", "generalRemark": "1. 3 \u6708 12 \u65e5\u56fd\u5bb6\u536b\u5065\u59d4\u786e\u8bca\u8865\u8ba2\u9057\u6f0f 12 \u4f8b\u786e\u8bca\u75c5\u4f8b\uff08\u975e 12 \u65e5\u65b0\u589e\uff09\uff0c\u6682\u65e0\u5177\u4f53\u7701\u4efd\u4fe1\u606f\u3002 2. \u6d59\u6c5f\u7701 12 \u4f8b\u5916\u7701\u6cbb\u6108\u6682\u65e0\u5177\u4f53\u7701\u4efd\u4fe1\u606f\u3002", "WHOArticle": "{\"title\": \"\\u65b0\\u51a0\\u75c5\\u6bd2\\u4f1a\\u53d8\\u5f02\\uff1f\\u53e3\\u7f69\\u4e0d\\u591f\\u600e\\u4e48\\u529e\\uff1f\\u4e16\\u754c\\u536b\\u751f\\u7ec4\\u7ec7\\u7684\\u7b54\\u7591\\u6765\\u4e86\\uff01\", \"imgUrl\": \"https://img1.dxycdn.com/2020/0220/196/3397701576545475720-135.jpg\", \"linkUrl\": \"https://mp.weixin.qq.com/s/6q0qMFXzoKI7MMvY7zrXUw\"}", "recommends": "[{\"countryType\": 1, \"sort\": 300, \"imgUrl\": \"https://img1.dxycdn.com/2020/0325/826/3403983726425257144-135.jpg\", \"recordStatus\": 1, \"linkUrl\": \"https://mp.weixin.qq.com/s?__biz=MjA1ODMxMDQwMQ==&mid=2657278282&idx=1&sn=ec5a88bf6cead3079f2f48f68f64aa93&chksm=4906dd247e715432a91c3c99e4d92082ffd2eb8c6ddf4355b833f597d9464aa22ad048d84d0b&token=2114569265\\u2329=zh_CN#rd\", \"title\": \"\\u4f20\\u67d3\\u75c5\\u5168\\u7403\\u5927\\u6d41\\u884c\\uff0c\\u5386\\u53f2\\u65e9\\u5c31\\u544a\\u8bc9\\u6211\\u4eec\\u7684 5 \\u4ef6\\u4e8b\", \"contentType\": 1}, {\"countryType\": 1, \"sort\": 299, \"imgUrl\": \"https://img1.dxycdn.com/2020/0313/012/3401794963846645571-135.jpg\", \"recordStatus\": 1, \"linkUrl\": \"https://mp.weixin.qq.com/s/Zaku42njWNpljKF3mViaiA\", \"title\": \"1 \\u4e2a\\u9519\\u8bef\\u52a8\\u4f5c\\uff0c\\u4e25\\u91cd\\u70e7\\u4f24\\uff0110 \\u4e2a\\u6d88\\u6bd2\\u5e38\\u89c1\\u9519\\u8bef\\u5343\\u4e07\\u522b\\u518d\\u72af\\u4e86\", \"contentType\": 4}, {\"countryType\": 1, \"sort\": 298, \"imgUrl\": \"https://img1.dxycdn.com/2020/0303/889/3399947603922974408-135.jpg\", \"recordStatus\": 1, \"linkUrl\": \"https://mp.weixin.qq.com/s/T9QvVHgkE30lMn_fC3EBBw\", \"title\": \"\\u7279\\u6b8a\\u65f6\\u671f\\uff0c\\u5b69\\u5b50\\u611f\\u5192\\u54b3\\u55fd\\u4e86\\u5230\\u5e95\\u8981\\u4e0d\\u8981\\u53bb\\u533b\\u9662\\uff1f\", \"contentType\": 2}, {\"countryType\": 1, \"sort\": 297, \"imgUrl\": \"https://img1.dxycdn.com/2020/0303/345/3399947210933784082-135.jpg\", \"recordStatus\": 1, \"linkUrl\": \"https://mp.weixin.qq.com/s/c98MyhQiJ3aiNWjjseYGbg\", \"title\": \"\\u7535\\u52a8\\u53e3\\u7f69\\u6709\\u6ca1\\u6709\\u7528\\uff1f\", \"contentType\": 1}, {\"countryType\": 1, \"sort\": 296, \"imgUrl\": \"https://img1.dxycdn.com/2020/0303/678/3399947393469903332-135.jpg\", \"recordStatus\": 1, \"linkUrl\": \"https://mp.weixin.qq.com/s/dejV_MZSZSZvlpSliER1dQ\", \"title\": \"\\u56e0\\u4e3a\\u75ab\\u60c5\\u803d\\u8bef\\u7684\\u75ab\\u82d7\\u63a5\\u79cd\\uff0c\\u8be5\\u5982\\u4f55\\u5b89\\u6392\\u8865\\u79cd\\uff1f\", \"contentType\": 2}]", "timelines": "[{\"summary\": \"\\u5f53\\u5730\\u65f6\\u95f46\\u67088\\u65e5\\u665a\\uff0c\\u963f\\u5e03\\u624e\\u6bd4\\u914b\\u957f\\u56fd\\u653f\\u5e9c\\u591a\\u4e2a\\u90e8\\u95e8\\u53d1\\u8868\\u8054\\u5408\\u58f0\\u660e\\u79f0\\uff0c\\u5c06\\u963f\\u5e03\\u624e\\u6bd4\\u914b\\u957f\\u56fd\\u6240\\u7ba1\\u8f96\\u533a\\u57df\\uff08\\u963f\\u5e03\\u624e\\u6bd4\\u5e02\\u3001\\u827e\\u56e0\\u5e02\\u548c\\u963f\\u5c14\\u8fbe\\u592b\\u62c9\\u5e02\\uff09\\u4e4b\\u95f4\\u7684\\u4eba\\u5458\\u6d41\\u52a8\\uff0c\\u4ee5\\u53ca\\u51fa\\u5165\\u963f\\u5e03\\u624e\\u6bd4\\u914b\\u957f\\u56fd\\u7684\\u4eba\\u5458\\u6d41\\u52a8\\u7981\\u4ee4\\uff0c\\u81ea6\\u67089\\u65e5\\u518d\\u5ef6\\u957f\\u4e00\\u5468\\u3002\\u4eba\\u5458\\u6d41\\u52a8\\u7981\\u4ee4\\u9002\\u7528\\u4e8e\\u963f\\u8054\\u914b\\u5883\\u5185\\u7684\\u6240\\u6709\\u5c45\\u6c11\\u3002\\u58f0\\u660e\\u8868\\u793a\\uff0c\\u91cd\\u8981\\u90e8\\u95e8\\u7684\\u5de5\\u4f5c\\u4eba\\u5458\\u3001\\u8fd0\\u8f93\\u5fc5\\u9700\\u54c1\\u7684\\u8f66\\u8f86\\u4ee5\\u53ca\\u60a3\\u6709\\u6162\\u6027\\u75c5\\u9700\\u8981\\u5916\\u51fa\\u5c31\\u8bca\\u7684\\u4eba\\u5458\\u53ef\\u4ee5\\u7533\\u8bf7\\u7279\\u6b8a\\u51fa\\u884c\\u8bb8\\u53ef\\u8bc1\\u3002\", \"infoSource\": \"\\u592e\\u89c6\\u65b0\\u95fbapp\", \"pubDate\": 1591680323000, \"title\": \"\\u963f\\u5e03\\u624e\\u6bd4\\u914b\\u957f\\u56fd\\u5ba3\\u5e03\\u5ef6\\u957f\\u4e00\\u5468\\u4eba\\u5458\\u6d41\\u52a8\\u7981\\u4ee4\", \"sourceUrl\": \"http://app.cctv.com/special/cportal/detail/arti/index.html?id=ArtiOex5vu4I9PwVoCdOk6EG200609&isfromapp=1\", \"pubDateStr\": \"14\\u5206\\u949f\\u524d\"}, {\"summary\": \"\\u5f53\\u5730\\u65f6\\u95f46\\u65e5\\u8d77\\uff0c\\u4e16\\u754c\\u4e0a\\u6700\\u5927\\u7684\\u94c1\\u77ff\\u77f3\\u4f9b\\u5e94\\u5546\\u2014\\u2014\\u5df4\\u897f\\u94c1\\u77ff\\u77f3\\u5de8\\u5934\\u6de1\\u6c34\\u6cb3\\u8c37\\u516c\\u53f8\\uff0c\\u56e0\\u5728\\u4f0a\\u5854\\u6bd4\\u62c9\\u7efc\\u5408\\u77ff\\u533a\\u7684200\\u4f59\\u540d\\u5458\\u5de5\\u611f\\u67d3\\u65b0\\u51a0\\u75c5\\u6bd2\\uff0c\\u88ab\\u5df4\\u897f\\u7b2c\\u4e09\\u5730\\u533a\\u6cd5\\u9662\\u5f3a\\u5236\\u6682\\u505c\\u8be5\\u7efc\\u5408\\u77ff\\u533a\\u7684\\u4e1a\\u52a1\\u3002\", \"infoSource\": \"\\u592e\\u89c6\\u65b0\\u95fbapp\", \"pubDate\": 1591670664000, \"title\": \"200\\u4f59\\u540d\\u5458\\u5de5\\u611f\\u67d3\\u65b0\\u51a0\\u75c5\\u6bd2\\uff0c\\u5df4\\u897f\\u6de1\\u6c34\\u6cb3\\u8c37\\u6682\\u505c\\u4f0a\\u5854\\u6bd4\\u62c9\\u7efc\\u5408\\u77ff\\u533a\\u4e1a\\u52a1\", \"sourceUrl\": \"http://app.cctv.com/special/cportal/detail/arti/index.html?id=ArtiYxBq1ymu9S9ElnOVUHlc200609&isfromapp=1\", \"pubDateStr\": \"2\\u5c0f\\u65f6\\u524d\"}, {\"summary\": \"\\u6839\\u636e\\u5df4\\u897f\\u536b\\u751f\\u90e88\\u65e518\\u65f6\\u516c\\u5e03\\u7684\\u6700\\u65b0\\u75ab\\u60c5\\u6570\\u636e\\uff0c\\u8fc7\\u53bb24\\u5c0f\\u65f6\\u5185\\u5df4\\u897f\\u65b0\\u589e\\u65b0\\u51a0\\u80ba\\u708e\\u786e\\u8bca\\u75c5\\u4f8b15654\\u4f8b\\uff0c\\u65b0\\u589e\\u6b7b\\u4ea1\\u75c5\\u4f8b679\\u4f8b\\uff0c\\u65b0\\u589e\\u6cbb\\u6108\\u75c5\\u4f8b6088\\u4f8b\\u3002\\u6839\\u636e8\\u65e5\\u516c\\u5e03\\u7684\\u7edf\\u8ba1\\u6570\\u5b57\\u7d2f\\u8ba1\\u8ba1\\u7b97\\uff0c\\u5df4\\u897f\\u5168\\u56fd\\u7d2f\\u8ba1\\u65b0\\u51a0\\u80ba\\u708e\\u786e\\u8bca\\u75c5\\u4f8b707412\\u4f8b\\uff0c\\u7d2f\\u8ba1\\u6b7b\\u4ea1\\u75c5\\u4f8b37134\\u4f8b\\u3002\\u00a0\", \"infoSource\": \"\\u592e\\u89c6\\u65b0\\u95fbapp\", \"pubDate\": 1591667160000, \"title\": \"\\u5df4\\u897f\\u65b0\\u51a0\\u80ba\\u708e\\u7d2f\\u8ba1\\u786e\\u8bca\\u4eba\\u6570\\u8d8570\\u4e07\", \"sourceUrl\": \"http://app.cctv.com/special/cportal/detail/arti/index.html?id=ArtiyUi5FB5SGguSYvGi67kq200609&isfromapp=1\", \"pubDateStr\": \"3\\u5c0f\\u65f6\\u524d\"}, {\"summary\": \"6\\u67088\\u65e50\\u65f6\\u81f324\\u65f6\\uff0c\\u5317\\u4eac\\u65b0\\u51a0\\u80ba\\u708e\\u5883\\u5916\\u8f93\\u5165\\u548c\\u672c\\u5730\\u786e\\u8bca\\u75c5\\u4f8b\\u3001\\u7591\\u4f3c\\u75c5\\u4f8b\\u3001\\u65e0\\u75c7\\u72b6\\u611f\\u67d3\\u8005\\u90fd\\u6ca1\\u6709\\u65b0\\u589e\\u62a5\\u544a\\u3002\\u672c\\u5730\\u75c5\\u4f8b\\u6cbb\\u6108\\u51fa\\u96621\\u4f8b\\uff0c\\u5b9e\\u73b0\\u201c\\u6e05\\u96f6\\u201d\\u30021\\u540d\\u5883\\u5916\\u8f93\\u5165\\u60a3\\u8005\\u4ecd\\u5728\\u9662\\u6cbb\\u7597\\u3002\", \"infoSource\": \"\\u4eba\\u6c11\\u65e5\\u62a5\", \"pubDate\": 1591664161000, \"title\": \"\\u597d\\u6d88\\u606f\\uff01\\u5317\\u4eac\\u672c\\u5730\\u786e\\u8bca\\u6e05\\u96f6\", \"sourceUrl\": \"http://m.weibo.cn/2803301701/4513829009101499\", \"pubDateStr\": \"4\\u5c0f\\u65f6\\u524d\"}, {\"summary\": \"6\\u67088\\u65e50\\u201424\\u65f6\\uff0c\\u5e7f\\u4e1c\\u7701\\u65b0\\u589e\\u5883\\u5916\\u8f93\\u5165\\u786e\\u8bca\\u75c5\\u4f8b2\\u4f8b\\uff0c\\u5e7f\\u5dde\\u62a5\\u544a\\uff0c\\u5747\\u6765\\u81ea\\u5b5f\\u52a0\\u62c9\\u56fd\\uff0c\\u5728\\u5165\\u5883\\u53e3\\u5cb8\\u53d1\\u73b0\\uff0c\\u5165\\u5883\\u540e\\u5373\\u88ab\\u9694\\u79bb\\u89c2\\u5bdf\\u3002\\u65b0\\u589e\\u51fa\\u96621\\u4f8b\\u3002\\u622a\\u81f36\\u67088\\u65e524\\u65f6\\uff0c\\u5e7f\\u4e1c\\u5168\\u7701\\u7d2f\\u8ba1\\u62a5\\u544a\\u65b0\\u51a0\\u80ba\\u708e\\u786e\\u8bca\\u75c5\\u4f8b1604\\u4f8b\\uff08\\u5883\\u5916\\u8f93\\u5165209\\u4f8b\\uff09\\u3002\\u76ee\\u524d\\u4ecd\\u5728\\u966210\\u4f8b\\u3002\\u65b0\\u589e\\u5883\\u5916\\u8f93\\u5165\\u65e0\\u75c7\\u72b6\\u611f\\u67d3\\u80051\\u4f8b\\uff0c\\u5e7f\\u5dde\\u62a5\\u544a\\uff0c\\u6765\\u81ea\\u7f8e\\u56fd\\uff0c\\u5728\\u5165\\u5883\\u53e3\\u5cb8\\u53d1\\u73b0\\uff0c\\u5165\\u5883\\u540e\\u5373\\u88ab\\u9694\\u79bb\\u89c2\\u5bdf\\u3002\", \"infoSource\": \"\\u592e\\u89c6\\u65b0\\u95fbapp\", \"pubDate\": 1591661760000, \"title\": \"\\u5e7f\\u4e1c8\\u65e5\\u65b0\\u589e\\u5883\\u5916\\u8f93\\u5165\\u786e\\u8bca\\u75c5\\u4f8b2\\u4f8b\\uff0c\\u65b0\\u589e\\u5883\\u5916\\u8f93\\u5165\\u65e0\\u75c7\\u72b6\\u611f\\u67d3\\u80051\\u4f8b\", \"sourceUrl\": \"http://app.cctv.com/special/cportal/detail/arti/index.html?id=ArtirgopjBYkLe3xojdl7KbB200609&isfromapp=1\", \"pubDateStr\": \"5\\u5c0f\\u65f6\\u524d\"}]", "wikis": "[{\"title\": \"\\u4ec0\\u4e48\\u662f\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\uff1f\", \"imgUrl\": \"\", \"description\": \"\\u6b64\\u6b21\\u6d41\\u884c\\u7684\\u51a0\\u72b6\\u75c5\\u6bd2\\u4e3a\\u4e00\\u79cd\\u65b0\\u53d1\\u73b0\\u7684\\u51a0\\u72b6\\u75c5\\u6bd2\\uff0c\\u56fd\\u9645\\u75c5\\u6bd2\\u5206\\u7c7b\\u59d4\\u5458\\u4f1a\\u547d\\u540d\\u4e3a SARS-Cov-2\\u3002\\u56e0\\u4e3a\\u4eba\\u7fa4\\u7f3a\\u5c11\\u5bf9\\u65b0\\u578b\\u75c5\\u6bd2\\u682a\\u7684\\u514d\\u75ab\\u529b\\uff0c\\u6240\\u4ee5\\u4eba\\u7fa4\\u666e\\u904d\\u6613\\u611f\\u3002\", \"linkUrl\": \"https://ask.dxy.com/ama/index#/disease/24677/info/0\"}, {\"title\": \"\\u5e2e\\u4f60\\u6392\\u9664\\u611f\\u67d3\\u75c7\\u72b6\", \"imgUrl\": \"https://img1.dxycdn.com/2020/0126/335/3393120598787233917-66.png\", \"description\": \"\\u51fa\\u73b0\\u4ec0\\u4e48\\u75c7\\u72b6\\u53ef\\u80fd\\u611f\\u67d3\\u4e86\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\uff1f\\u5982\\u4f55\\u5728\\u5bb6\\u505a\\u597d\\u81ea\\u6211\\u9694\\u79bb\\uff1f\", \"linkUrl\": \"https://ask.dxy.com/ama/index#/disease/24677/info/1\"}, {\"title\": \"\\u51a0\\u72b6\\u75c5\\u6bd2\\u6015\\u4ec0\\u4e48\\uff1f\", \"imgUrl\": \"https://img1.dxycdn.com/2020/0126/584/3393140198870641951-73.jpg\", \"description\": \"\\u54ea\\u4e9b\\u4eba\\u5bb9\\u6613\\u611f\\u67d3\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\uff1f\\u4ec0\\u4e48\\u4eba\\u5bb9\\u6613\\u53d8\\u6210\\u91cd\\u75c7\\uff1f\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\u81f4\\u75c5\\u6027\\u5982\\u4f55\\uff1f\", \"linkUrl\": \"https://ask.dxy.com/ama/index#/disease/24677/info/2\"}, {\"title\": \"\\u505a\\u597d\\u9884\\u9632\\u514d\\u611f\\u67d3\", \"imgUrl\": \"https://img1.dxycdn.com/2020/0127/314/3393234046053613437-73.jpg\", \"description\": \"\\u4eba\\u53e3\\u4e0d\\u5bc6\\u96c6\\u7684\\u5730\\u65b9\\u53ef\\u4ee5\\u4e0d\\u5e26\\u53e3\\u7f69\\u5417\\uff1f\\u53e3\\u7f69\\u80fd\\u91cd\\u590d\\u5e26\\u5417\\uff1f\\u716e\\u6cb8\\u540e\\u80fd\\u91cd\\u590d\\u4f7f\\u7528\\u5417\\uff1f\", \"linkUrl\": \"https://ask.dxy.com/ama/index#/disease/24677/info/6\"}, {\"title\": \"\\u65e5\\u5e38\\u9632\\u62a4\\u8981\\u5230\\u4f4d\", \"imgUrl\": \"https://img1.dxycdn.com/2020/0126/366/3393121524352686218-66.png\", \"description\": \"\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\u80ba\\u708e\\u6d41\\u884c\\uff0c\\u5916\\u5356\\u8fd8\\u80fd\\u5403\\u5417\\uff1f\\u4e70\\u4e0d\\u5230\\u6d88\\u6bd2\\u6db2\\u5bb6\\u91cc\\u6d88\\u6bd2\\u7528\\u4ec0\\u4e48\\u66ff\\u4ee3\\uff1f\", \"linkUrl\": \"https://ask.dxy.com/ama/index#/disease/24677/info/5\"}, {\"title\": \"\\u5982\\u4f55\\u786e\\u8bca\\u611f\\u67d3\\uff1f\", \"imgUrl\": \"https://img1.dxycdn.com/2020/0126/838/3393121081971054723-66.png\", \"description\": \"\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\u80ba\\u708e\\u60a3\\u8005\\u6709\\u4ec0\\u4e48\\u4e34\\u5e8a\\u8868\\u73b0\\uff1f\\u533b\\u751f\\u5982\\u4f55\\u8bc6\\u522b\\u5e76\\u786e\\u8bca\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\u80ba\\u708e\\uff1f\", \"linkUrl\": \"https://ask.dxy.com/ama/index#/disease/24677/info/3\"}, {\"title\": \"\\u6cbb\\u7597\\u65b9\\u6cd5\\u65e9\\u77e5\\u9053\", \"imgUrl\": \"https://img1.dxycdn.com/2020/0126/500/3393121414831020167-66.png\", \"description\": \"\\u6f5c\\u4f0f\\u671f\\u80fd\\u68c0\\u67e5\\u51fa\\u6765\\u5417\\uff1f\\u611f\\u67d3\\u4e86\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\u4e00\\u5b9a\\u4f1a\\u5f97\\u80ba\\u708e\\u5417\\uff1f\\u65b0\\u51a0\\u80ba\\u708e\\u5982\\u4f55\\u6cbb\\u7597\\uff1f\", \"linkUrl\": \"https://ask.dxy.com/ama/index#/disease/24677/info/4\"}]", "goodsGuides": "[{\"title\": \"\\u6d88\\u6bd2\\u5242\\u6307\\u5357\", \"recordStatus\": 1, \"categoryName\": \"\\u6d88\\u6bd2\\u5242\", \"contentImgUrls\": [\"https://img1.dxycdn.com/2020/0215/220/3396780175063930893-135.png\", \"https://img1.dxycdn.com/2020/0215/637/3396780181506594738-135.png\", \"https://img1.dxycdn.com/2020/0215/372/3396780187949046019-135.png\"]}, {\"title\": \"\\u53e3\\u7f69\\u6307\\u5357\", \"recordStatus\": 1, \"categoryName\": \"\\u53e3\\u7f69\", \"contentImgUrls\": [\"https://img1.dxycdn.com/2020/0225/169/3398653034208226202-135.png\"]}, {\"title\": \"\\u6d17\\u624b\\u6db2\\u6307\\u5357\", \"recordStatus\": 1, \"categoryName\": \"\\u6d17\\u624b\\u6db2\", \"contentImgUrls\": [\"https://img1.dxycdn.com/2020/0215/703/3396784974690083861-135.png\"]}, {\"title\": \"\\u6e29\\u5ea6\\u8ba1\\u6307\\u5357\", \"recordStatus\": 1, \"categoryName\": \"\\u6e29\\u5ea6\\u8ba1\", \"contentImgUrls\": [\"https://img1.dxycdn.com/2020/0215/743/3396785021934726693-135.png\"]}]", "rumors": "[{\"summary\": \"\", \"body\": \"\\u8fd1\\u65e5\\uff0c\\u6709\\u4eba\\u5728\\u670b\\u53cb\\u5708\\u515c\\u552e\\u67d0\\u516c\\u53f8\\u751f\\u4ea7\\u7684\\u65b0\\u51a0\\u75c5\\u6bd2\\u6297\\u4f53\\u68c0\\u6d4b\\u8bd5\\u5242\\u76d2\\uff0c\\u5355\\u4ef7 150 \\u5143\\uff0c\\u5e76\\u5ba3\\u79f0\\u53ef\\u4ee5\\u5bb6\\u5ead\\u81ea\\u884c\\u4f7f\\u7528\\u3002\\u5bf9\\u6b64\\uff0c\\u5317\\u4eac\\u5e02\\u836f\\u76d1\\u5c40\\u63d0\\u793a\\uff0c\\u7ecf\\u6279\\u51c6\\u6ce8\\u518c\\u7684\\u65b0\\u51a0\\u75c5\\u6bd2\\u68c0\\u6d4b\\u8bd5\\u5242\\u76d2\\uff0c\\u5747\\u9700\\u8981\\u5177\\u5907 PCR \\u5b9e\\u9a8c\\u5ba4\\u53ca\\u4e13\\u7528\\u8bbe\\u5907\\u7684\\u533b\\u7597\\u673a\\u6784\\u624d\\u80fd\\u5b8c\\u6210\\u68c0\\u6d4b\\uff0c\\u666e\\u901a\\u5e02\\u6c11\\u5bb6\\u5ead\\u4e0d\\u53ef\\u81ea\\u884c\\u4f7f\\u7528\\uff0c\\u5e02\\u6c11\\u4e0d\\u8981\\u8f7b\\u4fe1\\u865a\\u5047\\u5ba3\\u4f20\\uff0c\\u51fa\\u73b0\\u76f8\\u5173\\u75c7\\u72b6\\u5e94\\u53ca\\u65f6\\u5c31\\u533b\\u3002\", \"score\": 1000, \"mainSummary\": \"\\u5317\\u4eac\\u5e02\\u836f\\u76d1\\u5c40\\u63d0\\u793a\\uff1a\\u666e\\u901a\\u5e02\\u6c11\\u5bb6\\u5ead\\u4e0d\\u53ef\\u81ea\\u884c\\u4f7f\\u7528\", \"title\": \"\\u53ef\\u5728\\u5bb6\\u4f7f\\u7528\\u65b0\\u51a0\\u75c5\\u6bd2\\u8bd5\\u5242\\u76d2\\u81ea\\u6d4b\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u957f\\u65f6\\u95f4\\u5927\\u5f3a\\u5ea6\\u7684\\u8fd0\\u52a8\\uff0c\\u4f1a\\u5bfc\\u81f4\\u8eab\\u4f53\\u673a\\u80fd\\u5931\\u8c03\\uff0c\\u514d\\u75ab\\u529f\\u80fd\\u4e0b\\u964d\\uff0c\\u5e76\\u4e14\\u8fd0\\u52a8\\u635f\\u4f24\\u98ce\\u9669\\u589e\\u52a0\\u3002\\u56e0\\u6b64\\uff0c\\u7279\\u522b\\u5fcc\\u8bb3\\u5e73\\u5e38\\u4e0d\\u8fd0\\u52a8\\u3001\\u953b\\u70bc\\u641e\\u7a81\\u51fb\\u3002\\u4ec0\\u4e48\\u6837\\u7684\\u8fd0\\u52a8\\u5f3a\\u5ea6\\u662f\\u9002\\u5b9c\\u7684\\uff1a\\u8fd0\\u52a8\\u540e\\u611f\\u89c9\\u8f7b\\u5ea6\\u7684\\u547c\\u5438\\u6025\\u4fc3\\uff0c\\u5468\\u8eab\\u5fae\\u70ed\\uff0c\\u9762\\u8272\\u5fae\\u7ea2\\uff0c\\u5185\\u5fc3\\u611f\\u89c9\\u8f7b\\u677e\\u6109\\u5feb\\u3002\\u867d\\u7136\\u7a0d\\u5fae\\u611f\\u89c9\\u6709\\u70b9\\u75b2\\u4e4f\\uff0c\\u4f46\\u662f\\u7ecf\\u8fc7\\u4f11\\u606f\\u4ee5\\u540e\\u53ef\\u4ee5\\u6d88\\u9664\\uff0c\\u5e76\\u4e14\\u6ca1\\u6709\\u75bc\\u75db\\u548c\\u9ebb\\u6728\\u3002\", \"score\": 1000, \"mainSummary\": \"\\u56fd\\u5bb6\\u4f53\\u80b2\\u603b\\u5c40\\u4f53\\u80b2\\u79d1\\u5b66\\u7814\\u7a76\\u6240\\u7814\\u7a76\\u5458\\u5f90\\u5efa\\u65b9\\uff1a\\u957f\\u65f6\\u95f4\\u5927\\u5f3a\\u5ea6\\u7684\\u8fd0\\u52a8\\uff0c\\u4f1a\\u5bfc\\u81f4\\u8eab\\u4f53\\u673a\\u80fd\\u5931\\u8c03\\uff0c\\u514d\\u75ab\\u529f\\u80fd\\u4e0b\\u964d\", \"title\": \"\\u75ab\\u60c5\\u671f\\u95f4\\u5927\\u5f3a\\u5ea6\\u953b\\u70bc\\u53ef\\u63d0\\u9ad8\\u62b5\\u6297\\u529b\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u56e0\\u73b0\\u6709\\u7814\\u7a76\\u663e\\u793a ACE2 \\u662f\\u65b0\\u578b\\u51a0\\u72b6\\u75c5\\u6bd2\\u5165\\u4fb5\\u4eba\\u4f53\\u7684\\u5173\\u952e\\uff0c\\u7f51\\u4f20\\u670d\\u7528 ACEI\\uff08\\u8840\\u7ba1\\u7d27\\u5f20\\u7d20\\u8f6c\\u5316\\u9176\\u6291\\u5236\\u5242\\uff09\\u7c7b\\u964d\\u538b\\u836f\\u4f1a\\u589e\\u52a0\\u611f\\u67d3\\u65b0\\u51a0\\u75c5\\u6bd2\\u7684\\u98ce\\u9669\\u3002\\u4f46\\u76ee\\u524d\\u6ca1\\u6709\\u4efb\\u4f55\\u52a8\\u7269\\u548c\\u4e34\\u5e8a\\u7814\\u7a76\\u6570\\u636e\\u8bc1\\u5b9e\\u3002\\u64c5\\u81ea\\u505c\\u7528\\u964d\\u538b\\u836f\\u4f1a\\u5bfc\\u81f4\\u8840\\u538b\\u6ce2\\u52a8\\uff0c\\u7ed9\\u9ad8\\u8840\\u538b\\u60a3\\u8005\\u5e26\\u6765\\u66f4\\u5927\\u7684\\u5371\\u9669\\u3002\\u5bf9\\u9ad8\\u8840\\u538b\\u60a3\\u8005\\u800c\\u8a00\\uff0c\\u6240\\u6709\\u7684\\u836f\\u7269\\u8c03\\u6574\\u90fd\\u8981\\u5728\\u4e13\\u79d1\\u533b\\u751f\\u7684\\u6307\\u5bfc\\u4e0b\\u8fdb\\u884c\\u3002\", \"score\": 197, \"mainSummary\": \"\\u4e01\\u9999\\u533b\\u751f\\u56e2\\u961f\\u8f9f\\u8c23\\uff1a\\u76ee\\u524d\\u6ca1\\u6709\\u4efb\\u4f55\\u52a8\\u7269\\u548c\\u4e34\\u5e8a\\u7814\\u7a76\\u6570\\u636e\\u8bc1\\u5b9e\\u8fd9\\u79cd\\u8bf4\\u6cd5\\u7684\\u53ef\\u9760\\u6027\", \"title\": \"\\u5403\\u964d\\u538b\\u836f\\u4f1a\\u589e\\u52a0\\u611f\\u67d3\\u75c5\\u6bd2\\u7684\\u98ce\\u9669\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u6709\\u4f20\\u95fb\\u79f0\\uff1a\\u300c\\u75c5\\u60a3\\u9057\\u4f53\\u89e3\\u5256\\u53d1\\u73b0\\u6b7b\\u8005\\u80ba\\u90e8\\u51fa\\u73b0\\u5927\\u91cf\\u75f0\\u6813\\uff0c\\u800c\\u75f0\\u6813\\u662f\\u7531\\u547c\\u5438\\u673a\\u4f7f\\u7528\\u6240\\u4ea7\\u751f\\uff0c\\u81f4\\u4eba\\u7f3a\\u6c27\\u800c\\u6b7b\\u3002\\u6628\\u5929\\u5f00\\u59cb\\uff0c\\u6025\\u6551\\u6539\\u7528\\u5438\\u75f0\\u673a\\uff0c\\u5e2e\\u52a9\\u6b66\\u6c49\\u6b7b\\u4ea1\\u4eba\\u6570\\u51cf\\u534a\\uff0c\\u8fd9\\u9700\\u8981\\u611f\\u8c22\\u9057\\u4f53\\u6350\\u732e\\u8005\\u548c\\u540c\\u6d4e\\u6cd5\\u533b\\u7cfb\\u5218\\u826f\\u6559\\u6388\\u56e2\\u961f\\u7684\\u52aa\\u529b\\u3002\\u300d\\u5bf9\\u6b64\\uff0c\\u5218\\u826f\\u6559\\u6388\\u4eb2\\u81ea\\u8f9f\\u8c23\\uff1a\\u6ca1\\u6709\\u5e72\\u9884\\u8fc7\\u4efb\\u4f55\\u4e2a\\u4f8b\\u7684\\u4e34\\u5e8a\\u6cbb\\u7597\\u3002\\n\\u6cd5\\u533b\\u5b66\\u4e13\\u5bb6\\u8868\\u793a\\uff1a\\u300c\\u75f0\\u6813\\u4e0d\\u662f\\u547c\\u5438\\u673a\\u5bfc\\u81f4\\u7684\\uff0c\\u800c\\u662f\\u7531\\u80ba\\u90e8\\u9ecf\\u6db2\\u75c5\\u53d8\\u5f62\\u6210\\u7684\\uff0c\\u5c5e\\u4e8e\\u75be\\u75c5\\u635f\\u5bb3\\u540e\\u7684\\u75c5\\u7406\\u8fc7\\u7a0b\\u3002\\u300d\", \"score\": 196, \"mainSummary\": \"\\u5218\\u826f\\u6559\\u6388\\u8f9f\\u8c23\\uff1a\\u6ca1\\u6709\\u5e72\\u9884\\u8fc7\\u4efb\\u4f55\\u4e2a\\u4f8b\\u7684\\u4e34\\u5e8a\\u6cbb\\u7597\", \"title\": \"\\u6539\\u7528\\u5438\\u75f0\\u673a\\u540e\\uff0c\\u6b66\\u6c49\\u6b7b\\u4ea1\\u4eba\\u6570\\u51cf\\u534a\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u7f51\\u4f20\\u7684\\u65b0\\u95fb\\u622a\\u56fe\\u539f\\u6587\\u300cCDC confirms first coronavirus case of \\\"unknown\\\"origin in U.S.\\u300d\\u7684\\u610f\\u601d\\u5176\\u5b9e\\u662f\\uff1a\\u300c\\u7f8e\\u56fd\\u75be\\u63a7\\u4e2d\\u5fc3\\u786e\\u8ba4\\u7f8e\\u56fd\\u51fa\\u73b0\\u9996\\u4f8b\\u65e0\\u6cd5\\u786e\\u5b9a\\u75c5\\u6e90\\u65b0\\u51a0\\u80ba\\u708e\\u60a3\\u8005\\u3002\\u300d\\u7f51\\u53cb\\u8bf4\\u5f97\\u597d\\uff0c\\u53ea\\u80cc\\u5355\\u8bcd\\u4e0d\\u5b66\\u8bed\\u6cd5\\u7684\\u4eba\\uff0c\\u5c31\\u4e0d\\u8981\\u778e\\u7ffb\\u8bd1\\u4e86\\u3002\", \"score\": 195, \"mainSummary\": \"\\u4e01\\u9999\\u533b\\u751f\\u56e2\\u961f\\u67e5\\u8bc1\\uff1a\\u7cfb\\u7ffb\\u8bd1\\u9519\\u8bef\", \"title\": \"\\u7b2c\\u4e00\\u4f8b\\u65b0\\u51a0\\u80ba\\u708e\\u60a3\\u8005\\u6765\\u81ea\\u7f8e\\u56fd\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"28 \\u65e5\\uff0c\\u79d1\\u6280\\u90e8\\u793e\\u4f1a\\u53d1\\u5c55\\u79d1\\u6280\\u53f8\\u53f8\\u957f\\u5434\\u8fdc\\u5f6c\\u8868\\u793a\\uff0c\\u76ee\\u524d\\u7814\\u7a76\\u7ed3\\u8bba\\u663e\\u793a\\uff0c\\u547c\\u5438\\u9053\\u98de\\u6cab\\u548c\\u5bc6\\u5207\\u63a5\\u89e6\\u4f20\\u64ad\\u4ecd\\u7136\\u662f\\u4e3b\\u8981\\u4f20\\u64ad\\u9014\\u5f84\\u3002\\u7caa\\u53e3\\u4f20\\u64ad\\u6709\\u4e00\\u5b9a\\u98ce\\u9669\\uff0c\\u4f46\\u4f20\\u64ad\\u80fd\\u529b\\u548c\\u6761\\u4ef6\\u8fd8\\u9700\\u8fdb\\u4e00\\u6b65\\u76f8\\u5e94\\u7814\\u7a76\\u8bc1\\u5b9e\\u3002\\u9488\\u5bf9\\u6c14\\u6eb6\\u80f6\\u4f20\\u64ad\\uff0c\\u4e2d\\u56fd\\u533b\\u79d1\\u9662\\u5b9e\\u9a8c\\u52a8\\u7269\\u6240\\u5f00\\u5c55\\u76f8\\u5e94\\u5b9e\\u9a8c\\uff0c\\u6c14\\u6eb6\\u80f6\\u4f20\\u64ad\\u8981\\u540c\\u65f6\\u6ee1\\u8db3\\u5bc6\\u95ed\\u7684\\u7a7a\\u95f4\\u3001\\u8f83\\u957f\\u7684\\u65f6\\u95f4\\u3001\\u9ad8\\u6d53\\u5ea6\\u75c5\\u6bd2\\u4e09\\u4e2a\\u6761\\u4ef6\\uff0c\\u5728\\u8fd9\\u4e9b\\u6761\\u4ef6\\u4e0b\\u624d\\u6709\\u4f20\\u67d3\\u7684\\u53ef\\u80fd\\u6027\\u3002\\u901a\\u98ce\\u6761\\u4ef6\\u826f\\u597d\\u7684\\u65e5\\u5e38\\u751f\\u6d3b\\u4e2d\\u6c14\\u6eb6\\u80f6\\u4f20\\u64ad\\u53ef\\u80fd\\u6027\\u5c0f\\u3002\", \"score\": 193, \"mainSummary\": \"\\u79d1\\u6280\\u90e8\\u793e\\u4f1a\\u53d1\\u5c55\\u79d1\\u6280\\u53f8\\u53f8\\u957f\\u5434\\u8fdc\\u5f6c\\uff1a\\u76ee\\u524d\\u7814\\u7a76\\u7ed3\\u8bba\\u663e\\u793a\\uff0c\\u547c\\u5438\\u9053\\u98de\\u6cab\\u548c\\u5bc6\\u5207\\u63a5\\u89e6\\u4f20\\u64ad\\u4ecd\\u7136\\u662f\\u4e3b\\u8981\\u4f20\\u64ad\\u9014\\u5f84\", \"title\": \"\\u65b0\\u51a0\\u75c5\\u6bd2\\u4f20\\u64ad\\u9014\\u5f84\\u6709\\u53d8\\u5316\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u8fd1\\u65e5\\uff0c\\u90e8\\u5206\\u7f51\\u6c11\\u8f6c\\u53d1\\u300c\\u4e50\\u9675\\u5341\\u4e09\\u4eba\\u67d3 sk5 \\u75c5\\u6bd2\\uff0c\\u53c2\\u4e0e\\u62a2\\u6551\\u7684\\u533b\\u751f\\u5df2\\u88ab\\u9694\\u79bb\\u300d\\u7684\\u4fe1\\u606f\\uff0c\\u5176\\u5b9e\\uff0c\\u8be5\\u8c23\\u8a00\\u65e9\\u5728 2018 \\u5e74\\u5c31\\u5df2\\u7ecf\\u5b58\\u5728\\uff0c\\u4e14\\u9020\\u8c23\\u8005\\u88ab\\u4f9d\\u6cd5\\u67e5\\u5904\\u3002\\u6b64\\u6b21\\u7ecf\\u4e50\\u9675\\u5e02\\u516c\\u5b89\\u5c40\\u4fa6\\u67e5\\uff0c\\u786e\\u8ba4\\u8be5\\u8c23\\u8a00\\u5728\\u5f53\\u524d\\u65f6\\u671f\\u7684\\u9996\\u6b21\\u8f6c\\u53d1\\u8005\\u4e3a\\u8463\\u67d0\\u73b2\\uff08\\u5e86\\u4e91\\u53bf\\u5c45\\u4f4f\\uff09\\u30022020 \\u5e74 2 \\u6708 27 \\u65e5\\uff0c\\u8463\\u67d0\\u73b2\\u56e0\\u6563\\u5e03\\u8c23\\u8a00\\u6270\\u4e71\\u516c\\u5171\\u79e9\\u5e8f\\uff0c\\u5df2\\u88ab\\u516c\\u5b89\\u673a\\u5173\\u4f9d\\u6cd5\\u5904\\u4ee5\\u884c\\u653f\\u62d8\\u7559\\u3002\", \"score\": 192, \"mainSummary\": \"\\u4e01\\u9999\\u533b\\u751f\\u56e2\\u961f\\u67e5\\u8bc1\\uff1a\\u8be5\\u8c23\\u8a00\\u7cfb 2018 \\u5e74\\u7684\\u65e7\\u8c23\\u8a00\\uff0c\\u9020\\u8c23\\u8005\\u5df2\\u88ab\\u67e5\\u5904\", \"title\": \"\\u5341\\u4e09\\u540d\\u7537\\u5973\\u751f\\u611f\\u67d3 sk5 \\u75c5\\u6bd2\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u7f51\\u4f20\\u300c\\u9648\\u56fd\\u751f\\u5199\\u7684\\u4e00\\u672c\\u53eb\\u300a\\u5b9e\\u8bc1\\u5316\\u4e2d\\u533b\\u57fa\\u7840\\u7406\\u8bba\\u53ca\\u8fd0\\u7528\\u300b\\u7684\\u4e66\\u5728\\u5341\\u5e74\\u524d\\u9884\\u8a00\\u4e86\\u8fd9\\u6b21\\u80ba\\u708e\\u75ab\\u60c5\\u300d\\u3002\\u4e0a\\u6d77\\u56fe\\u4e66\\u9986\\u8fdb\\u884c\\u4e86\\u67e5\\u8bc1\\uff0c\\u6ca1\\u6709\\u68c0\\u7d22\\u5230\\u8fd9\\u672c\\u4e66\\u3002\\n\\u5728\\u4e07\\u65b9\\u6570\\u636e\\u5e93\\u91cc\\uff0c\\u53ef\\u4ee5\\u67e5\\u5f97\\u9648\\u56fd\\u751f\\u6240\\u5199\\u300a\\u5b9e\\u8bc1\\u5316\\u4e2d\\u533b\\u57fa\\u7840\\u7406\\u8bba\\u4f9d\\u636e\\u53ca\\u5e94\\u7528\\u300b\\u8fd9\\u7bc7\\u6587\\u7ae0\\uff0c\\u53d1\\u8868\\u5728\\u300a2011 \\u5e74\\u5168\\u56fd\\u5929\\u707e\\u9884\\u6d4b\\u7814\\u8ba8\\u5b66\\u672f\\u4f1a\\u8bae\\u8bba\\u6587\\u96c6\\u300b\\u4e2d\\uff0c\\u9898\\u540d\\u548c\\u7f51\\u4f20\\u6709\\u4e00\\u5b57\\u4e4b\\u5dee\\uff0c\\u4f46\\u80fd\\u591f\\u5bf9\\u4e0a\\u5e74\\u4efd\\u548c\\u4f1a\\u8bae\\u540d\\u79f0\\u3002\\u4f46\\u5e76\\u672a\\u53d1\\u73b0\\u6d89\\u53ca\\u4efb\\u4f55\\u4e0e\\u75ab\\u60c5\\u9884\\u6d4b\\u76f8\\u5173\\u7684\\u5185\\u5bb9\\u3002\", \"score\": 191, \"mainSummary\": \"\\u4e0a\\u6d77\\u56fe\\u4e66\\u9986\\u67e5\\u8bc1\\uff1a\\u6ca1\\u6709\\u627e\\u5230\\u4f20\\u95fb\\u91cc\\u63d0\\u5230\\u7684\\u8fd9\\u672c\\u4e66\\uff0c\\u540c\\u540d\\u6587\\u7ae0\\u4e5f\\u6ca1\\u6709\\u76f8\\u5173\\u5185\\u5bb9\", \"title\": \"\\u5341\\u5e74\\u524d\\u5c31\\u6709\\u4eba\\u9884\\u6d4b\\u75ab\\u60c5\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u4e0d\\u9700\\u8981\\u4f69\\u6234\\u591a\\u5c42\\u53e3\\u7f69\\u3002\\u5efa\\u8bae\\u9009\\u62e9 N95/KN95 \\u6216\\u666e\\u901a\\u5916\\u79d1\\u53e3\\u7f69\\uff0c\\u5e76\\u4e14\\u4e00\\u5c42\\u5c31\\u591f\\uff0c\\u5176\\u4ed6\\u53e3\\u7f69\\u9632\\u62a4\\u6548\\u679c\\u4e0d\\u5982\\u8fd9\\u4e09\\u79cd\\u3002\\u4f69\\u6234\\u591a\\u5c42\\u53e3\\u7f69\\u8fd8\\u53ef\\u80fd\\u9020\\u6210\\u547c\\u5438\\u4e0d\\u7545\\u3002\\n\", \"score\": 190, \"mainSummary\": \"\\u4e01\\u9999\\u533b\\u751f\\u56e2\\u961f\\u8f9f\\u8c23\\uff1a\\u4f69\\u6234\\u591a\\u5c42\\u53e3\\u7f69\\u53ef\\u80fd\\u9020\\u6210\\u547c\\u5438\\u4e0d\\u7545\", \"title\": \"\\u6234\\u591a\\u5c42\\u53e3\\u7f69\\u624d\\u80fd\\u9632\\u4f4f\\u75c5\\u6bd2?\", \"sourceUrl\": \"\", \"rumorType\": 0}, {\"summary\": \"\", \"body\": \"\\u636e\\u9999\\u6e2f\\u6587\\u6c47\\u7f51\\u62a5\\u9053\\uff0c\\u9999\\u6e2f\\u6e14\\u62a4\\u7f72\\u53d1\\u73b0\\u4e00\\u540d\\u65b0\\u51a0\\u80ba\\u708e\\u786e\\u8bca\\u60a3\\u8005\\u9972\\u517b\\u7684\\u5ba0\\u7269\\u72d7\\u5bf9\\u75c5\\u6bd2\\u6d4b\\u8bd5\\u5448\\u5f31\\u9633\\u6027\\u53cd\\u5e94\\u3002\\u9999\\u6e2f\\u98df\\u7269\\u53ca\\u536b\\u751f\\u5c40\\u957f\\u9648\\u8087\\u59cb 28 \\u65e5\\u5f3a\\u8c03\\uff0c\\u65e0\\u8bc1\\u636e\\u663e\\u793a\\u72d7\\u4f1a\\u4f20\\u64ad\\u65b0\\u51a0\\u75c5\\u6bd2\\u7ed9\\u4eba\\u3002\\u5979\\u547c\\u5401\\u517b\\u5ba0\\u7269\\u7684\\u5e02\\u6c11\\u6ce8\\u610f\\u4e2a\\u4eba\\u536b\\u751f\\u3002\\n\\n\\u9648\\u8087\\u59cb\\u8868\\u793a\\uff0c\\u8fd9\\u53ea\\u72d7\\u4f1a\\u63a5\\u53d7\\u517d\\u533b\\u7684\\u533b\\u5b66\\u76d1\\u5bdf\\uff0c\\u5e76\\u62bd\\u53d6\\u6837\\u672c\\u5316\\u9a8c\\uff0c\\u5f85\\u6d4b\\u8bd5\\u7ed3\\u679c\\u5448\\u9634\\u6027\\u624d\\u4f1a\\u53d1\\u8fd8\\u3002\", \"score\": 190, \"mainSummary\": \"\\u9999\\u6e2f\\u98df\\u536b\\u5c40\\u957f\\u9648\\u8087\\u59cb\\u5f3a\\u8c03\\uff1a\\u867d\\u67e5\\u5230\\u5f31\\u9633\\u6027\\uff0c\\u4f46\\u65e0\\u8bc1\\u636e\\u663e\\u793a\\u72d7\\u4f1a\\u4f20\\u64ad\\u65b0\\u51a0\\u75c5\\u6bd2\\u7ed9\\u4eba\", \"title\": \"\\u786e\\u8bca\\u8005\\u5bb6\\u4e2d\\u7684\\u72d7\\u68c0\\u6d4b\\u5448\\u5f31\\u9633\\u6027\\uff1f\", \"sourceUrl\": \"\", \"rumorType\": 1}]", "modifyTime": "2020-06-09T05:45:31Z", "createTime": "2020-01-20T16:31:39Z", "crawlTime": "2020-06-09T06:16:53.030Z"}}]
--------------------------------------------------------------------------------
/django_covid19/locale/zh_Hans/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the PACKAGE package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2020-11-03 16:06+0800\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 | "Plural-Forms: nplurals=1; plural=0;\n"
20 |
21 | #: admin.py:34 models.py:15
22 | msgid "globalStatistics"
23 | msgstr "全球疫情"
24 |
25 | #: admin.py:39 models.py:16
26 | msgid "domesticStatistics"
27 | msgstr "国内疫情"
28 |
29 | #: admin.py:45 models.py:17
30 | msgid "internationalStatistics"
31 | msgstr "国际疫情"
32 |
33 | #: apps.py:8
34 | msgid "django_covid19"
35 | msgstr "新冠肺炎疫情"
36 |
37 | #: management/commands/crawl.py:32
38 | msgid "Crawl data from DingXiangYuan."
39 | msgstr "从丁香园抓取数据"
40 |
41 | #: management/commands/import_crc.py:18
42 | msgid "Import country codes."
43 | msgstr "导入国家或地区编码。"
44 |
45 | #: models.py:18
46 | msgid "remarks"
47 | msgstr "备注"
48 |
49 | #: models.py:19
50 | msgid "notes"
51 | msgstr "说明"
52 |
53 | #: models.py:20
54 | msgid "generalRemark"
55 | msgstr ""
56 |
57 | #: models.py:21
58 | msgid "WHOArticle"
59 | msgstr "WHO 文章"
60 |
61 | #: models.py:22
62 | msgid "recommends"
63 | msgstr "防护知识"
64 |
65 | #: models.py:23
66 | msgid "timelines"
67 | msgstr "时间线事件"
68 |
69 | #: models.py:24
70 | msgid "Wiki"
71 | msgstr ""
72 |
73 | #: models.py:25
74 | msgid "goodsGuides"
75 | msgstr "购物指南"
76 |
77 | #: models.py:26
78 | msgid "rumors"
79 | msgstr "辟谣与防护"
80 |
81 | #: models.py:27 models.py:61 models.py:82 models.py:101
82 | msgid "modifyTime"
83 | msgstr "修改时间"
84 |
85 | #: models.py:28 models.py:60 models.py:81 models.py:100
86 | msgid "createTime"
87 | msgstr "创建时间"
88 |
89 | #: models.py:29
90 | msgid "crawlTime"
91 | msgstr "抓取时间"
92 |
93 | #: models.py:32 models.py:33
94 | msgid "Statistics"
95 | msgstr "统计数据"
96 |
97 | #: models.py:38
98 | msgid "continents"
99 | msgstr "大洲"
100 |
101 | #: models.py:39 models.py:70 models.py:91 models.py:111
102 | msgid "countryCode"
103 | msgstr "国家或地区编码"
104 |
105 | #: models.py:40 models.py:113
106 | msgid "countryName"
107 | msgstr "国家或地区名称"
108 |
109 | #: models.py:41
110 | msgid "countryFullName"
111 | msgstr "国家或地区全名"
112 |
113 | #: models.py:42 models.py:73 models.py:95
114 | msgid "currentConfirmedCount"
115 | msgstr "现存确诊"
116 |
117 | #: models.py:43 models.py:74 models.py:96
118 | msgid "confirmedCount"
119 | msgstr "累计确诊"
120 |
121 | #: models.py:44 models.py:75 models.py:97
122 | msgid "suspectedCount"
123 | msgstr "疑似病例"
124 |
125 | #: models.py:45 models.py:76 models.py:98
126 | msgid "curedCount"
127 | msgstr "累计治愈"
128 |
129 | #: models.py:46 models.py:77 models.py:99
130 | msgid "deadCount"
131 | msgstr "累计死亡"
132 |
133 | #: models.py:48
134 | msgid "showRank"
135 | msgstr "显示排名"
136 |
137 | #: models.py:49
138 | msgid "deadRateRank"
139 | msgstr "死亡率排名"
140 |
141 | #: models.py:50
142 | msgid "deadCountRank"
143 | msgstr "死亡数排名"
144 |
145 | #: models.py:51
146 | msgid "confirmedCountRank"
147 | msgstr "确认数排名"
148 |
149 | #: models.py:52
150 | msgid "deadRate"
151 | msgstr "死亡率"
152 |
153 | #: models.py:53
154 | msgid "tags"
155 | msgstr ""
156 |
157 | #: models.py:54
158 | msgid "statisticsData"
159 | msgstr "统计数据 URL"
160 |
161 | #: models.py:55 models.py:116
162 | msgid "comment"
163 | msgstr "备注"
164 |
165 | #: models.py:56
166 | msgid "incrVo"
167 | msgstr "新增情况"
168 |
169 | #: models.py:57
170 | msgid "sort"
171 | msgstr ""
172 |
173 | #: models.py:58
174 | msgid "operator"
175 | msgstr "操作者"
176 |
177 | #: models.py:59 models.py:80
178 | msgid "dailyData"
179 | msgstr "日统计数据"
180 |
181 | #: models.py:64 models.py:65
182 | msgid "Country"
183 | msgstr "国家或地区"
184 |
185 | #: models.py:71 models.py:93
186 | msgid "provinceName"
187 | msgstr "省名"
188 |
189 | #: models.py:72 models.py:92
190 | msgid "provinceCode"
191 | msgstr "省份编码"
192 |
193 | #: models.py:78
194 | msgid "dailyUrl"
195 | msgstr "日统计链接"
196 |
197 | #: models.py:79
198 | msgid "currentUrl"
199 | msgstr "最新统计链接"
200 |
201 | #: models.py:85 models.py:86
202 | msgid "Province"
203 | msgstr "国内省份"
204 |
205 | #: models.py:94
206 | msgid "cityName"
207 | msgstr "城市名称"
208 |
209 | #: models.py:104 models.py:105
210 | msgid "City"
211 | msgstr "国内城市"
212 |
213 | #: models.py:110
214 | msgid "numericCode"
215 | msgstr "数字编码"
216 |
217 | #: models.py:112
218 | msgid "shortCountryCode"
219 | msgstr "短国家或地区编码"
220 |
221 | #: models.py:114
222 | msgid "englishCountryName"
223 | msgstr "英文国家名"
224 |
225 | #: models.py:115
226 | msgid "englishCountryFullName"
227 | msgstr "英文国家全名"
228 |
229 | #: models.py:119 models.py:120
230 | msgid "CountryCode"
231 | msgstr "国家或地区编码"
232 |
233 | #: spider/nCoV/spiders/covidtracking.py:18
234 | msgid "Alabama"
235 | msgstr "阿拉巴马州"
236 |
237 | #: spider/nCoV/spiders/covidtracking.py:19
238 | msgid "Alaska"
239 | msgstr "阿拉斯加州"
240 |
241 | #: spider/nCoV/spiders/covidtracking.py:20
242 | msgid "AmericanSamoa"
243 | msgstr "美属萨摩亚"
244 |
245 | #: spider/nCoV/spiders/covidtracking.py:21
246 | msgid "Arizona"
247 | msgstr "亚利桑那州"
248 |
249 | #: spider/nCoV/spiders/covidtracking.py:22
250 | msgid "Arkansas"
251 | msgstr "阿肯色州"
252 |
253 | #: spider/nCoV/spiders/covidtracking.py:23
254 | msgid "California"
255 | msgstr "加利福尼亚州"
256 |
257 | #: spider/nCoV/spiders/covidtracking.py:24
258 | msgid "Colorado"
259 | msgstr "科罗拉多州"
260 |
261 | #: spider/nCoV/spiders/covidtracking.py:25
262 | msgid "Connecticut"
263 | msgstr "康涅狄格州"
264 |
265 | #: spider/nCoV/spiders/covidtracking.py:26
266 | msgid "Delaware"
267 | msgstr "特拉华州"
268 |
269 | #: spider/nCoV/spiders/covidtracking.py:27
270 | msgid "DistrictOfColumbia"
271 | msgstr "哥伦比亚特区"
272 |
273 | #: spider/nCoV/spiders/covidtracking.py:28
274 | msgid "Florida"
275 | msgstr "佛罗里达州"
276 |
277 | #: spider/nCoV/spiders/covidtracking.py:29
278 | msgid "Georgia"
279 | msgstr "乔治亚州"
280 |
281 | #: spider/nCoV/spiders/covidtracking.py:30
282 | msgid "Guam"
283 | msgstr "关岛"
284 |
285 | #: spider/nCoV/spiders/covidtracking.py:31
286 | msgid "Hawaii"
287 | msgstr "夏威夷州"
288 |
289 | #: spider/nCoV/spiders/covidtracking.py:32
290 | msgid "Idaho"
291 | msgstr "爱达荷州"
292 |
293 | #: spider/nCoV/spiders/covidtracking.py:33
294 | msgid "Illinois"
295 | msgstr "伊利诺斯州"
296 |
297 | #: spider/nCoV/spiders/covidtracking.py:34
298 | msgid "Indiana"
299 | msgstr "印第安纳州"
300 |
301 | #: spider/nCoV/spiders/covidtracking.py:35
302 | msgid "Iowa"
303 | msgstr "爱荷华州"
304 |
305 | #: spider/nCoV/spiders/covidtracking.py:36
306 | msgid "Kansas"
307 | msgstr "堪萨斯州"
308 |
309 | #: spider/nCoV/spiders/covidtracking.py:37
310 | msgid "Kentucky"
311 | msgstr "肯塔基州"
312 |
313 | #: spider/nCoV/spiders/covidtracking.py:38
314 | msgid "Louisiana"
315 | msgstr "路易斯安那州"
316 |
317 | #: spider/nCoV/spiders/covidtracking.py:39
318 | msgid "Maine"
319 | msgstr "缅因州"
320 |
321 | #: spider/nCoV/spiders/covidtracking.py:40
322 | msgid "Maryland"
323 | msgstr "马里兰州"
324 |
325 | #: spider/nCoV/spiders/covidtracking.py:41
326 | msgid "Massachusetts"
327 | msgstr "马萨诸塞州"
328 |
329 | #: spider/nCoV/spiders/covidtracking.py:42
330 | msgid "Michigan"
331 | msgstr "密歇根州"
332 |
333 | #: spider/nCoV/spiders/covidtracking.py:43
334 | msgid "Minnesota"
335 | msgstr "明尼苏达州"
336 |
337 | #: spider/nCoV/spiders/covidtracking.py:44
338 | msgid "Mississippi"
339 | msgstr "密西西比州"
340 |
341 | #: spider/nCoV/spiders/covidtracking.py:45
342 | msgid "Missouri"
343 | msgstr "密苏里州"
344 |
345 | #: spider/nCoV/spiders/covidtracking.py:46
346 | msgid "Montana"
347 | msgstr "蒙大纳州"
348 |
349 | #: spider/nCoV/spiders/covidtracking.py:47
350 | msgid "Nebraska"
351 | msgstr "内布拉斯加州"
352 |
353 | #: spider/nCoV/spiders/covidtracking.py:48
354 | msgid "Nevada"
355 | msgstr "内华达州"
356 |
357 | #: spider/nCoV/spiders/covidtracking.py:49
358 | msgid "NewHampshire"
359 | msgstr "新罕布什尔州"
360 |
361 | #: spider/nCoV/spiders/covidtracking.py:50
362 | msgid "NewJersey"
363 | msgstr "新泽西州"
364 |
365 | #: spider/nCoV/spiders/covidtracking.py:51
366 | msgid "NewMexico"
367 | msgstr "新墨西哥州"
368 |
369 | #: spider/nCoV/spiders/covidtracking.py:52
370 | msgid "NewYork"
371 | msgstr "纽约州"
372 |
373 | #: spider/nCoV/spiders/covidtracking.py:53
374 | msgid "NorthCarolina"
375 | msgstr "北卡罗来纳州"
376 |
377 | #: spider/nCoV/spiders/covidtracking.py:54
378 | msgid "NorthDakota"
379 | msgstr "北达科他州"
380 |
381 | #: spider/nCoV/spiders/covidtracking.py:55
382 | msgid "NorthernMarianaIslands"
383 | msgstr "北马里亚纳群岛"
384 |
385 | #: spider/nCoV/spiders/covidtracking.py:56
386 | msgid "Ohio"
387 | msgstr "俄亥俄州"
388 |
389 | #: spider/nCoV/spiders/covidtracking.py:57
390 | msgid "Oklahoma"
391 | msgstr "俄克拉荷马州"
392 |
393 | #: spider/nCoV/spiders/covidtracking.py:58
394 | msgid "Oregon"
395 | msgstr "俄勒冈州"
396 |
397 | #: spider/nCoV/spiders/covidtracking.py:59
398 | msgid "Pennsylvania"
399 | msgstr "宾夕法尼亚州"
400 |
401 | #: spider/nCoV/spiders/covidtracking.py:60
402 | msgid "PuertoRico"
403 | msgstr "波多黎各"
404 |
405 | #: spider/nCoV/spiders/covidtracking.py:61
406 | msgid "RhodeIsland"
407 | msgstr "美国罗德岛州"
408 |
409 | #: spider/nCoV/spiders/covidtracking.py:62
410 | msgid "SouthCarolina"
411 | msgstr "美国南卡罗来纳州"
412 |
413 | #: spider/nCoV/spiders/covidtracking.py:63
414 | msgid "SouthDakota"
415 | msgstr "南达科塔"
416 |
417 | #: spider/nCoV/spiders/covidtracking.py:64
418 | msgid "Tennessee"
419 | msgstr "田纳西州"
420 |
421 | #: spider/nCoV/spiders/covidtracking.py:65
422 | msgid "Texas"
423 | msgstr "德克萨斯州"
424 |
425 | #: spider/nCoV/spiders/covidtracking.py:66
426 | msgid "USVirginIslands"
427 | msgstr "美属维尔京群岛"
428 |
429 | #: spider/nCoV/spiders/covidtracking.py:67
430 | msgid "Utah"
431 | msgstr "犹他州"
432 |
433 | #: spider/nCoV/spiders/covidtracking.py:68
434 | msgid "Vermont"
435 | msgstr "佛蒙特州"
436 |
437 | #: spider/nCoV/spiders/covidtracking.py:69
438 | msgid "Virginia"
439 | msgstr "弗吉尼亚州"
440 |
441 | #: spider/nCoV/spiders/covidtracking.py:70
442 | msgid "Washington"
443 | msgstr "华盛顿州"
444 |
445 | #: spider/nCoV/spiders/covidtracking.py:71
446 | msgid "WestVirginia"
447 | msgstr "西佛吉尼亚州"
448 |
449 | #: spider/nCoV/spiders/covidtracking.py:72
450 | msgid "Wisconsin"
451 | msgstr "威斯康星州"
452 |
453 | #: spider/nCoV/spiders/covidtracking.py:73
454 | msgid "Wyoming"
455 | msgstr "怀俄明州"
456 |
457 | #~ msgid "serialNumber"
458 | #~ msgstr "序号"
459 |
460 | #~ msgid "ID"
461 | #~ msgstr "编号"
462 |
463 | #~ msgid "locationId"
464 | #~ msgstr "地区编码"
465 |
466 | #~ msgid "provinceShortName"
467 | #~ msgstr "短省名"
468 |
469 | #~ msgid "State"
470 | #~ msgstr "州"
471 |
--------------------------------------------------------------------------------
/django_covid19/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/django_covid19/management/__init__.py
--------------------------------------------------------------------------------
/django_covid19/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/django_covid19/management/commands/__init__.py
--------------------------------------------------------------------------------
/django_covid19/management/commands/crawl.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import django_covid19
4 |
5 | app_dir = os.path.dirname(django_covid19.__file__)
6 | sys.path.insert(0, os.path.join(app_dir, 'spider'))
7 |
8 | from nCoV.spiders.dxy import DXYSpider
9 | from nCoV.spiders.covidtracking import CovidTrackingSpider
10 | from scrapy.crawler import CrawlerProcess
11 | from scrapy.utils.project import get_project_settings
12 | from django.core.management.base import BaseCommand
13 | from django.utils.translation import ugettext_lazy as _
14 |
15 | class Scraper:
16 | def __init__(self):
17 | settings_file_path = 'nCoV.settings'
18 | os.environ.setdefault('SCRAPY_SETTINGS_MODULE', settings_file_path)
19 | self.process = CrawlerProcess(get_project_settings())
20 | self.spider = DXYSpider
21 | self.covidtracking_spider = CovidTrackingSpider
22 |
23 | def run_spiders(self, spider):
24 | if spider == 'covidtracking':
25 | self.process.crawl(self.covidtracking_spider)
26 | else:
27 | self.process.crawl(self.spider)
28 | self.process.start()
29 |
30 | class Command(BaseCommand):
31 |
32 | help = _('Crawl data from DingXiangYuan.')
33 |
34 | def add_arguments(self, parser):
35 | parser.add_argument('spider', type=str, help='spider name')
36 |
37 | def handle(self, *args, **options):
38 | spider = options['spider']
39 | scraper = Scraper()
40 | scraper.run_spiders(spider)
41 |
--------------------------------------------------------------------------------
/django_covid19/management/commands/import_crc.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import django_covid19
3 | import os
4 | import posixpath
5 | import sys
6 |
7 | from django.conf import settings
8 | from django.core.management.base import BaseCommand
9 | from django.utils.translation import ugettext_lazy as _
10 |
11 | from django_covid19.models import CountryCode
12 |
13 | app_dir = os.path.dirname(django_covid19.__file__)
14 |
15 |
16 | class Command(BaseCommand):
17 |
18 | help = _('Import country codes.')
19 |
20 | def handle(self, *args, **options):
21 | path = posixpath.join(app_dir, 'data', 'CountryCodes.csv')
22 | reader = csv.DictReader(open(path))
23 | for r in reader:
24 | countryCode = r['countryCode']
25 | CountryCode.objects.update_or_create(
26 | countryCode=countryCode, defaults={
27 | "countryCode": countryCode,
28 | "numericCode": r['numericCode'],
29 | "shortCountryCode": r['shortCountryCode'],
30 | "countryName": r['countryName'],
31 | "englishCountryName": r['englishCountryName'],
32 | "englishCountryFullName": r['englishCountryFullName'],
33 | "comment": r['comment']
34 | })
35 |
--------------------------------------------------------------------------------
/django_covid19/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/django_covid19/migrations/__init__.py
--------------------------------------------------------------------------------
/django_covid19/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.utils import timezone
3 | from django_mysql.models import JSONField
4 | from django.utils.translation import ugettext_lazy as _
5 |
6 |
7 | class Statistics(models.Model):
8 |
9 | JSON_FIELDS = (
10 | 'globalStatistics', 'domesticStatistics', 'internationalStatistics',
11 | 'remarks', 'notes', 'WHOArticle', 'recommends', 'timelines',
12 | 'wikis', 'goodsGuides', 'rumors'
13 | )
14 |
15 | globalStatistics = models.TextField(_('globalStatistics'), default='{}')
16 | domesticStatistics = models.TextField(_('domesticStatistics'), default='{}')
17 | internationalStatistics = models.TextField(_('internationalStatistics'), default='{}')
18 | remarks = models.TextField(_('remarks'), default='[]')
19 | notes = models.TextField(_('notes'), default='[]')
20 | generalRemark = models.TextField(_('generalRemark'), default='')
21 | WHOArticle = models.TextField(_('WHOArticle'), default='{}')
22 | recommends = models.TextField(_('recommends'), default='[]')
23 | timelines = models.TextField(_('timelines'), default='[]')
24 | wikis = models.TextField(_('Wiki'), default='[]')
25 | goodsGuides = models.TextField(_('goodsGuides'), default='[]')
26 | rumors = models.TextField(_('rumors'), default='[]')
27 | modifyTime = models.DateTimeField(_('modifyTime'), null=True)
28 | createTime = models.DateTimeField(_('createTime'), null=True)
29 | crawlTime = models.DateTimeField(_('crawlTime'), default=timezone.now, editable=False)
30 |
31 | class Meta:
32 | verbose_name = _('Statistics')
33 | verbose_name_plural = _('Statistics')
34 |
35 |
36 | class Country(models.Model):
37 |
38 | continents = models.CharField(_('continents'), max_length=50)
39 | countryCode = models.CharField(_('countryCode'), max_length=20)
40 | countryName = models.CharField(_('countryName'), max_length=50)
41 | countryFullName = models.CharField(_('countryFullName'), max_length=50)
42 | currentConfirmedCount = models.IntegerField(_('currentConfirmedCount'), default=0)
43 | confirmedCount = models.IntegerField(_('confirmedCount'), default=0)
44 | suspectedCount = models.IntegerField(_('suspectedCount'), default=0)
45 | curedCount = models.IntegerField(_('curedCount'), default=0)
46 | deadCount = models.IntegerField(_('deadCount'), default=0)
47 |
48 | showRank = models.BooleanField(_('showRank'), default=False)
49 | deadRateRank = models.IntegerField(_('deadRateRank'), null=True)
50 | deadCountRank = models.IntegerField(_('deadCountRank'), null=True)
51 | confirmedCountRank = models.FloatField(_('confirmedCountRank'), null=True)
52 | deadRate = models.FloatField(_('deadRate'), null=True)
53 | tags = models.CharField(_('tags'), max_length=200, null=True)
54 | statisticsData = models.CharField(_('statisticsData'), max_length=500, null=True)
55 | comment = models.CharField(_('comment'), max_length=200, null=True)
56 | incrVo = models.TextField(_('incrVo'), null=True)
57 | sort = models.IntegerField(_('sort'), null=True)
58 | operator = models.CharField(_('operator'), max_length=50, null=True)
59 | dailyData = models.TextField(_('dailyData'))
60 | createTime = models.DateTimeField(_('createTime'), auto_now_add=True, editable=False)
61 | modifyTime = models.DateTimeField(_('modifyTime'), auto_now=True, editable=False)
62 |
63 | class Meta:
64 | verbose_name = _('Country')
65 | verbose_name_plural = _('Country')
66 |
67 |
68 | class Province(models.Model):
69 |
70 | countryCode = models.CharField(_('countryCode'), max_length=20)
71 | provinceName = models.CharField(_('provinceName'), max_length=50)
72 | provinceCode = models.CharField(_('provinceCode'), max_length=20)
73 | currentConfirmedCount = models.IntegerField(_('currentConfirmedCount'), default=0)
74 | confirmedCount = models.IntegerField(_('confirmedCount'), default=0)
75 | suspectedCount = models.IntegerField(_('suspectedCount'), default=0)
76 | curedCount = models.IntegerField(_('curedCount'), default=0)
77 | deadCount = models.IntegerField(_('deadCount'), default=0)
78 | dailyUrl = models.URLField(_('dailyUrl'), null=True, blank=True)
79 | currentUrl = models.URLField(_('currentUrl'), null=True, blank=True)
80 | dailyData = models.TextField(_('dailyData'), default='[]')
81 | createTime = models.DateTimeField(_('createTime'), auto_now_add=True, editable=False)
82 | modifyTime = models.DateTimeField(_('modifyTime'), auto_now=True, editable=False)
83 |
84 | class Meta:
85 | verbose_name = _('Province')
86 | verbose_name_plural = _('Province')
87 |
88 |
89 | class City(models.Model):
90 |
91 | countryCode = models.CharField(_('countryCode'), max_length=20)
92 | provinceCode = models.CharField(_('provinceCode'), max_length=20)
93 | provinceName = models.CharField(_('provinceName'), max_length=50)
94 | cityName = models.CharField(_('cityName'), max_length=50)
95 | currentConfirmedCount = models.IntegerField(_('currentConfirmedCount'), default=0)
96 | confirmedCount = models.IntegerField(_('confirmedCount'), default=0)
97 | suspectedCount = models.IntegerField(_('suspectedCount'), default=0)
98 | curedCount = models.IntegerField(_('curedCount'), default=0)
99 | deadCount = models.IntegerField(_('deadCount'), default=0)
100 | createTime = models.DateTimeField(_('createTime'), auto_now_add=True, editable=False)
101 | modifyTime = models.DateTimeField(_('modifyTime'), auto_now=True, editable=False)
102 |
103 | class Meta:
104 | verbose_name = _('City')
105 | verbose_name_plural = _('City')
106 |
107 |
108 | class CountryCode(models.Model):
109 |
110 | numericCode = models.IntegerField(_('numericCode'))
111 | countryCode = models.CharField(_('countryCode'), max_length=20)
112 | shortCountryCode = models.CharField(_('shortCountryCode'), max_length=5)
113 | countryName = models.CharField(_('countryName'), max_length=50)
114 | englishCountryName = models.CharField(_('englishCountryName'), max_length=50)
115 | englishCountryFullName = models.CharField(_('englishCountryFullName'), max_length=100)
116 | comment = models.CharField(_('comment'), max_length=200, null=True)
117 |
118 | class Meta:
119 | verbose_name = _('CountryCode')
120 | verbose_name_plural = _('CountryCode')
--------------------------------------------------------------------------------
/django_covid19/serializers.py:
--------------------------------------------------------------------------------
1 | from . import models
2 | from rest_framework import serializers
3 | from django.urls import reverse
4 | from django.utils.translation import ugettext_lazy as _
5 |
6 | import json
7 |
8 | class WHOArticleSerializer(serializers.Serializer):
9 |
10 | title = serializers.CharField(max_length=100)
11 | linkUrl = serializers.URLField()
12 | imgUrl = serializers.URLField()
13 |
14 |
15 | class RecommendSerializer(serializers.Serializer):
16 |
17 | title = serializers.CharField()
18 | linkUrl = serializers.URLField()
19 | imgUrl = serializers.URLField()
20 | contentType = serializers.IntegerField()
21 | recordStatus = serializers.IntegerField()
22 | countryType = serializers.IntegerField()
23 |
24 |
25 | class TimelineSerializer(serializers.Serializer):
26 |
27 | pubDate = serializers.IntegerField()
28 | pubDateStr = serializers.CharField()
29 | title = serializers.CharField()
30 | summary = serializers.CharField()
31 | infoSource = serializers.CharField()
32 | sourceUrl = serializers.URLField()
33 |
34 |
35 | class WikiSerializer(serializers.Serializer):
36 |
37 | title = serializers.CharField()
38 | linkUrl = serializers.URLField()
39 | imgUrl = serializers.URLField()
40 | description = serializers.CharField()
41 |
42 |
43 | class GoodsGuideSerializer(serializers.Serializer):
44 |
45 | title = serializers.CharField()
46 | categoryName = serializers.CharField()
47 | recordStatus = serializers.IntegerField()
48 | contentImgUrls = serializers.ListField(
49 | serializers.URLField(max_length=200), max_length=10)
50 |
51 |
52 | class RumorSerializer(serializers.Serializer):
53 |
54 | title = serializers.CharField()
55 | mainSummary = serializers.CharField()
56 | summary = serializers.CharField()
57 | body = serializers.CharField()
58 | sourceUrl = serializers.URLField()
59 | score = serializers.IntegerField()
60 | rumorType = serializers.IntegerField()
61 |
62 |
63 | class LatestStatisticsSerializer(serializers.Serializer):
64 |
65 | globalStatistics = serializers.DictField()
66 | domesticStatistics = serializers.DictField()
67 | internationalStatistics = serializers.DictField()
68 | remarks = serializers.JSONField()
69 | notes = serializers.ListField(
70 | child=serializers.CharField(max_length=100), max_length=10
71 | )
72 | generalRemark = serializers.CharField()
73 | WHOArticle = WHOArticleSerializer()
74 | recommends = RecommendSerializer(many=True)
75 | timelines = TimelineSerializer(many=True)
76 | wikis = WikiSerializer(many=True)
77 | goodsGuides = GoodsGuideSerializer(many=True)
78 | rumors = RumorSerializer(many=True)
79 | modifyTime = serializers.DateTimeField()
80 | createTime = serializers.DateTimeField()
81 |
82 |
83 | class StatisticsSerializer(serializers.Serializer):
84 |
85 | globalStatistics = serializers.DictField()
86 | domesticStatistics = serializers.DictField()
87 | internationalStatistics = serializers.DictField()
88 | modifyTime = serializers.DateTimeField()
89 | createTime = serializers.DateTimeField()
90 |
91 | class Meta:
92 | model = models.Statistics
93 | fields = (
94 | 'globalStatistics', 'domesticStatistics',
95 | 'internationalStatistics', 'modifyTime', 'createTime'
96 | )
97 |
98 |
99 | class CountrySerializer(serializers.ModelSerializer):
100 |
101 | def to_representation(self, inst):
102 | data = super().to_representation(inst)
103 | incrVo = data.get('incrVo')
104 | if incrVo:
105 | data['incrVo'] = json.loads(incrVo)
106 | return data
107 |
108 | class Meta:
109 | model = models.Country
110 | fields = [
111 | 'continents', 'countryCode', 'countryName',
112 | 'currentConfirmedCount', 'confirmedCount',
113 | 'suspectedCount', 'curedCount', 'deadCount', 'incrVo'
114 | ]
115 |
116 |
117 | class CountryDailySerializer(serializers.ModelSerializer):
118 |
119 | class Meta:
120 | model = models.Country
121 | fields = ['dailyData']
122 |
123 |
124 | class ProvinceSerializer(serializers.ModelSerializer):
125 |
126 | class Meta:
127 | model = models.Province
128 | fields = [
129 | 'countryCode', 'provinceCode', 'provinceName',
130 | 'currentConfirmedCount', 'confirmedCount', 'suspectedCount',
131 | 'curedCount', 'deadCount', 'dailyUrl', 'currentUrl'
132 | ]
133 |
134 |
135 | class ProvinceDailySerializer(serializers.ModelSerializer):
136 |
137 | class Meta:
138 | model = models.Province
139 | fields = ['provinceCode', 'provinceName', 'dailyData']
140 |
141 |
142 | class CitySerializer(serializers.ModelSerializer):
143 |
144 | class Meta:
145 | model = models.City
146 | fields = [
147 | 'provinceCode', 'provinceName', 'cityName',
148 | 'currentConfirmedCount', 'confirmedCount', 'suspectedCount',
149 | 'curedCount', 'deadCount'
150 | ]
151 |
152 |
153 | class CountryCodeSerializer(serializers.ModelSerializer):
154 |
155 | # 丁香园支持的国家编码
156 | DXY_COUNTRY_CODES = (
157 | 'ABW', 'AFG', 'AGO', 'AI', 'ALB', 'AND', 'ARE', 'ARG', 'ARM', 'ATG',
158 | 'AUS', 'AUT', 'AZE', 'BDI', 'BEL', 'BEN', 'BES', 'BFA', 'BGD',
159 | 'BGR', 'BHR', 'BHS', 'BIH', 'BL', 'BLR', 'BLZ', 'BMU', 'BOL', 'BRA',
160 | 'BRB', 'BRN', 'BTN', 'BWA', 'CAF', 'CAN', 'CHE', 'CHL', 'CHN',
161 | 'CIB', 'CIV', 'CMR', 'CNMI', 'COD', 'COG', 'COL', 'COM', 'CPV',
162 | 'CRI', 'CUB', 'CW', 'CYM', 'CYP', 'CZE', 'DEU', 'DJI', 'DMA', 'DNK',
163 | 'DOM', 'DZA', 'ECU', 'EGY', 'ERI', 'ESP', 'EST', 'ETH', 'FIN',
164 | 'FJI', 'FLK', 'FO', 'FRA', 'GAB', 'GBN', 'GBR', 'GEO', 'GG', 'GHA',
165 | 'GIN', 'GLP', 'GMB', 'GNQ', 'GRC', 'GRD', 'GRL', 'GTM', 'GU', 'GUF',
166 | 'GUY', 'HND', 'HRV', 'HTI', 'HUN', 'IDN', 'IND', 'IRL', 'IRN',
167 | 'IRQ', 'ISL', 'ISR', 'ITA', 'JAM', 'JE', 'JOR', 'JPN', 'KAZ', 'KEN',
168 | 'KGZ', 'KHM', 'KNA', 'KOR', 'KWT', 'LAO', 'LBN', 'LBR', 'LBY',
169 | 'LCA', 'LIE', 'LKA', 'LSO', 'LTU', 'LUX', 'LVA', 'MAR', 'MCO',
170 | 'MDA', 'MDG', 'MDV', 'MEX', 'MKD', 'MLI', 'MLT', 'MMR', 'MNE',
171 | 'MNG', 'MOZ', 'MRT', 'MS', 'MTQ', 'MUS', 'MWI', 'MYS', 'MYT',
172 | 'Mann', 'NAM', 'NCL', 'NER', 'NGA', 'NIC', 'NLD', 'NOR', 'NPL',
173 | 'NZL', 'OMN', 'PAK', 'PAN', 'PER', 'PHL', 'PNG', 'POL', 'PRI',
174 | 'PRT', 'PRY', 'PSE', 'PYF', 'Princess', 'QAT', 'REU', 'ROU', 'RUS',
175 | 'RWA', 'SAU', 'SDN', 'SEN', 'SGP', 'SLE', 'SLV', 'SMR', 'SOM',
176 | 'SPM', 'SRB', 'SSD', 'STP', 'SUR', 'SVK', 'SVN', 'SWE', 'SWZ',
177 | 'SYC', 'SYR', 'Saint Martin', 'Sint Maarten', 'TCA', 'TCD', 'TGO',
178 | 'THA', 'TJK', 'TLS', 'TTO', 'TUN', 'TUR', 'TZA', 'UGA', 'UKR',
179 | 'URY', 'USA', 'USVI', 'UZB', 'VAT', 'VCT', 'VEN', 'VG', 'VNM',
180 | 'YEM', 'ZAF', 'ZMB', 'ZWE')
181 |
182 | def to_representation(self, inst):
183 | data = super().to_representation(inst)
184 | context = self.context
185 | request = context['request']
186 | countryCode = data['countryCode']
187 | if countryCode not in self.DXY_COUNTRY_CODES:
188 | data['existApi'] = False
189 | data['currentApi'] = None
190 | data['dailyApi'] = None
191 | return data
192 | kwargs = { 'countryCode': countryCode }
193 | data['existApi'] = True
194 | data['currentApi'] = request.build_absolute_uri(reverse(
195 | 'django_covid19:country-detail', kwargs=kwargs))
196 | data['dailyApi'] = request.build_absolute_uri(reverse(
197 | 'django_covid19:country-daily', kwargs=kwargs))
198 | return data
199 |
200 | class Meta:
201 | model = models.CountryCode
202 | fields = [
203 | 'numericCode', 'countryCode', 'shortCountryCode', 'countryName',
204 | 'englishCountryName', 'englishCountryFullName', 'comment'
205 | ]
206 |
--------------------------------------------------------------------------------
/django_covid19/settings.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 |
3 | CACHE_PAGE_TIMEOUT = getattr(settings, 'CACHE_PAGE_TIMEOUT', 24*60*60)
4 |
5 | SCRAPY_LOG_FILE = getattr(settings, 'SCRAPY_LOG_FILE', None)
--------------------------------------------------------------------------------
/django_covid19/signals.py:
--------------------------------------------------------------------------------
1 | from django.dispatch import receiver
2 | from django.core.cache import cache
3 | from django.core.signals import request_finished
4 |
5 | @receiver(request_finished)
6 | def spider_callback(sender, **kwargs):
7 | if cache.get('crawled'):
8 | cache.clear()
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/django_covid19/spider/nCoV/__init__.py
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/items.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define here the models for your scraped items
4 | #
5 | # See documentation in:
6 | # https://docs.scrapy.org/en/latest/topics/items.html
7 |
8 | import scrapy
9 |
10 | from scrapy_djangoitem import DjangoItem
11 | from django_covid19 import models
12 |
13 |
14 | class StatisticsItem(DjangoItem):
15 |
16 | django_model = models.Statistics
17 |
18 |
19 | class ProvinceItem(DjangoItem):
20 |
21 | django_model = models.Province
22 |
23 |
24 | class CountryItem(DjangoItem):
25 |
26 | django_model = models.Country
27 |
28 |
29 | class CityItem(DjangoItem):
30 |
31 | django_model = models.City
32 |
33 | # class StateItem(DjangoItem):
34 |
35 | # django_model = models.State
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/middlewares.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define here the models for your spider middleware
4 | #
5 | # See documentation in:
6 | # https://docs.scrapy.org/en/latest/topics/spider-middleware.html
7 |
8 | from scrapy import signals
9 |
10 |
11 | class NcovSpiderMiddleware(object):
12 | # Not all methods need to be defined. If a method is not defined,
13 | # scrapy acts as if the spider middleware does not modify the
14 | # passed objects.
15 |
16 | @classmethod
17 | def from_crawler(cls, crawler):
18 | # This method is used by Scrapy to create your spiders.
19 | s = cls()
20 | crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
21 | return s
22 |
23 | def process_spider_input(self, response, spider):
24 | # Called for each response that goes through the spider
25 | # middleware and into the spider.
26 |
27 | # Should return None or raise an exception.
28 | return None
29 |
30 | def process_spider_output(self, response, result, spider):
31 | # Called with the results returned from the Spider, after
32 | # it has processed the response.
33 |
34 | # Must return an iterable of Request, dict or Item objects.
35 | for i in result:
36 | yield i
37 |
38 | def process_spider_exception(self, response, exception, spider):
39 | # Called when a spider or process_spider_input() method
40 | # (from other spider middleware) raises an exception.
41 |
42 | # Should return either None or an iterable of Request, dict
43 | # or Item objects.
44 | pass
45 |
46 | def process_start_requests(self, start_requests, spider):
47 | # Called with the start requests of the spider, and works
48 | # similarly to the process_spider_output() method, except
49 | # that it doesn’t have a response associated.
50 |
51 | # Must return only requests (not items).
52 | for r in start_requests:
53 | yield r
54 |
55 | def spider_opened(self, spider):
56 | spider.logger.info('Spider opened: %s' % spider.name)
57 |
58 |
59 | class NcovDownloaderMiddleware(object):
60 | # Not all methods need to be defined. If a method is not defined,
61 | # scrapy acts as if the downloader middleware does not modify the
62 | # passed objects.
63 |
64 | @classmethod
65 | def from_crawler(cls, crawler):
66 | # This method is used by Scrapy to create your spiders.
67 | s = cls()
68 | crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
69 | return s
70 |
71 | def process_request(self, request, spider):
72 | # Called for each request that goes through the downloader
73 | # middleware.
74 |
75 | # Must either:
76 | # - return None: continue processing this request
77 | # - or return a Response object
78 | # - or return a Request object
79 | # - or raise IgnoreRequest: process_exception() methods of
80 | # installed downloader middleware will be called
81 | return None
82 |
83 | def process_response(self, request, response, spider):
84 | # Called with the response returned from the downloader.
85 |
86 | # Must either;
87 | # - return a Response object
88 | # - return a Request object
89 | # - or raise IgnoreRequest
90 | return response
91 |
92 | def process_exception(self, request, exception, spider):
93 | # Called when a download handler or a process_request()
94 | # (from other downloader middleware) raises an exception.
95 |
96 | # Must either:
97 | # - return None: continue processing this exception
98 | # - return a Response object: stops process_exception() chain
99 | # - return a Request object: stops process_exception() chain
100 | pass
101 |
102 | def spider_opened(self, spider):
103 | spider.logger.info('Spider opened: %s' % spider.name)
104 |
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/pipelines.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Define your item pipelines here
4 | #
5 | # Don't forget to add your pipeline to the ITEM_PIPELINES setting
6 | # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
7 |
8 | import os
9 | import json
10 | import sqlite3
11 | from uuid import uuid4
12 |
13 | from django.core.cache import cache
14 |
15 | from . import items
16 |
17 | class BasePipeline(object):
18 |
19 | def open_spider(self, spider):
20 | spider.object_id = uuid4().hex
21 | cache.set('running_spider_id', spider.object_id)
22 | spider.crawled = 0
23 |
24 | def close_spider(self, spider):
25 | cache.set('crawled', spider.crawled)
26 | cache.delete('running_spider_id')
27 |
28 |
29 | class CovidTrackingPipeline(BasePipeline):
30 |
31 | def process_item(self, item, spider):
32 | if isinstance(item, items.ProvinceItem) \
33 | and item['countryCode'] == 'USA':
34 | provinceCode = item['provinceCode']
35 | countryCode = item['countryCode']
36 | items.ProvinceItem.django_model.objects.update_or_create(
37 | countryCode=countryCode,
38 | provinceCode=provinceCode,
39 | defaults=item)
40 | return item
41 |
42 |
43 | class NcovPipeline(BasePipeline):
44 |
45 | def process_item(self, item, spider):
46 | if isinstance(item, items.CityItem):
47 | countryCode = item['countryCode']
48 | provinceCode = item['provinceCode']
49 | items.CityItem.django_model.objects.update_or_create(
50 | countryCode=countryCode,
51 | provinceCode=provinceCode,
52 | cityName=item['cityName'],
53 | defaults=item)
54 | return item
55 | elif isinstance(item, items.ProvinceItem) \
56 | and item['countryCode'] == 'CHN':
57 | items.ProvinceItem.django_model.objects.update_or_create(
58 | provinceName=item['provinceName'],
59 | defaults=item)
60 | return item
61 | elif isinstance(item, items.CountryItem):
62 | items.CountryItem.django_model.objects.update_or_create(
63 | countryName=item['countryName'],
64 | defaults=item)
65 | return item
66 | elif isinstance(item, items.StatisticsItem):
67 | klass = item.__class__
68 | klass.django_model.objects.create(**item)
69 | return item
70 | else:
71 | return item
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/settings.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Scrapy settings for nCoV project
4 | #
5 | # For simplicity, this file contains only settings considered important or
6 | # commonly used. You can find more settings consulting the documentation:
7 | #
8 | # https://docs.scrapy.org/en/latest/topics/settings.html
9 | # https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
10 | # https://docs.scrapy.org/en/latest/topics/spider-middleware.html
11 |
12 | BOT_NAME = 'nCoV'
13 |
14 | SPIDER_MODULES = ['nCoV.spiders']
15 | NEWSPIDER_MODULE = 'nCoV.spiders'
16 |
17 |
18 | # Crawl responsibly by identifying yourself (and your website) on the user-agent
19 | USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5'
20 |
21 | # Obey robots.txt rules
22 | ROBOTSTXT_OBEY = False
23 |
24 | # Configure maximum concurrent requests performed by Scrapy (default: 16)
25 | #CONCURRENT_REQUESTS = 32
26 |
27 | # Configure a delay for requests for the same website (default: 0)
28 | # See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
29 | # See also autothrottle settings and docs
30 | #DOWNLOAD_DELAY = 3
31 | # The download delay setting will honor only one of:
32 | #CONCURRENT_REQUESTS_PER_DOMAIN = 16
33 | #CONCURRENT_REQUESTS_PER_IP = 16
34 |
35 | # Disable cookies (enabled by default)
36 | #COOKIES_ENABLED = False
37 |
38 | # Disable Telnet Console (enabled by default)
39 | #TELNETCONSOLE_ENABLED = False
40 |
41 | # Override the default request headers:
42 | #DEFAULT_REQUEST_HEADERS = {
43 | # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
44 | # 'Accept-Language': 'en',
45 | #}
46 |
47 | # Enable or disable spider middlewares
48 | # See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
49 | #SPIDER_MIDDLEWARES = {
50 | # 'nCoV.middlewares.NcovSpiderMiddleware': 543,
51 | #}
52 |
53 | # Enable or disable downloader middlewares
54 | # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
55 | #DOWNLOADER_MIDDLEWARES = {
56 | # 'nCoV.middlewares.NcovDownloaderMiddleware': 543,
57 | #}
58 |
59 | # Enable or disable extensions
60 | # See https://docs.scrapy.org/en/latest/topics/extensions.html
61 | #EXTENSIONS = {
62 | # 'scrapy.extensions.telnet.TelnetConsole': None,
63 | #}
64 |
65 | # Configure item pipelines
66 | # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
67 | ITEM_PIPELINES = {
68 | 'nCoV.pipelines.NcovPipeline': 300,
69 | 'nCoV.pipelines.CovidTrackingPipeline': 400
70 | }
71 |
72 | # Enable and configure the AutoThrottle extension (disabled by default)
73 | # See https://docs.scrapy.org/en/latest/topics/autothrottle.html
74 | #AUTOTHROTTLE_ENABLED = True
75 | # The initial download delay
76 | #AUTOTHROTTLE_START_DELAY = 5
77 | # The maximum download delay to be set in case of high latencies
78 | #AUTOTHROTTLE_MAX_DELAY = 60
79 | # The average number of requests Scrapy should be sending in parallel to
80 | # each remote server
81 | #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
82 | # Enable showing throttling stats for every response received:
83 | #AUTOTHROTTLE_DEBUG = False
84 |
85 | # Enable and configure HTTP caching (disabled by default)
86 | # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
87 | #HTTPCACHE_ENABLED = True
88 | #HTTPCACHE_EXPIRATION_SECS = 0
89 | #HTTPCACHE_DIR = 'httpcache'
90 | #HTTPCACHE_IGNORE_HTTP_CODES = []
91 | #HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
92 |
93 | # Get settings from django
94 | from django.conf import settings
95 |
96 | for name in dir(settings):
97 | if not name.startswith('SCRAPY_'):
98 | continue
99 | scrapy_name = name[7:]
100 | globals()[scrapy_name] = getattr(settings, name, None)
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/spiders/__init__.py:
--------------------------------------------------------------------------------
1 | # This package will contain the spiders of your Scrapy project
2 | #
3 | # Please refer to the documentation for information on how to create and manage
4 | # your spiders.
5 |
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/spiders/covidtracking.py:
--------------------------------------------------------------------------------
1 | """美国各州疫情数据源"""
2 |
3 | import json
4 | import scrapy
5 | import logging
6 | from scrapy.selector import Selector
7 |
8 | from .. import items
9 |
10 | from django.core.cache import cache
11 | from django.utils.timezone import datetime, make_aware
12 | from django.utils.translation import ugettext_lazy as _
13 |
14 | logger = logging.getLogger()
15 |
16 | # For state i18n
17 | STATES = {
18 | "Alabama": _("Alabama"),
19 | "Alaska": _("Alaska"),
20 | "AmericanSamoa": _("AmericanSamoa"),
21 | "Arizona": _("Arizona"),
22 | "Arkansas": _("Arkansas"),
23 | "California": _("California"),
24 | "Colorado": _("Colorado"),
25 | "Connecticut": _("Connecticut"),
26 | "Delaware": _("Delaware"),
27 | "DistrictOfColumbia": _("DistrictOfColumbia"),
28 | "Florida": _("Florida"),
29 | "Georgia": _("Georgia"),
30 | "Guam": _("Guam"),
31 | "Hawaii": _("Hawaii"),
32 | "Idaho": _("Idaho"),
33 | "Illinois": _("Illinois"),
34 | "Indiana": _("Indiana"),
35 | "Iowa": _("Iowa"),
36 | "Kansas": _("Kansas"),
37 | "Kentucky": _("Kentucky"),
38 | "Louisiana": _("Louisiana"),
39 | "Maine": _("Maine"),
40 | "Maryland": _("Maryland"),
41 | "Massachusetts": _("Massachusetts"),
42 | "Michigan": _("Michigan"),
43 | "Minnesota": _("Minnesota"),
44 | "Mississippi": _("Mississippi"),
45 | "Missouri": _("Missouri"),
46 | "Montana": _("Montana"),
47 | "Nebraska": _("Nebraska"),
48 | "Nevada": _("Nevada"),
49 | "NewHampshire": _("NewHampshire"),
50 | "NewJersey": _("NewJersey"),
51 | "NewMexico": _("NewMexico"),
52 | "NewYork": _("NewYork"),
53 | "NorthCarolina": _("NorthCarolina"),
54 | "NorthDakota": _("NorthDakota"),
55 | "NorthernMarianaIslands": _("NorthernMarianaIslands"),
56 | "Ohio": _("Ohio"),
57 | "Oklahoma": _("Oklahoma"),
58 | "Oregon": _("Oregon"),
59 | "Pennsylvania": _("Pennsylvania"),
60 | "PuertoRico": _("PuertoRico"),
61 | "RhodeIsland": _("RhodeIsland"),
62 | "SouthCarolina": _("SouthCarolina"),
63 | "SouthDakota": _("SouthDakota"),
64 | "Tennessee": _("Tennessee"),
65 | "Texas": _("Texas"),
66 | "USVirginIslands": _("USVirginIslands"),
67 | "Utah": _("Utah"),
68 | "Vermont": _("Vermont"),
69 | "Virginia": _("Virginia"),
70 | "Washington": _("Washington"),
71 | "WestVirginia": _("WestVirginia"),
72 | "Wisconsin": _("Wisconsin"),
73 | "Wyoming": _("Wyoming")
74 | }
75 |
76 | class CovidTrackingSpider(scrapy.Spider):
77 |
78 | """Data source: https://covidtracking.com/api
79 |
80 | Covidtracking update all the data each day between 4pm and 5pm EDT.
81 | """
82 |
83 | name = "covidtracking"
84 | allowed_domains = ["covidtracking.com"]
85 |
86 | # custom attributes
87 | daily_state_url_template = \
88 | 'https://covidtracking.com/api/v1/states/%s/daily.json'
89 | current_state_url_template = \
90 | 'https://covidtracking.com/api/v1/states/%s/current.json'
91 | countryCode = 'USA'
92 | states = {}
93 |
94 | def start_requests(self):
95 | object_id = self.object_id
96 | spider_id = cache.get('running_spider_id')
97 | if object_id != spider_id:
98 | logger.info('Spider is running.')
99 | self.crawled = 0
100 | return
101 |
102 | yield scrapy.Request(
103 | 'https://covidtracking.com/api/v1/states/info.json',
104 | self.parse_info)
105 |
106 | def parse_info(self, response):
107 | countryCode = self.countryCode
108 | states = self.states
109 | result = json.loads(response.text)
110 | for item in result:
111 | state = item['state']
112 | state_name = item['name']
113 | state_name = ''.join(state_name.split())
114 | states[state] = {
115 | 'state': state,
116 | 'countryCode': countryCode,
117 | 'stateName': state_name
118 | }
119 | yield scrapy.Request(
120 | 'https://covidtracking.com/api/v1/states/current.json',
121 | self.parse_current_states)
122 |
123 | def parse_current_states(self, response):
124 | countryCode = self.countryCode
125 | states = self.states
126 | result = json.loads(response.text)
127 | for item in result:
128 | state = item['state']
129 | daily_state_url = self.daily_state_url_template % state.lower()
130 | current_state_url = self.current_state_url_template % state.lower()
131 | state_item = states[state]
132 | state_item.update(item)
133 | state_item.pop('grade', None)
134 | state_item.pop('total', None)
135 | state_item['countryCode'] = countryCode
136 | state_item['currentUrl'] = current_state_url
137 | state_item['dailyUrl'] = daily_state_url
138 | yield scrapy.Request(
139 | daily_state_url,
140 | self.parse_daily_state,
141 | meta={'state_item': state_item})
142 |
143 | self.crawled = 1 # 代表爬虫已爬取数据
144 |
145 | def parse_daily_state(self, response):
146 | meta = response.meta
147 | province = meta['state_item']
148 | dailyData = json.loads(response.text)[::-1]
149 | countryCode = self.countryCode
150 | provinceCode = province['state']
151 | provinceName = province['stateName']
152 | formated_dailyData = []
153 | for daily_item in dailyData:
154 | formated_dailyData.append(
155 | self.format(countryCode, provinceName, daily_item))
156 | province_args = {}
157 | provice_fieldnames = [f.name for f in \
158 | items.ProvinceItem.django_model._meta.get_fields()]
159 | for fieldname in provice_fieldnames:
160 | value = province.get(fieldname)
161 | if value is not None:
162 | province_args[fieldname] = value
163 | province_args['provinceName'] = provinceName
164 | province_args['provinceCode'] = provinceCode
165 | province_args['dailyData'] = json.dumps(formated_dailyData)
166 | yield items.ProvinceItem(**province_args)
167 |
168 | def format(self, countryCode, stateName, data):
169 | item = {}
170 | item['dateId'] = data['date']
171 | item['provinceCode'] = data['state']
172 | item['provinceName'] = stateName
173 | item['countryCode'] = countryCode
174 |
175 | item['confirmedCount'] = data.get('positive')
176 | item['currentConfirmedCount'] = self.get_current_confirmed(data)
177 | item['suspectedCount'] = data.get('pending')
178 | item['curedCount'] = data.get('recovered')
179 | item['deadCount'] = data.get('death')
180 |
181 | item['currentConfirmedIncr'] = self.get_current_confirmed_incr(data)
182 | item['confirmedIncr'] = data.get('positiveIncrease')
183 | item['suspectedIncr'] = data.get('totalTestResultsIncrease')
184 | item['curedIncr'] = None # 未提供
185 | item['deadIncr'] = data.get('deathIncrease')
186 | return item
187 |
188 | def get_current_confirmed(self, data):
189 | positive = data['positive'] if data.get('positive') else 0
190 | death = data['death'] if data.get('death') else 0
191 | recovered = data['recovered'] if data.get('recovered') else 0
192 | return positive - death - recovered
193 |
194 | def get_current_confirmed_incr(self, data):
195 | positive = data['positiveIncrease'] if data.get('positiveIncrease') else 0
196 | death = data['deathIncrease'] if data.get('deathIncrease') else 0
197 | return positive - death
198 |
--------------------------------------------------------------------------------
/django_covid19/spider/nCoV/spiders/dxy.py:
--------------------------------------------------------------------------------
1 | """丁香园数据源"""
2 |
3 | import json
4 | import scrapy
5 | import logging
6 | from scrapy.selector import Selector
7 |
8 | from .. import items
9 |
10 | from django.core.cache import cache
11 | from django.utils.timezone import datetime, make_aware
12 |
13 | logger = logging.getLogger()
14 |
15 | PROVINCE_CODES = {
16 | "黑龙江": "HLJ",
17 | "香港": "XG",
18 | "青海": "QH",
19 | "陕西": "SX", # 同山西
20 | "重庆": "CQ",
21 | "辽宁": "LN",
22 | "贵州": "GZ",
23 | "西藏": "XZ",
24 | "福建": "FJ",
25 | "甘肃": "GS",
26 | "澳门": "AM",
27 | "湖南": "HN",
28 | "湖北": "HB",
29 | "海南": "HN-2",
30 | "浙江": "ZJ",
31 | "河南": "HN-1",
32 | "河北": "HB-1",
33 | "江西": "JX",
34 | "江苏": "JS",
35 | "新疆": "XJ",
36 | "广西": "GX",
37 | "广东": "GD",
38 | "山西": "SX-1",
39 | "山东": "SD",
40 | "安徽": "AH",
41 | "宁夏": "NX",
42 | "天津": "TJ",
43 | "四川": "SC",
44 | "吉林": "JL",
45 | "台湾": "TW",
46 | "北京": "BJ",
47 | "内蒙古": "NMG",
48 | "云南": "YN",
49 | "上海": "SH"
50 | }
51 |
52 | COUNTRY_CODE_FIX = {
53 | 'Princess': 'PRINCESS',
54 | 'Saint Martin': 'MAF',
55 | 'Sint Maarten': 'SXM'
56 | }
57 |
58 | class DXYSpider(scrapy.Spider):
59 |
60 | name = "dxy"
61 | allowed_domains = ["ncov.dxy.cn", "file1.dxycdn.com"]
62 | start_urls = [
63 | "http://ncov.dxy.cn/ncovh5/view/pneumonia",
64 | ]
65 |
66 | countryCode = 'CHN'
67 |
68 | def parse(self, response):
69 | object_id = self.object_id
70 | spider_id = cache.get('running_spider_id')
71 | if object_id != spider_id:
72 | logger.info('Spider is running.')
73 | self.crawled = 0
74 | return
75 |
76 | sel = Selector(response)
77 | scripts = sel.xpath('//script')
78 |
79 | # 判断是否需要保存抓取的数据
80 | statistics = self.get_dict(scripts, '#getStatisticsService')
81 | create_time = make_aware(
82 | datetime.fromtimestamp(statistics['createTime'] / 1000.0))
83 | modify_time = make_aware(
84 | datetime.fromtimestamp(statistics['modifyTime'] / 1000.0))
85 | qs = items.StatisticsItem.django_model.objects.all().order_by('-id')
86 | if qs.count() > 1 and qs[0].modifyTime == modify_time:
87 | logger.info('Data does not change.')
88 | self.crawled = 0
89 | return
90 |
91 | # 统计信息
92 | statistics = self.explain_statistics(statistics)
93 | statistics['createTime'] = create_time
94 | statistics['modifyTime'] = modify_time
95 |
96 | # 国内数据
97 | provinces = self.get_list(scripts, '#getAreaStat')
98 | for province in provinces:
99 | cities = province.pop('cities', [])
100 | province.pop('locationId')
101 | yield scrapy.Request(
102 | province['statisticsData'],
103 | callback=self.parse_province_statistics_data,
104 | meta={
105 | 'province': province,
106 | 'cities': cities
107 | }
108 | )
109 |
110 | # 时间线事件,id=“getTimelineService2” 为英文内容
111 | timelines = self.get_list(scripts, '#getTimelineService1')
112 | result = []
113 | for item in timelines:
114 | timeline = {}
115 | for key in ('title', 'summary', 'infoSource', 'sourceUrl',
116 | 'pubDate', 'pubDateStr'):
117 | timeline[key] = item.get(key)
118 | result.append(timeline)
119 | statistics['timelines'] = json.dumps(result)
120 |
121 | # 建议,id=“#getIndexRecommendList2” 为英文内容
122 | recommends = self.get_list(scripts, '#getIndexRecommendList2')
123 | result = []
124 | for item in recommends:
125 | recommend = {}
126 | for key in ('title', 'linkUrl', 'imgUrl', 'countryType',
127 | 'contentType', 'recordStatus', 'sort'):
128 | recommend[key] = item.get(key)
129 | result.append(recommend)
130 | statistics['recommends'] = json.dumps(result)
131 |
132 | # WHO 文章
133 | item = self.get_dict(scripts, '#fetchWHOArticle')
134 | article = {}
135 | for key in ('title', 'linkUrl', 'imgUrl'):
136 | article[key] = item.get(key)
137 | statistics['WHOArticle'] = json.dumps(article)
138 |
139 | # wiki
140 | wiki_result = self.get_dict(scripts, '#getWikiList')
141 | wikis = wiki_result['result']
142 | result = []
143 | for item in wikis:
144 | wiki = {}
145 | for key in ('title', 'linkUrl', 'imgUrl', 'description'):
146 | wiki[key] = item.get(key)
147 | result.append(wiki)
148 | statistics['wikis'] = json.dumps(result)
149 |
150 |
151 | # 购物指南
152 | guides = self.get_list(scripts, '#fetchGoodsGuide')
153 | result = []
154 | for item in guides:
155 | guide = {}
156 | for key in ('categoryName', 'title', 'recordStatus',
157 | 'contentImgUrls'):
158 | guide[key] = item.get(key)
159 | result.append(guide)
160 | statistics['goodsGuides'] = json.dumps(result)
161 |
162 | # 辟谣与防护
163 | # 丁香园页面已无“辟谣与防护”的文本类型数据,取消该数据
164 | statistics['rumors'] = {}
165 | yield statistics
166 |
167 | # 国外数据
168 | countries = self.get_list(
169 | scripts, '#getListByCountryTypeService2true')
170 | for country in countries:
171 | country.pop('id', None)
172 | country['countryName'] = country.pop('provinceName', None)
173 | country['provinceName'] = ''
174 | country.pop('countryType')
175 | country.pop('cityName')
176 | country.pop('provinceId')
177 | country.pop('provinceName')
178 | country.pop('provinceShortName')
179 | country.pop('modifyTime', None)
180 | country.pop('createTime', None)
181 | country['incrVo'] = json.dumps(country.get('incrVo', {}))
182 | statistics_data = country.get('statisticsData')
183 | if statistics_data:
184 | yield scrapy.Request(
185 | statistics_data,
186 | callback=self.parse_country_statistics_data,
187 | meta={
188 | 'country': country
189 | }
190 | )
191 | else:
192 | yield items.CountryItem(dailyData=[], **country)
193 |
194 | self.crawled = 1 # 代表爬虫已爬取数据
195 |
196 | def parse_province_statistics_data(self, response):
197 | countryCode = self.countryCode
198 | meta = response.meta
199 | cities = meta['cities']
200 | province = meta['province']
201 | provinceName = province['provinceShortName']
202 | provinceCode = PROVINCE_CODES[provinceName]
203 | result = json.loads(response.text)
204 | dailyData = result['data']
205 | for item in dailyData:
206 | item['countryCode'] = countryCode
207 | item['provinceName'] = provinceName
208 | item['provinceCode'] = provinceCode
209 | data = json.dumps(dailyData)
210 | province['provinceName'] = provinceName
211 | province_args = {}
212 | provice_fieldnames = [f.name for f in \
213 | items.ProvinceItem.django_model._meta.get_fields()]
214 | for fieldname in provice_fieldnames:
215 | value = province.get(fieldname)
216 | if value is not None:
217 | province_args[fieldname] = value
218 | province_args['dailyData'] = data
219 | province_args['dailyUrl'] = province.get('statisticsData')
220 | province_args['countryCode'] = countryCode
221 | province_args['provinceCode'] = provinceCode
222 | yield items.ProvinceItem(**province_args)
223 |
224 | for city in cities:
225 | city.pop('locationId')
226 | yield items.CityItem(
227 | countryCode=countryCode,
228 | provinceCode=provinceCode,
229 | provinceName=provinceName,
230 | **city
231 | )
232 |
233 | def parse_country_statistics_data(self, response):
234 | result = json.loads(response.text)
235 | dailyData = result['data']
236 | meta = response.meta
237 | country = meta['country']
238 | country.pop('locationId')
239 | country['countryCode'] = countryCode \
240 | = country.pop('countryShortCode')
241 | countryCode = COUNTRY_CODE_FIX.get(countryCode, countryCode)
242 | for item in dailyData:
243 | item['countryCode'] = countryCode
244 | item['countryName'] = country['countryName']
245 | dailyData = json.dumps(dailyData)
246 | yield items.CountryItem(dailyData=dailyData, **country)
247 |
248 | def explain_statistics(self, data):
249 | statistics = data['globalStatistics']
250 | instance = {}
251 | item = {}
252 | for key in (
253 | 'currentConfirmedCount', 'curedCount', 'confirmedCount',
254 | 'seriousCount', 'suspectedCount', 'deadCount',
255 | 'currentConfirmedIncr', 'curedIncr', 'confirmedIncr',
256 | 'suspectedIncr', 'deadIncr'):
257 | item[key] = statistics.get(key, 0)
258 | instance['globalStatistics'] = json.dumps(item)
259 |
260 | statistics = data['foreignStatistics']
261 | item = {}
262 | for key in (
263 | 'currentConfirmedCount', 'curedCount', 'confirmedCount',
264 | 'seriousCount', 'suspectedCount', 'deadCount',
265 | 'currentConfirmedIncr', 'curedIncr', 'confirmedIncr',
266 | 'suspectedIncr', 'deadIncr'):
267 | item[key] = statistics.get(key, 0)
268 | instance['internationalStatistics'] = json.dumps(item)
269 |
270 |
271 | statistics = data
272 | item = {}
273 | for key in (
274 | 'currentConfirmedCount', 'curedCount', 'confirmedCount',
275 | 'seriousCount', 'suspectedCount', 'deadCount',
276 | 'currentConfirmedIncr', 'curedIncr', 'confirmedIncr',
277 | 'suspectedIncr', 'deadIncr'):
278 | item[key] = statistics.get(key, 0)
279 | instance['domesticStatistics'] = json.dumps(item)
280 |
281 | # Remark and Note
282 | remarks = []
283 | for key in ('remark1', 'remark2', 'remark3', 'remark4', 'remark5'):
284 | remark = data.get(key)
285 | if remark:
286 | remarks.append(remark)
287 |
288 | notes = []
289 | for key in ('note1', 'note2', 'note3'):
290 | note = data.get(key)
291 | if note:
292 | notes.append(note)
293 |
294 | instance['remarks'] = json.dumps(remarks)
295 | instance['notes'] = json.dumps(notes)
296 | instance['generalRemark'] = data.get('generalRemark')
297 | return items.StatisticsItem(**instance)
298 |
299 | def get_list(self, scripts, data_id):
300 | ret = scripts.css(data_id).re(r'(\[.+\])')
301 | return json.loads(ret[0])
302 |
303 | def get_dict(self, scripts, data_id):
304 | ret = scripts.css(data_id).re(r'\=\s*(\{.+\})\}catch\(e\)\{\}')
305 | return json.loads(ret[0])
306 |
--------------------------------------------------------------------------------
/django_covid19/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 | from django.test.client import Client as DjangoClient
3 |
4 | from django.urls import reverse
5 |
6 | # Create your tests here.
7 |
8 | class StatisticsTestCase(TestCase):
9 |
10 | """Supporting Chinese cities only."""
11 |
12 | fixtures = ['statistics.json']
13 |
14 | def test_list_view_status_code(self):
15 | url = reverse('django_covid19:statistics-list')
16 | response = self.client.get(url)
17 | self.assertEquals(response.status_code, 200)
18 |
19 | def test_latest_view_status_code(self):
20 | url = reverse('django_covid19:statistics-latest')
21 | response = self.client.get(url)
22 | self.assertEquals(response.status_code, 200)
23 |
24 |
25 | class CountriesTestCase(TestCase):
26 |
27 | fixtures = ['country.json']
28 | countryCode = 'USA'
29 |
30 | def test_list_view_status_code(self):
31 | url = reverse('django_covid19:country-list')
32 | response = self.client.get(url)
33 | self.assertEquals(response.status_code, 200)
34 | for item in response.json():
35 | self.assertEquals('countryCode' in item, True)
36 | self.assertEquals('countryName' in item, True)
37 | self.assertEquals('continents' in item, True)
38 |
39 | def test_list_daily_view_status_code(self):
40 | url = reverse('django_covid19:country-list-daily')
41 | response = self.client.get(url)
42 | self.assertEquals(response.status_code, 200)
43 |
44 | def test_detail_view_status_code(self):
45 | kwargs = {'countryCode': self.countryCode}
46 | url = reverse('django_covid19:country-detail', kwargs=kwargs)
47 | response = self.client.get(url)
48 | self.assertEquals(response.status_code, 200)
49 |
50 | def test_daily_view_status_code(self):
51 | kwargs = {'countryCode': self.countryCode}
52 | url = reverse('django_covid19:country-daily', kwargs=kwargs)
53 | response = self.client.get(url)
54 | self.assertEquals(response.status_code, 200)
55 |
56 |
57 | class ProvincesTestCase(TestCase):
58 |
59 | fixtures = ['province.json']
60 |
61 | countryCode = 'USA'
62 | provinceCode = 'AL'
63 | provinceName = 'Alabama'
64 |
65 | def test_list_view_status_code(self):
66 | kwargs = {'countryCode': self.countryCode}
67 | url = reverse('django_covid19:province-list', kwargs=kwargs)
68 | response = self.client.get(url)
69 | self.assertEquals(response.status_code, 200)
70 |
71 | def test_list_daily_view_status_code(self):
72 | kwargs = {'countryCode': self.countryCode}
73 | url = reverse('django_covid19:province-list-daily', kwargs=kwargs)
74 | response = self.client.get(url)
75 | self.assertEquals(response.status_code, 200)
76 |
77 | def test_daily_view_status_code(self):
78 | kwargs = {
79 | 'countryCode': self.countryCode,
80 | 'provinceCode': self.provinceCode
81 | }
82 | url = reverse('django_covid19:province-daily', kwargs=kwargs)
83 | response = self.client.get(url)
84 | self.assertEquals(response.status_code, 200)
85 |
86 | def test_daily_by_name_view_status_code(self):
87 | kwargs = {
88 | 'countryCode': self.countryCode,
89 | 'provinceName': self.provinceName
90 | }
91 | url = reverse('django_covid19:province-daily-by-name', kwargs=kwargs)
92 | response = self.client.get(url)
93 | self.assertEquals(response.status_code, 200)
94 |
95 | def test_detail_view_status_code(self):
96 | kwargs = {
97 | 'countryCode': self.countryCode,
98 | 'provinceCode': self.provinceCode
99 | }
100 | url = reverse('django_covid19:province-detail', kwargs=kwargs)
101 | response = self.client.get(url)
102 | self.assertEquals(response.status_code, 200)
103 |
104 | def test_detail_by_nameview_status_code(self):
105 | kwargs = {
106 | 'countryCode': self.countryCode,
107 | 'provinceName': self.provinceName
108 | }
109 | url = reverse('django_covid19:province-detail-by-name', kwargs=kwargs)
110 | response = self.client.get(url)
111 | self.assertEquals(response.status_code, 200)
112 |
113 |
114 | class CitiesTestCase(TestCase):
115 |
116 | """Supporting Chinese cities only."""
117 |
118 | fixtures = ['city.json']
119 |
120 | countryCode = 'CHN'
121 | cityName = '深圳'
122 |
123 | def test_list_view_status_code(self):
124 | kwargs = {'countryCode': self.countryCode,}
125 | url = reverse('django_covid19:city-list', kwargs=kwargs)
126 | response = self.client.get(url)
127 | self.assertEquals(response.status_code, 200)
128 |
129 | def test_detail_view_status_code(self):
130 | kwargs = {
131 | 'countryCode': self.countryCode,
132 | 'cityName': self.cityName
133 | }
134 | url = reverse('django_covid19:city-detail', kwargs=kwargs)
135 | response = self.client.get(url)
136 | self.assertEquals(response.status_code, 200)
137 |
--------------------------------------------------------------------------------
/django_covid19/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from django.urls import include, path
3 |
4 | from rest_framework import routers
5 | from . import views
6 |
7 | # Wire up our API using automatic URL routing.
8 | # Additionally, we include login URLs for the browsable API.
9 |
10 | app_name = 'django_covid19'
11 |
12 | urlpatterns = [
13 | url(r'statistics/$', views.StatisticsListView.as_view(), name='statistics-list'),
14 | url(r'statistics/latest/$', views.LatestStatisticsView.as_view(), name='statistics-latest'),
15 |
16 | url(r'cities/(?P[A-Z]+)/$', views.CityListView.as_view(), name='city-list'),
17 | url(r'cities/(?P[A-Z]+)/(?P[^/]+)/$', views.CityRetrieveByNameView.as_view(), name='city-detail'),
18 |
19 | url(r'countries/$', views.CountryListView.as_view(), name='country-list'),
20 | url(r'countries/daily/$', views.CountryListDailyView.as_view(), name='country-list-daily'),
21 | url(r'countries/(?P[A-Z]+)/$', views.CountryRetrieveView.as_view(), name='country-detail'),
22 | url(r'countries/(?P[A-Z]+)/daily/$', views.CountryDailyView.as_view(), name='country-daily'),
23 |
24 | url(r'provinces/(?P[A-Z]+)/$', views.ProvinceListView.as_view(), name='province-list'),
25 | url(r'provinces/(?P[A-Z]+)/daily/$', views.ProvinceListDailyView.as_view(), name='province-list-daily'),
26 | url(r'provinces/(?P[A-Z]+)/(?P[A-Z\-\d]+)/daily/$', views.ProvinceDailyView.as_view(), name='province-daily'),
27 | url(r'provinces/(?P[A-Z]+)/(?P[^/]+)/daily/$', views.ProvinceDailyByNameView.as_view(), name='province-daily-by-name'),
28 | url(r'provinces/(?P[A-Z]+)/(?P[A-Z\-\d]+)/$', views.ProvinceRetrieveView.as_view(), name='province-detail'),
29 | url(r'provinces/(?P[A-Z]+)/(?P[^/]+)/$', views.ProvinceRetrieveByNameView.as_view(), name='province-detail-by-name'),
30 |
31 | url(r'country-codes/$', views.CountryCodeListView.as_view(), name='country-code-list'),
32 | url(r'country-codes/(?P[A-Z]+)/$', views.CountryCodeRetrieveView.as_view(), name='country-code-detail'),
33 | ]
--------------------------------------------------------------------------------
/django_covid19/views.py:
--------------------------------------------------------------------------------
1 | from django.http import Http404
2 | from django.views.decorators.cache import cache_page
3 | from django.utils.decorators import method_decorator
4 |
5 | from rest_framework.response import Response
6 | from rest_framework.generics import ListAPIView
7 | from rest_framework.views import APIView
8 |
9 | from . import filters
10 | from . import models
11 | from . import serializers
12 | from .settings import CACHE_PAGE_TIMEOUT
13 |
14 | import json
15 |
16 | DEFAULT_COUNTRY_CODE = 'CHN'
17 | EXCLUDE_COUNTRY_CODES = ('TWN', 'HKG', 'MAC') # They belong to China.
18 |
19 | class LatestStatisticsView(APIView):
20 |
21 | """最新统计信息"""
22 |
23 | def get_object(self):
24 | result = {}
25 | inst = models.Statistics.objects.order_by('-id').first()
26 | if inst is None:
27 | raise Http404
28 | return inst
29 |
30 | @method_decorator(cache_page(
31 | CACHE_PAGE_TIMEOUT, key_prefix='statistics-lastest'))
32 | def get(self, request):
33 | obj = self.get_object()
34 | result = {}
35 | for field in models.Statistics._meta.fields:
36 | name = field.attname
37 | value = getattr(obj, name)
38 | if name not in models.Statistics.JSON_FIELDS:
39 | result[name] = value
40 | continue
41 | try:
42 | value = json.loads(value)
43 | except ValueError:
44 | value = None
45 | result[name] = value
46 | serializer = serializers.LatestStatisticsSerializer(result)
47 | return Response(serializer.data)
48 |
49 |
50 | class StatisticsListView(ListAPIView):
51 |
52 | """统计信息列表"""
53 |
54 | serializer_class = serializers.StatisticsSerializer
55 |
56 | def get_queryset(self):
57 | result = []
58 | qs = models.Statistics.objects.all().order_by('-modifyTime')
59 | values_fields = (
60 | 'globalStatistics', 'domesticStatistics',
61 | 'internationalStatistics', 'modifyTime', 'createTime')
62 | for item in qs.values_list(*values_fields):
63 | item = dict(zip(values_fields, item))
64 | statistics = {}
65 | for name, value in item.items():
66 | if name not in models.Statistics.JSON_FIELDS:
67 | statistics[name] = value
68 | continue
69 | try:
70 | value = json.loads(value)
71 | except ValueError:
72 | value = None
73 | statistics[name] = value
74 | result.append(statistics)
75 | return result
76 |
77 | @method_decorator(cache_page(
78 | CACHE_PAGE_TIMEOUT, key_prefix='statistics-list'))
79 | def dispatch(self, *args, **kwargs):
80 | return super(StatisticsListView, self).dispatch(*args, **kwargs)
81 |
82 |
83 | class CountryListView(ListAPIView):
84 |
85 | serializer_class = serializers.CountrySerializer
86 | filter_class = filters.CountryFilter
87 |
88 | def get_queryset(self):
89 | return models.Country.objects.all().order_by(
90 | 'continents', 'countryCode')
91 |
92 | @method_decorator(cache_page(
93 | CACHE_PAGE_TIMEOUT, key_prefix='country-list'))
94 | def dispatch(self, *args, **kwargs):
95 | return super(CountryListView, self).dispatch(*args, **kwargs)
96 |
97 |
98 | class CountryListDailyView(ListAPIView):
99 |
100 | serializer_class = serializers.CountryDailySerializer
101 | filter_class = filters.CountryFilter
102 |
103 | def get_queryset(self):
104 | return models.Country.objects.all().order_by(
105 | 'continents', 'countryCode')
106 |
107 | def list(self, request, *args, **kwargs):
108 | queryset = self.filter_queryset(self.get_queryset())
109 |
110 | result = []
111 | page = self.paginate_queryset(queryset)
112 | if page is not None:
113 | serializer = self.get_serializer(page, many=True)
114 | for item in serializer.data:
115 | dailyData = json.loads(item['dailyData'])
116 | result.extend(dailyData)
117 | return self.get_paginated_response(result)
118 |
119 | serializer = self.get_serializer(queryset, many=True)
120 | for item in serializer.data:
121 | dailyData = json.loads(item['dailyData'])
122 | result.extend(dailyData)
123 | return Response(result)
124 |
125 | @method_decorator(cache_page(
126 | CACHE_PAGE_TIMEOUT, key_prefix='country-list-daily'))
127 | def dispatch(self, *args, **kwargs):
128 | return super(CountryListDailyView, self).dispatch(*args, **kwargs)
129 |
130 |
131 | class CountryRetrieveView(APIView):
132 |
133 | def get_object(self, countryCode):
134 | country = models.Country.objects.filter(
135 | countryCode=countryCode).first()
136 | if country is None:
137 | raise Http404
138 | return country
139 |
140 | @method_decorator(cache_page(
141 | CACHE_PAGE_TIMEOUT, key_prefix='country-detail'))
142 | def get(self, request, countryCode):
143 | country = self.get_object(countryCode)
144 | serializer = serializers.CountrySerializer(country)
145 | return Response(serializer.data)
146 |
147 |
148 | class CountryDailyView(APIView):
149 |
150 | def get_object(self, countryCode):
151 | country = models.Country.objects.filter(
152 | countryCode=countryCode).first()
153 | if country is None:
154 | raise Http404
155 | return country
156 |
157 | @method_decorator(cache_page(
158 | CACHE_PAGE_TIMEOUT, key_prefix='country-daily-list'))
159 | def get(self, request, countryCode):
160 | country = self.get_object(countryCode)
161 | result = country.dailyData
162 | result = json.loads(result)
163 | return Response(result)
164 |
165 |
166 | class ProvinceListView(ListAPIView):
167 |
168 | """省列表"""
169 |
170 | serializer_class = serializers.ProvinceSerializer
171 | filter_class = filters.ProvinceFilter
172 |
173 | def get_queryset(self):
174 | countryCode = self.kwargs['countryCode']
175 | if not countryCode:
176 | countryCode = DEFAULT_COUNTRY_CODE
177 | return models.Province.objects.filter(
178 | countryCode=countryCode).order_by('provinceCode')
179 |
180 | @method_decorator(cache_page(
181 | CACHE_PAGE_TIMEOUT, key_prefix='province-list'))
182 | def dispatch(self, *args, **kwargs):
183 | return super(ProvinceListView, self).dispatch(*args, **kwargs)
184 |
185 |
186 | class ProvinceDailyView(APIView):
187 |
188 | """省按天返回列表"""
189 |
190 | def get_object(self, countryCode, provinceCode):
191 | province = models.Province.objects.filter(
192 | countryCode=countryCode, provinceCode=provinceCode).first()
193 | if province is None:
194 | raise Http404
195 | return province
196 |
197 | @method_decorator(cache_page(
198 | CACHE_PAGE_TIMEOUT, key_prefix='province-daily-list'))
199 | def get(self, request, countryCode, provinceCode):
200 | if countryCode is None:
201 | countryCode = DEFAULT_COUNTRY_CODE
202 | province = self.get_object(countryCode, provinceCode)
203 | result = province.dailyData
204 | result = json.loads(result)
205 | return Response(result)
206 |
207 |
208 | class ProvinceDailyByNameView(APIView):
209 |
210 | """省按天返回列表"""
211 |
212 | def get_object(self, countryCode, provinceName):
213 | province = models.Province.objects.filter(
214 | countryCode=countryCode, provinceName=provinceName).first()
215 | if province is None:
216 | raise Http404
217 | return province
218 |
219 | @method_decorator(cache_page(
220 | CACHE_PAGE_TIMEOUT, key_prefix='province-daily-list-by-name'))
221 | def get(self, request, countryCode, provinceName):
222 | if countryCode is None:
223 | countryCode = DEFAULT_COUNTRY_CODE
224 | province = self.get_object(countryCode, provinceName)
225 | result = province.dailyData
226 | result = json.loads(result)
227 | return Response(result)
228 |
229 |
230 | class ProvinceListDailyView(ListAPIView):
231 |
232 | serializer_class = serializers.ProvinceDailySerializer
233 | filter_class = filters.ProvinceFilter
234 |
235 | def get_queryset(self):
236 | countryCode = self.kwargs['countryCode']
237 | if not countryCode:
238 | countryCode = DEFAULT_COUNTRY_CODE
239 | return models.Province.objects.filter(
240 | countryCode=countryCode).order_by('provinceCode')
241 |
242 | def list(self, request, *args, **kwargs):
243 | queryset = self.filter_queryset(self.get_queryset())
244 |
245 | result = []
246 | page = self.paginate_queryset(queryset)
247 | if page is not None:
248 | serializer = self.get_serializer(page, many=True)
249 | for item in serializer.data:
250 | dailyData = json.loads(item['dailyData'])
251 | result.extend(dailyData)
252 | return self.get_paginated_response(result)
253 |
254 | serializer = self.get_serializer(queryset, many=True)
255 | for item in serializer.data:
256 | dailyData = json.loads(item['dailyData'])
257 | result.extend(dailyData)
258 | return Response(result)
259 |
260 | @method_decorator(cache_page(
261 | CACHE_PAGE_TIMEOUT, key_prefix='province-list-daily'))
262 | def dispatch(self, *args, **kwargs):
263 | return super(ProvinceListDailyView, self).dispatch(*args, **kwargs)
264 |
265 |
266 | class ProvinceRetrieveView(APIView):
267 |
268 | """通过省编码获取数据"""
269 |
270 | def get_object(self, countryCode, provinceCode):
271 | province = models.Province.objects.filter(
272 | countryCode=countryCode, provinceCode=provinceCode).first()
273 | if province is None:
274 | raise Http404
275 | return province
276 |
277 | @method_decorator(cache_page(
278 | CACHE_PAGE_TIMEOUT, key_prefix='province-detail'))
279 | def get(self, request, countryCode, provinceCode):
280 | if countryCode is None:
281 | countryCode = DEFAULT_COUNTRY_CODE
282 | province = self.get_object(countryCode, provinceCode)
283 | serializer = serializers.ProvinceSerializer(province)
284 | return Response(serializer.data)
285 |
286 |
287 | class ProvinceRetrieveByNameView(APIView):
288 |
289 | """通过省名获取数据"""
290 |
291 | def get_object(self, countryCode, provinceName):
292 | province = models.Province.objects.filter(
293 | countryCode=countryCode, provinceName=provinceName).first()
294 | if province is None:
295 | raise Http404
296 | return province
297 |
298 | @method_decorator(cache_page(
299 | CACHE_PAGE_TIMEOUT, key_prefix='province-detail-by-name'))
300 | def get(self, request, countryCode, provinceName=None):
301 | if countryCode is None:
302 | countryCode = DEFAULT_COUNTRY_CODE
303 | province = self.get_object(countryCode, provinceName)
304 | serializer = serializers.ProvinceSerializer(province)
305 | return Response(serializer.data)
306 |
307 |
308 | class CityListView(ListAPIView):
309 |
310 | serializer_class = serializers.CitySerializer
311 | filter_class = filters.CityFilter
312 |
313 | def get_queryset(self):
314 | countryCode = self.kwargs['countryCode']
315 | if not countryCode:
316 | countryCode = DEFAULT_COUNTRY_CODE
317 | return models.City.objects.filter(
318 | countryCode=countryCode).order_by('provinceCode', 'cityName')
319 |
320 | @method_decorator(cache_page(
321 | CACHE_PAGE_TIMEOUT, key_prefix='city-list'))
322 | def dispatch(self, *args, **kwargs):
323 | return super(CityListView, self).dispatch(*args, **kwargs)
324 |
325 |
326 | class CityRetrieveByNameView(APIView):
327 |
328 | def get_object(self, countryCode, cityName):
329 | city = models.City.objects.filter(
330 | countryCode=countryCode, cityName=cityName).first()
331 | if city is None:
332 | raise Http404
333 | return city
334 |
335 | @method_decorator(cache_page(
336 | CACHE_PAGE_TIMEOUT, key_prefix='city-detail-by-name'))
337 | def get(self, request, countryCode, cityName):
338 | if countryCode is None:
339 | countryCode = DEFAULT_COUNTRY_CODE
340 | city = self.get_object(countryCode, cityName)
341 | serializer = serializers.CitySerializer(city)
342 | return Response(serializer.data)
343 |
344 |
345 | class CountryCodeListView(ListAPIView):
346 |
347 | """国家编码列表"""
348 |
349 | serializer_class = serializers.CountryCodeSerializer
350 | filter_class = filters.CountryCodeFilter
351 |
352 | def get_queryset(self):
353 | return models.CountryCode.objects.order_by('countryCode')
354 |
355 | def list(self, request, *args, **kwargs):
356 | queryset = self.filter_queryset(self.get_queryset())
357 | queryset = queryset.exclude(countryCode__in=EXCLUDE_COUNTRY_CODES)
358 |
359 | result = []
360 | page = self.paginate_queryset(queryset)
361 | if page is not None:
362 | serializer = self.get_serializer(
363 | page, many=True, context={'request': request})
364 | result = serializer.data
365 | return self.get_paginated_response(result)
366 |
367 | serializer = self.get_serializer(
368 | queryset, many=True, context={'request': request})
369 | result = serializer.data
370 | return Response(result)
371 |
372 | @method_decorator(cache_page(
373 | CACHE_PAGE_TIMEOUT, key_prefix='country-code-list'))
374 | def dispatch(self, *args, **kwargs):
375 | return super(CountryCodeListView, self).dispatch(
376 | *args, **kwargs)
377 |
378 |
379 | class CountryCodeRetrieveView(APIView):
380 |
381 | def get_object(self, countryCode):
382 | if countryCode in EXCLUDE_COUNTRY_CODES:
383 | raise Http404
384 | inst = models.CountryCode.objects.filter(
385 | countryCode=countryCode).first()
386 | if inst is None:
387 | raise Http404
388 | return inst
389 |
390 | @method_decorator(cache_page(
391 | CACHE_PAGE_TIMEOUT, key_prefix='country-code-detail'))
392 | def get(self, request, countryCode):
393 | inst = self.get_object(countryCode)
394 | serializer = serializers.CountryCodeSerializer(
395 | inst, context={ 'request': request })
396 | return Response(serializer.data)
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | ncov.leafcoder.cn
--------------------------------------------------------------------------------
/docs/images/dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/docs/images/dashboard.png
--------------------------------------------------------------------------------
/docs/images/docs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leafcoder/django-covid19/930dc8776cd854bbbb0d8d74f53698b0c9d84752/docs/images/docs.png
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 新冠肺炎实时接口 - leafcoder
6 |
7 |
8 |
9 |
10 |
11 |
12 |
21 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 新冠肺炎实时接口 - leafcoder
6 |
7 |
8 |
9 |
10 |
11 |
12 |
21 |
22 |
23 |
24 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | django-crontab==0.7.1
2 | django-filter==2.2.0
3 | djangorestframework==3.11.2
4 | Scrapy==2.0.1
5 | scrapy-djangoitem==1.1.1
6 | django-mysql==3.5.0
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = django_covid19
3 | version = 0.4rc1
4 | description = A django app of covid-19 API in countries around the world, provinces and cities in China, and states in the USA.
5 | long_description = file: README.md
6 | long-description-content-type = text/markdown
7 | url = https://github.com/leafcoder/django-covid19
8 | author = leafcoder
9 | author_email = leafcoder@gmail.com
10 | license = MIT
11 | license_file = LICENSE
12 | keywords = python django covid19 2019-ncov app
13 | classifiers =
14 | Development Status :: 5 - Production/Stable
15 | Environment :: Web Environment
16 | Framework :: Django
17 | Framework :: Django :: 2.0
18 | Framework :: Django :: 2.1
19 | Framework :: Django :: 2.2
20 | Intended Audience :: Developers
21 | License :: OSI Approved :: MIT License
22 | Natural Language :: Chinese (Simplified)
23 | Operating System :: OS Independent
24 | Programming Language :: Python
25 | Programming Language :: Python :: 3
26 | Programming Language :: Python :: 3 :: Only
27 | Programming Language :: Python :: 3.5
28 | Programming Language :: Python :: 3.6
29 | Programming Language :: Python :: 3.7
30 | Topic :: Internet :: WWW/HTTP
31 | Topic :: Internet :: WWW/HTTP :: Dynamic Content
32 | Topic :: Software Development :: Libraries
33 | Topic :: Software Development :: Libraries :: Python Modules
34 |
35 | [options]
36 | include_package_data = true
37 | packages = find:
38 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import setuptools
4 |
5 | with open('requirements.txt') as f:
6 | install_requires = [line.strip() for line in f]
7 |
8 | setuptools.setup(
9 | install_requires=install_requires
10 | )
11 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist =
3 | py{35,36,37}-django{20,21,22}
4 |
5 | [testenv]
6 | deps=
7 | django20: Django>=2.0,<2.1
8 | django21: Django>=2.1,<2.2
9 | django22: Django>=2.2,<2.3
10 | django_mysql
11 | django-cors-headers
12 | django-crontab
13 | django-filter
14 | djangorestframework
15 | Scrapy
16 | scrapy-djangoitem
17 | setenv=
18 | PYTHONDONTWRITEBYTECODE=1
19 | changedir=
20 | demo_proj
21 | commands=
22 | {envpython} manage.py test django_covid19
23 | sitepackages=False
24 |
--------------------------------------------------------------------------------