Skip to content

Commit 0e44798

Browse files
author
chiwent
committed
first commit
1 parent 1a4e1c7 commit 0e44798

File tree

6 files changed

+495
-2
lines changed

6 files changed

+495
-2
lines changed

.gitignore

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
6+
# Runtime data
7+
pids
8+
*.pid
9+
*.seed
10+
*.pid.lock
11+
12+
node_modules
13+
14+
.npm
15+
16+
*.DS_Store
17+
18+
.node_repl_history
19+
20+
package-lock.json

README.md

+60-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,60 @@
1-
# cli-weather
2-
天气预报cli工具(支持中国天气网和和风天气)
1+
# waether-cli
2+
3+
[![NPM](https://nodei.co/npm/weather-ct.png)](https://nodei.co/npm/weather-ct/)
4+
5+
天气预报cli工具(支持中国天气网和和风天气)<br>
6+
7+
该版本可以视为[和风天气](https://github.com/chiwent/weather-hf)的升级版本,引入了中国天气网的源,支持最长7天的天气预报(和风免费用户最多支持3天),并且中国天气网不需要引入开发者key,查询的次数都不限制,这些方面都是优于和风的。不过和风提供的数据类型更多,比如支持能见度,中国天气网不支持。<br>
8+
9+
### 安装
10+
```
11+
npm install -g weather-ct
12+
13+
```
14+
15+
### 参数说明
16+
17+
```
18+
--source / -s : 选择源(1:中国天气网,2:和风天气),默认是1
19+
--city / -c : 选择目标城市(如果选择了地区可以忽略)
20+
--area / -a : 选择目标地区(如果选择了城市可以忽略)
21+
--opt / -o : 选择查询的模式,目前有now(今天的天气情况),forecast(未来天气情况).如果选择了1的源,请忽略now选项.如果选择了2的源,默认是now
22+
--lang / -l : 语言,默认为中文,可忽略。如果选择了1的源,请忽略
23+
--key / -k : 开发者key,如果在config.json中已经填了可忽略此选项。如果选择了1的源,请忽略。
24+
```
25+
26+
#### 注意事项
27+
在最开始使用和风源的时候,需要在命令行中加入key配置,它只需要配置一次,后续可以省略key<br>
28+
中国天气网输入的地址需要是汉语拼音,和风支持中文汉字<br>
29+
下面的模式无法使用:<br>
30+
```
31+
$ waethercli -a huadu
32+
```
33+
请使用:<br>
34+
```
35+
$ waethercli -c guangzhou(待查询地区的辖区)
36+
```
37+
38+
39+
### demo
40+
41+
#### 中国天气网(1)
42+
```
43+
$ waethercli -c guangzhou
44+
$ waethercli -c guangzhou -o forecast
45+
$ waethercli -a huadu -o forecast
46+
```
47+
48+
#### 和风天气(2)
49+
```js
50+
$ waethercli -c guangzhou
51+
$ waethercli -c guangzhou -o forecast
52+
$ waethercli -a huadu
53+
$ waethercli -a huadu -o forecast
54+
```
55+
56+
57+
#### 补充
58+
两个源都还没有测试过外国和港澳台<br>
59+
中国天气网的的源有两个,一个可以靠位置的拼音来查询,另外一个只能靠位置的编码来查询,并且在部分地区的命名上也没有统一的标准,有些区直接划为了市,有些区把“区”的称号取消了,让人很难受。所以可能在输入部分地区后会有bug<br>
60+

lib/config.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "key": "" }

lib/index.js

+286
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
#!/usr/bin/env node
2+
3+
'use strict';
4+
5+
const meow = require('meow');
6+
const chalk = require('chalk');
7+
const weather = require('./weather');
8+
const key_config = require('./config.json');
9+
const fs = require('fs');
10+
const path = require('path');
11+
const readline = require('readline');
12+
const axios = require('axios');
13+
const pinyin = require('js-pinyin');
14+
15+
pinyin.setOptions({ checkPolyphone: false, charCase: 0 });
16+
17+
const cli = meow(`
18+
Usage
19+
$ weathercli <input>
20+
Options
21+
--source, -s Which source would you like? 1: http://www.weather.com.cn/(default) 2:http://www.heweather.com/
22+
--city, -c City you want check
23+
--area, -a area you want check.
24+
--opt, -o the mode selection: now:today's weather forecast:then next few days' weather, default: 'now'
25+
--lang, -l language, en: English, if you ignore this option, it default to Chinese. The source 1 only support Chinese.
26+
--key, -k key.If you select source 1, please ignore it.
27+
Examples
28+
$ weathercli -c guangzhou
29+
$ weathersli -s 2 -a fengtai
30+
`, {
31+
flags: {
32+
source: {
33+
type: 'number',
34+
alias: 's',
35+
default: 1
36+
},
37+
city: {
38+
type: 'string',
39+
alias: 'c'
40+
},
41+
area: {
42+
type: 'string',
43+
alias: 'a'
44+
},
45+
opt: {
46+
type: 'string',
47+
alias: 'o',
48+
default: 'now'
49+
},
50+
lang: {
51+
type: 'string',
52+
alias: 'l',
53+
default: ''
54+
},
55+
key: {
56+
type: 'string',
57+
alias: 'k',
58+
default: key_config.key
59+
}
60+
}
61+
});
62+
63+
64+
65+
// if (!cli.flags.source) {
66+
// console.log(chalk.bold.red('Please select source!'));
67+
// process.exit(1);
68+
// }
69+
let wait_for_province = async function() {
70+
let rl = readline.createInterface({
71+
input: process.stdin,
72+
output: process.stdout
73+
});
74+
75+
76+
await rl.question('It is belong...(上一级地址) \n', (answer) => {
77+
console.log('Waiting... It is belong(它属于)', answer);
78+
rl.close();
79+
let url = 'http://flash.weather.com.cn/wmaps/xml/' + answer + '.xml';
80+
console.log(url)
81+
let get = function() {
82+
return axios.get(url)
83+
.then(response => {
84+
let r = readline.createInterface({
85+
input: process.stdin,
86+
output: process.stdout
87+
});
88+
var reg = /\<city .*\/\>/g;
89+
let cityList = response.data.match(reg);
90+
let filterUrl = () => {
91+
let code;
92+
cityList.forEach((item, index) => {
93+
let cityname = /\<city .* cityname=\"(.*?)\"/g.exec(item)[1];
94+
95+
if (cityname.substr(-1) === '市' || cityname.substr(-1) === '区' || cityname.substr(-1) === '县') {
96+
cityname = cityname.substring(0, cityname.length - 1);
97+
}
98+
let select = pinyin.getFullChars(cityname).toLowerCase();
99+
if (select === cli.flags.city) {
100+
code = /\<city .* url=\"(.*?)\"/g.exec(item)[1];
101+
} else if (select === cli.flags.area) {
102+
code = /\<city .* url=\"(.*?)\"/g.exec(item)[1];
103+
}
104+
})
105+
return code;
106+
}
107+
108+
let filter_url = 'http://mobile.weather.com.cn/data/forecast/' + filterUrl().trim() + '.html'
109+
return axios.get(filter_url);
110+
}).then((response) => {
111+
let data = response.data;
112+
let format_data = { "fa": "天气", "fb": "天气2", "fc": "最高温度", "fd": "最低温度", "fe": "风向1", "ff": "风向2", "fg": "风力1", "fh": "风力2", "fi": "日出日落" };
113+
let weather_json = {
114+
"10": "暴雨",
115+
"11": "大暴雨",
116+
"12": "特大暴雨",
117+
"13": "阵雪",
118+
"14": "小雪",
119+
"15": "中雪",
120+
"16": "大雪",
121+
"17": "暴雪",
122+
"18": "雾",
123+
"19": "冻雨",
124+
"20": "沙尘暴",
125+
"21": "小到中雨",
126+
"22": "中到大雨",
127+
"23": "大到暴雨",
128+
"24": "暴雨到大暴雨",
129+
"25": "大暴雨到特大暴雨",
130+
"26": "小到中雪",
131+
"27": "中到大雪",
132+
"28": "大到暴雪",
133+
"29": "浮尘",
134+
"30": "扬沙",
135+
"31": "强沙尘暴",
136+
"53": "霾",
137+
"99": "",
138+
"00": "晴",
139+
"01": "多云",
140+
"02": "阴",
141+
"03": "阵雨",
142+
"04": "雷阵雨",
143+
"05": "雷阵雨伴有冰雹",
144+
"06": "雨夹雪",
145+
"07": "小雨",
146+
"08": "中雨",
147+
"09": "大雨"
148+
};
149+
let fx_json = {
150+
"0": "无持续风向",
151+
"1": "东北风",
152+
"2": "东风",
153+
"3": "东南风",
154+
"4": "南风",
155+
"5": "西南风",
156+
"6": "西风",
157+
"7": "西北风",
158+
"8": "北风",
159+
"9": "旋转风"
160+
};
161+
let fl_json = {
162+
"0": "微风",
163+
"1": "3-4级",
164+
"2": "4-5级",
165+
"3": "5-6级",
166+
"4": "6-7级",
167+
"5": "7-8级",
168+
"6": "8-9级",
169+
"7": "9-10级",
170+
"8": "10-11级",
171+
"9": "11-12级"
172+
};
173+
console.log(chalk.bold.yellow('Forecast :'));
174+
let location = cli.flags.city || cli.flags.area;
175+
console.log(chalk.red(`Location: ${location}, ${data.c.c3}`));
176+
177+
data.f.f1.forEach((item, index) => {
178+
console.log(chalk.green('=============================================='))
179+
console.log(chalk.bold.yellow(`The next ${index + 1} day(s) :`));
180+
console.log(chalk.cyan(`${format_data.fa}: ${weather_json[item.fa]} ~ ${weather_json[item.fb]}`));
181+
console.log(chalk.cyan(`${format_data.fd}: ${item.fd}`));
182+
console.log(chalk.cyan(`${format_data.fc}: ${item.fc}`));
183+
console.log(chalk.cyan(`${format_data.fe}: ${fx_json[item.fe]}`));
184+
console.log(chalk.cyan(`${format_data.ff}: ${fx_json[item.ff]}`));
185+
console.log(chalk.cyan(`${format_data.fg}: ${fl_json[item.fg]}`));
186+
console.log(chalk.cyan(`${format_data.fh}: ${fl_json[item.fh]}`));
187+
console.log(chalk.cyan(`${format_data.fi}: ${item.fi}`));
188+
})
189+
190+
})
191+
}
192+
get().then(() => {
193+
process.exit(0);
194+
});
195+
196+
});
197+
}
198+
199+
if (cli.flags.source === 2) {
200+
if (!key_config.flag)
201+
try {
202+
let file_data = fs.readFileSync(__dirname + '/config.json', 'utf-8');
203+
if (!file_data.key && !cli.flags.key) {
204+
console.log('Please input your key! You only need to enter it once. Next time you can ignore it.');
205+
process.exit(0);
206+
}
207+
if (cli.flags.key) {
208+
let str = JSON.stringify({ key: cli.flags.key, flag: true });
209+
fs.writeFileSync(__dirname + '/config.json', str);
210+
}
211+
} catch (error) {
212+
console.error(error);
213+
process.exit(1);
214+
}
215+
weather.getWeather(cli.flags)
216+
.then(result => {
217+
result = JSON.parse(result);
218+
console.log(chalk.red(`Location: ${result.area}, ${result.city}, ${result.province}`));
219+
console.log(chalk.blue(`Update-Time: ${result.update_loc}`));
220+
console.log(chalk.green(`Data:`));
221+
let dat = JSON.stringify(result.data);
222+
let data = JSON.parse(dat);
223+
if (dat.length < 250) {
224+
console.log(chalk.bold.yellow('Today :'));
225+
console.log(chalk.cyan(data.cond_txt));
226+
console.log(chalk.cyan(`temperature(温度): ${data.tmp}`));
227+
console.log(chalk.cyan(`humidity(湿度): ${data.hum}`));
228+
console.log(chalk.cyan(`pcpn(降水量): ${data.pcpn}`));
229+
console.log(chalk.cyan(`vis(能见度): ${data.vis}`));
230+
console.log(chalk.cyan(`wind_dir(风向): ${data.wind_dir}`));
231+
console.log(chalk.cyan(`wind_sc(风力): ${data.wind_sc}`));
232+
console.log(chalk.cyan(`wind_spd(风速): ${data.wind_spd}`));
233+
} else {
234+
data.forEach((item, index) => {
235+
console.log(chalk.green('=============================================='))
236+
console.log(chalk.bold.yellow(`The next ${index + 1} day(s) :`));
237+
console.log(chalk.cyan(item.cond_txt));
238+
console.log(chalk.cyan(`min-temperature(最低温度): ${item.tmp_min}`));
239+
console.log(chalk.cyan(`max-temperature(最高温度): ${item.tmp_max}`));
240+
console.log(chalk.cyan(`humidity(湿度): ${item.hum}`));
241+
console.log(chalk.cyan(`pcpn(降水量): ${item.pcpn}`));
242+
console.log(chalk.cyan(`vis(能见度): ${item.vis}`));
243+
console.log(chalk.cyan(`windDir(风向): ${item.wind_dir}`));
244+
console.log(chalk.cyan(`windPower(风力): ${item.wind_sc}`));
245+
console.log(chalk.cyan(`windState(风速): ${item.wind_spd}`));
246+
});
247+
}
248+
process.exit(0);
249+
}).catch(error => {
250+
if (error) {
251+
console.log(chalk.bold.red(error));
252+
process.exit(1);
253+
}
254+
});
255+
} else if (cli.flags.source === 1) {
256+
if (!cli.flags.city && !cli.flags.area) {
257+
console.log(chalk.bold.red('Please select city or area!'));
258+
process.exit(1);
259+
}
260+
if (cli.flags.opt === 'forecast') {
261+
wait_for_province();
262+
} else {
263+
weather.getWeather(cli.flags)
264+
.then(result => {
265+
let city = /\<city .* cityname=\"(.*?)\"/g.exec(result)[1];
266+
let state = /\<city .* stateDetailed=\"(.*?)\"/g.exec(result)[1];
267+
let min_temp = /\<city .* tem2=\"(.*?)\"/g.exec(result)[1];
268+
let max_temp = /\<city .* tem1=\"(.*?)\"/g.exec(result)[1];
269+
let temp_now = /\<city .* temNow=\"(.*?)\"/g.exec(result)[1];
270+
let windState = /\<city .* windState=\"(.*?)\"/g.exec(result)[1];
271+
let windDir = /\<city .* windDir=\"(.*?)\"/g.exec(result)[1];
272+
let windPower = /\<city .* windPower=\"(.*?)\"/g.exec(result)[1];
273+
let humidity = /\<city .* humidity=\"(.*?)\"/g.exec(result)[1];
274+
console.log(chalk.bold.yellow('Today :'));
275+
console.log(chalk.red(`Location: ${cli.flags.city}, ${city}`))
276+
console.log(chalk.cyan(state));
277+
console.log(chalk.cyan(`min-temperature(最低温度): ${min_temp}`));
278+
console.log(chalk.cyan(`max-temperature(最高温度): ${max_temp}`));
279+
console.log(chalk.cyan(`temperature-now(现在温度): ${temp_now}`));
280+
console.log(chalk.cyan(`humidity(湿度): ${humidity}`));
281+
console.log(chalk.cyan(`windDir(风向): ${windDir}`));
282+
console.log(chalk.cyan(`windPower(风力): ${windPower}`));
283+
console.log(chalk.cyan(`windState(风速): ${windState}`));
284+
})
285+
}
286+
}

0 commit comments

Comments
 (0)