我正在创建一个Bash脚本来解析网页上的空气污染水平: http://aqicn.org/city/beijing/m/
文件中有很多东西,但这是相关的一点:
" iaqi":[{" P":" PM25"" V":[ 59 ,21,112],"我":"北京时间pm25(罚款 颗粒物质)由美国大使馆北京空气质量公司测量 监控 (\ u7f8e \ u56fd \ u9a7b \ u5317 \ u4eac \ u5927 \ u4f7f \ u9986 \ u7a7a \ u6c14 \ u8d28 \ u91cf \ u76d1 \ u6d4b)。 使用EPA将值从\ u00b5g / m3转换为AQI级别 标准"},{" P":" PM10"" V":[ 15 下,5,69] ,"我":"北京时间10点 (可吸入颗粒物)由北京环境测量 保护监测中心
我希望脚本解析并显示2个数字:当前PM2.5和PM10级别(上段中粗体中的数字)。
CITY="beijing"
AQIDATA=$(wget -q 0 http://aqicn.org/city/$CITY/m/ -O -)
PM25=$(awk -v FS="(\"p\":\"pm25\",\"v\":\\\[|,[0-9]+)" '{print $2}' <<< $AQIDATA)
PM100=$(awk -v FS="(\"p\":\"pm10\",\"v\":\\\[|,[0-9]+)" '{print $2}' <<< $AQIDATA)
echo $PM25 $PM100
即使我可以正确显示PM2.5级别,我也无法显示PM10级别。我无法理解为什么,因为字符串是相似的。
任何人都可以解释一下吗?
答案 0 :(得分:3)
以下方法基于两个步骤:
(1)提取相关的JSON;
(2)使用JSON感知工具从JSON中提取相关信息 - jq。
(1)理想情况下,Web服务将提供允许直接获取JSON的JSON API,但由于您具有用于浏览器查看的URL,因此需要某种形式的屏幕抓取。这种方法有一定的脆弱性,所以我在这里只提供目前有用的东西:
wget -O - http://aqicn.org/city/beijing/m |
gawk 'BEGIN{RS="function"}
$1 ~/getAqiModel/ {
sub(/.*var model=/,"");
sub(/;return model;}/,"");
print}'
(可以使用支持多字符RS的gawk或awk;如果你有另一个awk,那么首先拆分&#34; function&#34;,使用例如:
sed $&#39; s / function / \\\ n / g&#39; #3反斜杠)
上述输出可以通过管道输出到以下jq命令,该命令执行上面(2)中设想的过滤。
(2)
jq -c '.iaqi | .[]
| select(.p? =="pm25" or .p? =="pm10") | [.p, .v[0]]'
结果:
["pm25",59]
["pm10",15]
答案 1 :(得分:2)
我认为您的问题是您有一行HTML
文件,其中包含一个脚本,其中包含一个包含您要查找的数据的变量。
您的字段分隔符 "p":"pm100", "v":[
或逗号和一些数字。
对于pm25
,这是有效的,因为它是第一个,并且在它之前没有出现,21
或类似的内容。
但是,对于pm10
,有一些与pm25
相关联。因此 second 字段包含,21
和,112
之间的空字符串
@karakfa有一个似乎有效的黑客攻击 - 但他并没有很好地解释为什么它会起作用。
他所做的是使用awk
的记录分隔符(通常是换行符)并将其设置为:
,,
或[
。所以在你的情况下,其中一个记录是"pm25"
,因为它前面有一个冒号,它是一个分隔符,后面跟一个逗号,也是一个分隔符。
一旦它到达匹配的内容("pm25"
),它就会将计数器设置为4.然后,对于这个和下一个记录,它会计算此计数器。 "pm25"
本身"v"
,:
和[
之间的空字符串,最后在使用您要输出的数字点击记录时达到一个:4 && ! 3
如果为false,3 && ! 2
为false,2 && ! 1
为false,但1 && ! 0
为真。由于没有执行块,awk
只打印此记录,这是您想要的值。
更强大的工作可能是使用xpath
来查找脚本,然后使用一些json
解析器或类似的来获取值。
答案 2 :(得分:1)
awk
救援!
如果必须,你可以使用这种hacky方式使用智能计数器和手工制作的分隔符。设置RS而不是FS传输循环通过字段到awk本身。多字符RS不适用于所有awks(gawk支持它)。
$ awk -v RS='[:,[]' '$0=="\"pm25\""{c=4} c&&!--c' file
59
$ awk -v RS='[:,[]' '$0=="\"pm10\""{c=4} c&&!--c' file
15
答案 3 :(得分:1)
chw21's helpful answer解释了为什么您的方法无效。
peak's helpful answer是最强大的,因为它采用了适当的JSON解析。
如果您不想或不能使用第三方实用程序jq
进行JSON解析,我建议使用sed
而不是awk
,因为{ {1}}不适合基于 field 的数据解析。
awk
以上内容适用于GNU和BSD / OSX $ sed -E 's/^.*"pm25"[^[]+\[([0-9]+).+"pm10"[^[]+\[([0-9]+).*$/\1 \2/' <<< "$AQIDATA"
59 15
。
将结果读入变量:
sed
注意我是如何选择小写变量名的,因为最好避免shell编程中的所有大写变量,以免与特殊的shell和环境变量冲突。
如果您不能依赖源字符串中值的顺序,请使用两个单独的read pm25 pm10 < \
<(sed -E 's/^.*"pm25"[^[]+\[([0-9]+).+"pm10"[^[]+\[([0-9]+).*$/\1 \2/' <<< "$AQIDATA")
命令:
sed