Python Code :不同Json文件的數據挖掘、清洗、反寫

從Python爬蟲爬下來的網頁數據,是一堆亂碼(Json格式),如何在這一對亂碼中找到自己想要的數據,或者說,如何在多個文件中整合出自己想要的新的內容,然後用一個Excel表格來表示呢?

本博客通過記錄一個實際問題的解決,闡述相關代碼。

問題:

1、從網頁上爬取下的Json格式文件包含商品名字、價格,準確找到該兩項目,通過csv表格完成一個數據可視化、

2、假設網頁上數據小部分有更新,重新爬取到Json格式文件;

3、挖掘出哪些變動;

4、兩者規則不一樣的情況下再次做數據可視化、並且和前一次做一個對比

5、重要信息(新價格)的數據清洗覆蓋

Json文件層次:

data_deal文件下有data文件夾和Js文件夾:其中data放置舊信息;Js放置新信息;

data文件夾下面有Comb文件(對應舊的名字、價格);Prop文件(對應商品的系列號);

一、代碼思路流程圖:


二、代碼解釋:

# -*- coding: utf-8 -*-
import numpy
import json
import csv
import os
import os.path
import shutil
import sys
import csv

reload(sys)
sys.setdefaultencoding( "utf-8" )

count_the_right_file=0
dets=[]
sum_prop=0
sum_comp=0
num_prop=0
num_comp=0
wrong_files=[]
首先:import相關Python的工具包:簡單介紹一下:json用來處理json格式的數據、os作爲文件路徑的相關操作、shutil在文件複製到指定路徑的時候用到、csv可以非常方便的幫助我們整理數據並做一個可視化操作;

其次:定義了一些相關的列表:wrong_file用於存放數據發生改動的data文件夾中的json文件名;

def getDirList(p):
    p=str(p)
    if p=="":
        return []
    if p[-1]!="/":
        p=p+"/"
    a=os.listdir(p)
    return a
    
js_file_names=[]
js_file_names=getDirList("/home/suanyi3/data_deal/js")

這一步就是做一個文件夾路徑下所有文件名的整理,該操作之後,js_file_names這個列表就會按順序存放/home/suanyi3/data_deal/js文件下的所有文件名;


for file in range(len(js_file_names)):
        js_file_addr="/home/suanyi3/data_deal/js/"+js_file_names[file]
        compare1=[]
        compare2=[]
	te=0
        de=0
#########################################<<>>##########################################
        try:
            with open(js_file_addr) as f:
                data=json.load(f)
                #print data
                #print data["a"]["bn"]
                for i in range(len(data["f"])):
                    compare1.append(data["f"][i]["be"])
                    compare1.append(data["f"][i]["bh"])
                #print compare1
                file_index=(data["a"]["bn"])
                file_index=file_index.split('_')
                print file_index
                bomb_addr="/home/suanyi3/data_deal/data/comb/"+ file_index[0] + ".js"
                prop_addr="/home/suanyi3/data_deal/data/prop/"+ file_index[0] + ".js"
        except IndexError:
             pass
##########################################<<>>###################################
	try:
             with open(prop_addr) as ff:
                prop_data=json.load(ff)
        except IOError,IndexError:
             pass
	if(data["a"]["j"]==prop_data["KEY_SERIES"]["SeriesFullName"]):
	     de=1
        else:
	     de=0
	sum_prop=sum_prop+de
	num_prop=num_prop+1
        print count_the_right_file
###########################################<<>>##################################
        try:
             with open(bomb_addr) as ff:
                com_data=json.load(ff)
                for i in range(len(com_data)):
                   compare2.append(com_data[i]["CombName"])
                   compare2.append(com_data[i]["Price"])
                #print compare2
        except IOError,IndexError:
             pass
這一步很關鍵:
首先解釋一下爲什麼要用try--except結構:因爲如果不用,讀取文件夾如果不存在的話就很尷尬了,會報錯
其次解釋一下我發現的挖掘數據的規則:js文件下的字典“a”鍵下面的子鍵“bn”存放有Comb文件和Prop文件中文件的名字,秩序要做一個split把“_”下劃線分開就是對應的文件名字;比如:

我們再去Comb文件夾尋找233.js這個文件:

兩者的系列號、價格、名字是對應的→然而我爲什麼說是對應的?對應着什麼?
我們來看:
這面有另外一個規則:js文件夾下面的"f"鍵下面的“be”、“bh”鍵分別對應Comb文件下面的CombName、CombPrice(舊數據名字、價格)如下所示:




所以代碼解決的問題就是在js 文件下面找出Prop文件中的系列號對不對應,對應用de參數來表示(1/0),然後在Comb中的舊價格和名字,用compare2來表示,新數據用compare1來表示,然後做一個輸出;


	if(len(compare2)>=len(compare1)):
		length=len(compare1)
		mis_length=len(compare2)
		tell=compare2
	else:
		length=len(compare2)
		mis_length=len(compare1)
		tell=compare1
        for j in range(length):
             count=[]
             if(compare1[j]==compare2[j]):
                 count.append(1)
	     else:
		 count.append(0)
#        if(count==len(compare2)-1):
#            print "rightrightrightright!!!"
#            te=1
#	else:
#	     te=0	     
        for j in range(0,length,2):
	     if(compare1[j+1]!=compare2[j+1]):
	         te=te+1
 	     else:
 	         te=te+0
             body=(js_file_names[file],file_index,data["a"]["j"],prop_data["KEY_SERIES"]["SeriesFullName"],de,com_data[0]["CombName"],compare1[j],compare1[j+1],compare2[j],compare2[j+1],bool(compare1[j+1]==compare2[j+1]),bool(compare1[j]==compare2[j]))
             dets.append(body)
	if((mis_length-length)>0):
	     for i in range(length,(mis_length-length),2):
	           body=(js_file_names[file],file_index,data["a"]["j"],prop_data["KEY_SERIES"]["SeriesFullName"],de,com_data[0]["CombName"],tell[i],tell[i+1],"missssssss","misssssssss",0)
                   dets.append(body)
        dets.append(body)
這段代碼主要是做在對於compre1、compare2列表下的價格進行比對,長度不一樣的話,用mis_length來表示長,用length表示短者;
然後進行比較,如果一一對應,te=0恆成立;
如果又不一樣的話我們馬上把te+1使之大於0;
緊接着作如下操作:
	if (te>=1 and de==1):
	     wrong_files.append(bomb_addr)
很簡單:我們用dets表來儲存所有的要整理的參數(新舊價格名字系列號de、te)用wrong_files來存儲不對應的文件名字;

#######################################<<>>##############################################
headers=["Js_File","prop_File","New_Series_Name","Old_Series_Name","The_Same?","ID","compare1_CombNames","compare1_Price","compare2_CombNames","compare2_Price","All_The_Same?"]
with open('temp4.csv','w') as fff:
	fff_csv=csv.writer(fff)
	fff_csv.writerow(headers)
	fff_csv.writerows(dets)

此時,我們可以做一個操作:還記得之前[[import csv]]這句話嗎?現在發揮作用了執行之後你會得到你想要的表格:裏面的每一項信息是什麼我已經在header列表中寫的很清楚了:我們保存下這個表格,大小:140M,列數:12,行數接近80萬行;因此我們處理的這個數據量大概是接近百萬級別的;耗時:4s



########################################<<>>##########################################
print wrong_files  
print len(wrong_files) 

def moveFileto(sourceDir,targetDir):
	shutil.copy(sourceDir,targetDir)

targetDir="/home/suanyi3/data_deal/ooo/"
for wrong_file in wrong_files:
	moveFileto(wrong_file,targetDir)
這部分運用到了一個函數:def moveFileto(sourceDir,targetDir)
通過它,我們可以複製需要變動的Comb文件夾下面的文件Copy到我們的targetDir路徑下;如下圖完成複製:

我們可以看到,並不是所有複製過來,而是有了變動的價格對應的js文件我們才把他拿過來,這一部工作成功完成!!

三、後續工作:

接下來是我們的後續工作,我們要把真實的數據反寫回去,另外開一個test.py腳本,重新寫些代碼:
reload(sys)
sys.setdefaultencoding( "utf-8" )
import的東西不變,多加這兩行:因爲這樣的話,反寫回去的中文字符纔可以得到識別;

def store(measurement,addr):
	new_js="/home/suanyi3/data_deal/oo/"+addr+".json"
	with open(new_js,'w') as f:
		jsonStr=json.dumps(measurement,ensure_ascii=False)
		f.write(jsonStr)
多加一個函數:def store(measurement,addr):
看完後面的 代碼你會發現:這個函數是這整個Python腳本的關鍵,他可以在json文件夾中特定位置寫進字典裏面對應的值;
而其他的代碼也大同小異:
def getDirList(p):
    p=str(p)
    if p=="":
        return []
    if p[-1]!="/":
        p=p+"/"
    a=os.listdir(p)
    return a

def store(measurement,addr):
	new_js="/home/suanyi3/data_deal/oo/"+addr+".json"
	with open(new_js,'w') as f:
		jsonStr=json.dumps(measurement,ensure_ascii=False)
		f.write(jsonStr)


js_file_names=[]
js_file_names=getDirList("/home/suanyi3/data_deal/js")
#print js_file_names
for file in range(len(js_file_names)):
        js_file_addr="/home/suanyi3/data_deal/js/"+js_file_names[file]
        compare1=[]
        compare2=[]
	te=0
        de=0
#########################################<<>>##########################################
        try:
            with open(js_file_addr) as f:
                data=json.load(f)
                for i in range(len(data["f"])):
                    compare1.append(data["f"][i]["be"])
                    compare1.append(data["f"][i]["bh"])
                #print compare1
                file_index=(data["a"]["bn"])
                file_index=file_index.split('_')
                print file_index
                ooo_addr="/home/suanyi3/data_deal/ooo/"+ file_index[0] + ".js"
	except IndexError:
             pass
#########################################<<>>#####################################
	try:
             with open(ooo_addr) as ff:
                ooo_data=json.load(ff)
		for i in range(min(len(ooo_data),len(data["f"]))):
			ooo_data[i]["CombName"]=data["f"][i]["be"]
			ooo_data[i]["Price"]=data["f"][i]["bh"]
		print ooo_data[i]["CombName"],ooo_data[i]["Price"]
		store(ooo_data,file_index[0])
        except IOError,IndexError:
             pass
以上代碼、思路爲作者一行行親手編寫,解決:不同Json文件的數據挖掘、清洗、反寫;數據量:百萬級;時間:4~5s;也樂於跟大家分享,按着這個步驟往下是可以完成屬於你自己的工程項目的。當然,我也允許你的懶惰,如果需要源代碼,請在下面留下你的郵箱地址。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章