├── .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 |
2 | 3 | # 新冠肺炎实时接口 4 | 5 |

6 | 7 | 8 | GitHub forks 9 | 10 | 11 | GitHub forks 12 | 13 | 14 | GitHub forks 15 | 16 |

17 | 18 |

19 | GitHub release (latest by date) 20 | GitHub top language 21 | GitHub code size in bytes 22 | GitHub commit activity 23 | downloads 24 |

25 |
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 | [![在线文档](https://raw.githubusercontent.com/leafcoder/django-covid19/master/docs/images/docs.png)](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 | [![在线数据大屏](https://raw.githubusercontent.com/leafcoder/django-covid19/master/docs/images/dashboard.png)](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 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |

国内各省、自治区、直辖市疫情

44 |
45 |
46 |
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 | --------------------------------------------------------------------------------