Python3 不解压直接解析xml文件,并进行csv出力

现在有一个zip文件,里面有多个类型的文件,想要在不解压zip包的情况下筛选并解析其中的xml文件,并且将解析的数据出力到csv文件中。(利用Python提供的zipfile库)

宜人宜己,方便自己以后查找,也给大家提供一个思路吧。

Python环境:Python 3.7

IDE:JetBrains PyCharm

条件准备:在任意路径下放入需要进行读取的zip文件:

eg:在 E:\work 下有一个文件:E:\work\movies.zip

Python3 不解压直接解析xml文件,并进行csv出力_第1张图片

在zip文件中有一个movies文件夹,在\movies里面有多个文件,它们类型五花八门:

Python3 不解压直接解析xml文件,并进行csv出力_第2张图片

我们的目标就是要在不解压movies.zip的情况下,直接读取里面的person.xml和person2.xml,并将文件里面的数据进行csv出力。

person.xml文件:



   张三
   
   25
   178
   140
   1994-07-22
   13689457821
   成都


   李四
   
   27
   164
   110
   1992-12-25
   13683645821
   上海


   王倩
   
   21
   170
   100
   1998-05-02
   13689489461
   北京


   陈宇
   
   24
   171
   120
   1995-04-25
   13689489471
   成都


   何希美
   
   23
   166
   92
   1996-06-12
   13684857856
   西安


   杨俊
   
   28
   175
   142
   1998-08-31
   13656197821
   重庆

person2.xml文件:



   陈思南
   
   26
   170
   120
   1993-03-25
   13689659821
   贵州


   李若白
   
   36
   172
   130
   1986-10-21
   13684695821
   邯郸


   张晓玲
   
   25
   165
   96
   1994-06-19
   13689479161
   成都


   林韵
   
   27
   168
   98
   1992-05-15
   13688940471
   贵州

打开JetBrains PyCharm,点击【File -> New Project...】新建一个工程,接着在建好的工程中新建一个Python File(eg:zipFileParse.py)。

打开刚刚建好的Python File,首先我们需要在文件的开始位置导入我们需要的Python库(模块):

①zipfile:用于zip文件读取

②csv:用于进行csv文件出力

③xml.dom.minidom:用于解析xml文件

④io:主要是利用其中的StingIO()函数

⑤fnmatch:用于从工作空间中取出指定类型的文件名列表

⑥os:操作系统

⑦re:正则表达式

好了,下面上代码:

import zipfile, csv, xml.dom.minidom, io, fnmatch, os, re

# 获取指定工作空间下的所有指定类型的文件名
# path 工作空间
# fnexp 文件类型
# 返回所有指定类型文件名列表
def iterFindFiles(path, fnexp):
    for root, dirs, files in os.walk(path):
        for fileName in fnmatch.filter(files, fnexp):
            # yield的作用是把一个函数变成一个generator(返回一个iterable对象)
            yield os.path.join(root, fileName)


# 电影详细信息取得
# data DOMTree
# 返回电影信息data
def getMoviesDetail(data):
    # 返回data定义
    rtnData = []
    # data编集
    for movie in data:
        # 行编集
        row = []
        # 名称
        if movie.hasAttribute("title"):
            row.append(movie.getAttribute("title"))
        # 类型
        type = movie.getElementsByTagName("type")[0]
        row.append(type.childNodes[0].data)
        # 格式
        format = movie.getElementsByTagName("format")[0]
        row.append(format.childNodes[0].data)
        # 年份
        year = movie.getElementsByTagName("year")[0]
        row.append(year.childNodes[0].data)
        # 地区
        rating = movie.getElementsByTagName("rating")[0]
        row.append(rating.childNodes[0].data)
        # 明星数
        stars = movie.getElementsByTagName("stars")[0]
        row.append(stars.childNodes[0].data)
        # 描述
        description = movie.getElementsByTagName("description")[0]
        row.append(description.childNodes[0].data)

        # 返回data追加
        rtnData.append(row)

    return rtnData

# 人员信息取得
# data DOMTree
# 返回人员信息data
def getPersonData(data):
    # 返回data定义
    rtnData = []
    # 返回data编集
    for person in data:
        # 行编集
        row = []
        # 项目
        if person.hasAttribute("project"):
            row.append(person.getAttribute("project"))
        # 姓名
        name = person.getElementsByTagName("name")[0]
        row.append(name.childNodes[0].data)
        # 性别
        sex = person.getElementsByTagName("sex")[0]
        row.append(sex.childNodes[0].data)
        # 年龄
        age = person.getElementsByTagName("age")[0]
        row.append(age.childNodes[0].data)
        # 身高
        height = person.getElementsByTagName("height")[0]
        row.append(height.childNodes[0].data)
        # 体重
        weight = person.getElementsByTagName("weight")[0]
        row.append(weight.childNodes[0].data)
        # 生日
        birthday = person.getElementsByTagName("birthday")[0]
        row.append(birthday.childNodes[0].data)
        # 电话
        phone = person.getElementsByTagName("phone")[0]
        row.append(phone.childNodes[0].data)
        # 住址
        home = person.getElementsByTagName("home")[0]
        row.append(home.childNodes[0].data)

        # 返回data追加
        rtnData.append(row)

    return rtnData

# csv出力data取得
# data DOMTree
# type 类型
# 返回csv出力data
def getCsvData(data, type):
    # csv出力data定义
    csvData = []

    if type == "person":
        # 类型为 person 的场合,取得人员信息
        csvData = getPersonData(data)
    elif type == "movie":
        # 类型为 movie 的场合,取得电影信息
        csvData = getMoviesDetail(data)

    return csvData

# csv出力
# file csv出力文件
# header csv出力Header
# dataList csv出力dataList
def csvOut(file, header, dataList):
    # 打开文件
    with open(file, "w", encoding="utf-8", newline="") as csvFile:
        # 通过 csv.writer() 获取一个写对象
        writer = csv.writer(csvFile, dialect="excel")
        # Header写入
        writer.writerow(header)

        # data写入
        for data in dataList:
            for row in data:
                writer.writerow(row)

# xml 文件解析
# filePath zip文件路径
# type 类型
# 返回csv出力data
def xmlFileParse(filePath, type):
    # 打开 zip文件
    with zipfile.ZipFile(os.path.join(os.getcwd(), filePath)) as zFile:
        # csv出力data定义
        rtnData = []
        if zFile.namelist() == None or zFile.namelist() == []:
            print("包内没有文件!")
        else:
            # .namelist():取得 zip文件内的所有文件(包括文件夹)
            for fileName in zFile.namelist():
                # 第一列
                row_0 = ""
                # dataBody
                dataBody = []
                # 从 zip文件中取得所有 .xml文件名
                if re.search(r"([\w]*.xml)+$", fileName, re.S):
                    print("读取文件:", fileName)
                    # 通过io.SringIO()获取文件流(file对象)
                    fileSource = io.StringIO(zFile.read(fileName).decode("utf-8"))
                    # 利用 xml.dom.minidom.parse() 将文件(file对象转为DOM)
                    DomTree = xml.dom.minidom.parse(fileSource)
                    # 获取 DOM 上的所有节点
                    allElement = DomTree.documentElement

                    # 用 '/' 将文件名分割
                    subFileName = fileName.split(r"/")
                    # 获取指定类型的 data
                    if re.search(type, subFileName[len(subFileName) - 1]):
                        # 第一列data编集
                        if type == "person" and allElement.hasAttribute("company"):
                            row_0 = allElement.getAttribute("company")
                        elif type == "movie" and allElement.hasAttribute("shelf"):
                            row_0 = allElement.getAttribute("shelf")

                        # 根据 TagName 获取DOMTree
                        dataTree = allElement.getElementsByTagName(type)
                        # dataBody 取得
                        dataBody = getCsvData(dataTree, type)
                    else:
                        pass

                    for row in dataBody:
                        # 将第一列data插入行
                        row.insert(0, row_0)
                        # csv出力data追加
                        rtnData.append(row)

                    # 文件流关闭
                    fileSource.close()
        return rtnData


# 主程序入口
if __name__ == "__main__":
    p_cnt = 30
    print("*"*p_cnt, " Start ", "*"*p_cnt)
    # csv出力dataList
    csvDataList = []
    # 取得工作空间内的所有 zip文件
    for zFile in iterFindFiles(r"E:\work", r"*.zip"):
        print(zFile)
        # csv出力data追加
        csvDataList.append(xmlFileParse(zFile, "person"))

    # csv出力文件名
    csvFile = r"E:\work\person.csv"
    # Header
    csvHeader = ["company", "person", "name", "sex", "age", "height", "weight", "birthday",
                "phone", "home"]
    # csv文件出力
    csvOut(csvFile, csvHeader, csvDataList)

    print("*"*p_cnt, " Success ", "*"*p_cnt)

现在运行一下,看看是否正确:

Python3 不解压直接解析xml文件,并进行csv出力_第3张图片

执行成功:

Python3 不解压直接解析xml文件,并进行csv出力_第4张图片

回到我们指定的路径下面查看一下,是否生成了csv文件:person.csv

Python3 不解压直接解析xml文件,并进行csv出力_第5张图片

打开已经生成的person.csv文件,看看是否已经写入了我们需要的数据:

Python3 不解压直接解析xml文件,并进行csv出力_第6张图片

OK,到这里就已经成功实现了在不解压zip文件的情况下直接读取里面的xml文件,并解析数据写入到csv文件中。

注:

    ①由于各种压缩方式不一致,zip不支持固实压缩,因此可以不解压直接读取其中的文件内容;其他常用的压缩方式如rar、7z等都是采用的固实压缩,将要压缩的所有文件作为一块数据进行压缩,所以要读取其中的文件内容,但是如果是一个文件单独进行压缩的倒是可以实现。

    ②关于出力的csv文件中中文乱码的问题:

        在csv出力的代码中:

Python3 不解压直接解析xml文件,并进行csv出力_第7张图片

    在这里,我们设置了打开文件的编码格式为utf-8,在出力的csv文件中,使用文本编集工具打开时,里面的中文正常显示;但是用Excel打开时,里面的中文出现乱码:

Python3 不解压直接解析xml文件,并进行csv出力_第8张图片

这是因为中文的编码一般使用的是GBK,而Excel对中文的默认编码格式也是如此,如果在写入的时候使用utf-8的编码格式写入,Excel在自动解析的时候就会出现中文乱码的情况。

如果想要使用Excel打开时中文不出现乱码现象,很简单,代码中只需在csv出力中不要设置编码格式,即:

def csvOut(file, header, dataList):
    # 打开文件
    with open(file, "w", newline="") as csvFile:
        # 通过 csv.writer() 获取一个写对象
        writer = csv.writer(csvFile, dialect="excel")
        # Header写入
        writer.writerow(header)

        # data写入
        for data in dataList:
            for row in data:
                writer.writerow(row)

这样就解决了使用Excel打开csv文件时中文显示乱码的问题。

大家有问题欢迎批评指正。

 

你可能感兴趣的:(Python,Python3,zip,xml,csv)