2016-02-22 31 views
1

我創建一個bash腳本解析從網頁中的空氣污染水平: http://aqicn.org/city/beijing/m/類似琴絃,不同的結果

有文件中的很多東西,但這是相關的位:

「iaqi」:[{ 「p」: 「PM25」, 「v」:[,21112]中, 「i」:「北京PM25(細 顆粒狀物質)由美國使館空氣質量測量 Monitor (\ u7f8e \ u56fd \ uaba7b \ u5317 \ u4eac \ u5927 \ u4f7f \ u9986 \ u7a7a \ u14c14 \ u8d28 \ u91cf \ u76d1 \ u6d4b)。 使用EPA 標準將值從\ u00b5g/m3轉換爲AQI水平。「},{」p「:」pm10「,」v「:[,569],」i「:」Beijing PM10 (可吸入顆粒物),由北京環境 保護監測中心

我想要的腳本來分析和測量顯示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級別顯示。我不明白爲什麼,因爲字符串是相似的。

這裏有人能解釋嗎?

+2

的數據看起來很像JSON。你有沒有考慮過使用AWK或Bash JSON解析器?有一些在http://www.json.org列出。 –

回答

1

如果你不想或者不能使用第三方工具jq的JSON解析,我建議使用sed而不是awk,因爲awk是不適合用於基於解析的這些數據。

$ sed -E 's/^.*"pm25"[^[]+\[([0-9]+).+"pm10"[^[]+\[([0-9]+).*$/\1 \2/' <<< "$AQIDATA" 
59 15 

上面應與GNU和BSD/OSX sed工作。

讀結果到變量:

read pm25 pm10 < \ 
    <(sed -E 's/^.*"pm25"[^[]+\[([0-9]+).+"pm10"[^[]+\[([0-9]+).*$/\1 \2/' <<< "$AQIDATA") 

注意如何我選擇小寫的變量名,因爲它是最好避免在shell編程全部大寫的變量,從而避免特殊衝突shell和環境變量。

如果你不能依賴源字符串中的值的順序上,使用兩個單獨的sed命令:

pm25=$(sed -E 's/^.*"pm25"[^[]+\[([0-9]+).*$/\1/' <<< "$AQIDATA") 
pm10=$(sed -E 's/^.*"pm10"[^[]+\[([0-9]+).*$/\1/' <<< "$AQIDATA") 
+0

所有非常好的評論。我接受這個答案只是因爲它很清楚,它不依賴於解析JSON(我對此一無所知,我也懶得學習)。 –

1

awk來救援!

如果您需要,您可以使用智能計數器和手工製作的分隔符來使用這種黑客方式。設置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 
2

我覺得你的問題是,你有一個單行HTML文件,它包含包含包含你正在尋找的數據變量的腳本。

你的字段分隔符是要麼"p":"pm100", "v":[一個逗號和一些數字。

對於pm25這是有效的,因爲它是第一個,並且在它之前沒有發生,21或類似事件。

但是,對於pm10,有一些與之前的pm25相關聯。所以字段包含空字符串,21,112

之間@karakfa有,似乎工作一劈 - 但他沒有很好地解釋爲什麼它的工作原理。

他所做的是用awk的記錄分隔符(通常是一個換行符)並將其設置爲任意的:,,或[。所以在你的情況下,其中一個記錄應該是"pm25",因爲它前面是一個冒號,它是一個分隔符,並且以逗號(也是分隔符)繼承。

一旦它擊中匹配的內容("pm25")它設置一個計數器4.然後,對於這一點,接下來的記錄,它倒計數該計數器。 "pm25"本身,"v":[之間的空字符串,最後擊中你要輸出的數字記錄時達到一個:4 && ! 3是假的,3 && ! 2是假的,2 && ! 1是假的,但1 && ! 0是真實的。由於沒有執行塊,awk只是打印此記錄,這是您想要的值。

一個更健壯的工作可能會使用xpath來查找腳本,然後使用一些json解析器或類似的來獲取值。

+0

很好的解釋,除了聲明「它將繼續計入負數」。請改正。 – peak

+0

你說得對,我不知道' - c'是如何工作的。我試了一下,'c'不會低於0。 – chw21

+0

一旦'c'達到0,'&&'的短路邏輯就會阻止評估'c &&! - c'的RHS。整潔,簡潔,聰明,是的,但也有點鬼鬼祟祟。 – peak

3

以下的方法是基於兩個步驟:

(1)提取相關JSON;

(2)使用JSON-aware工具,提取從JSON的相關信息 - 在這裏jq

(1)理想情況下,Web服務將提供一個JSON API,它允許人們直接獲取JSON,但由於您使用的URL是用瀏覽器查看的,因此需要某種形式的屏幕抓取。有這樣的做法一定的脆性,所以在這裏我只是提供一些當前工作:

wget -O - http://aqicn.org/city/beijing/m | 
    gawk 'BEGIN{RS="function"} 
     $1 ~/getAqiModel/ { 
     sub(/.*var model=/,""); 
     sub(/;return model;}/,""); 
     print}' 

(呆子或支持RS可用於多字符一個awk;如果您有其他AWK,然後先被分割的「功能」,使用例如:

SED $的/功能/ \\\ N/G'#3反斜槓)

的上面可以管道輸出到以下jq命令,它執行上面(2)中設想的過濾。

(2)

jq -c '.iaqi | .[] 
| select(.p? =="pm25" or .p? =="pm10") | [.p, .v[0]]' 

結果:

["pm25",59] 
["pm10",15] 
+1

很好 - 使用JSON解析器是最穩健的方法;請注意,由於使用多字符「RS」值,您的'awk'命令需要GNU Awk或Mawk(不適用於BSD/OSX Awk)。 – mklement0

+0

@ mklement0 - 修訂。謝謝。 – peak