数据分析进阶 更复杂的数据格式处理

目的:练习BeautifulSoup和xml的在清洗数据的使用

练习1:获取航空公司列表

描述:根据给定的excel文件获取一个包含所有航空公司的列表。在你所返回的数据中要去掉所有类似 “All U.S. Carriers” 的组合。最终你应该返回一个含有运营商编码的列表

from bs4 import BeautifulSoup
html_page = "options.html"

def extract_carriers(page): data = []#存放结果数据 with open(page,'r') as html:
#使用BeautifulSoup解析html文件,并且使用默认的lxml引擎 soup = BeautifulSoup(html,'lxml')
#根据标签的id=CarrierList找到对应的元素(select标签) carryList = soup.find(id='CarrierList')
#找到select标签下的所有option元素 options
= carryList.find_all('option') for option in options:
#如果option的值包含All,去除
if not option['value'].startswith('All'):
#将符合条件的值加入到列表,然后进行返回 data.append(option[
'value']) return data
def test():
    #测试函数,如果assert不出错,则代码符合要求
    data = extract_carriers(html_page)
    assert len(data) == 16
    assert "FL" in data
    assert "NK" in data
   
if __name__ == "__main__":
    test()

练习2:获取机场列表

描述:根据给定的excel文件获取一个包含所有机场的列表。在你所返回的数据中要去掉所有类似 “All U.S. Carriers” 的组合。最终你应该返回一个含有机场编码的列表

该题的解提思路同上,不做详细描述

def extract_airports(page):
    data = []
    with open(page,'r') as html:
        soup = BeautifulSoup(html,'lxml')
        airportList = soup.find(id='AirportList')
        options = airportList.find_all('option')
        for option in options:
            if not option['value'].startswith('All'):
                data.append(option['value'])
        return data

def test():
    data = extract_airports(html_page)
    assert len(data) == 15
    assert "ATL" in data
    assert "ABR" in data

if __name__ == "__main__":
    test()

练习3:处理所有数据

描述:根据一个航班信息的html的表格具有一个表格类“dataTDRight”从该表格中提取航班数据,并作为字典列表,每个字典包含文件中的相关信息和表格行。以下是你应该返回的数据结构示例:

data = [
     {"courier": "FL",
         "airport": "ATL",
         "year": 2012,
         "month": 12,
         "flights": {"domestic": 100,
                     "international": 100}
        },
         {"courier": "..."}
]    

思路:1.通过beautifulsoup来解析html文件

        2.构建如上的数据格式

        3.根据class='dataTDRight'找到html中的元素,同时找到下面的tr,td并获取值

        4.提取满足条件的值,放到定义好的字典中,同时加入到列表中返回即可

from bs4 import BeautifulSoup
import os
datadir = "data"


def process_all(datadir):
    #根据传入的路径,列举并返回文件对象
    files = os.listdir(datadir)
    return files
def process_file(f): data = [] #存放结果数据 with open("{}/{}".format(datadir, f),"r") as html: soup=BeautifulSoup(html,'lxml')
#构建字典 entry
= {"courier": "", "airport": "", "year":'' , "month": '', "flights": {"domestic": '', "international": ''} }
#将文件中的值填充到字典中 entry[
'courier'],entry['airport'] = f[:6].split("-")
#根据html标签和class名称找到所要提取的元素 table_data
= soup.find('table',{'class':'dataTDRight'})
#找到table下所有的tr
for tr in table_data.find_all('tr'):
#找到tr下所有的td td
= tr.find_all('td')
#如果年月和航班数据应该是整型。你应该跳过包含一年 TOTAL 数据的行
if td[1].text == 'Month' or td[1].text == 'TOTAL': continue else:
#将td中的数据依次填入到字典中, entry[
'year'] = int(td[0].text) entry['month'] = int(td[1].text) entry['flights']['domestic'] = int(td[2].text.replace(',','')) entry['flights']['international'] = int(td[3].text.replace(',',''))
#把字典加入到列表中,然后进行返回 data.append(entry)
return data
def test():
    #测试函数,调用process_all()函数,然后和某些值进行对比,如果不出错,说明代码符合要求
    print "Running a simple test..."
    files = process_all(datadir)
    data = []
    # Test will loop over three data files.
    for f in files:
        data += process_file(f)
        
    assert len(data) == 399  # Total number of rows
    for entry in data[:3]:
        assert type(entry["year"]) == int
        assert type(entry["month"]) == int
        assert type(entry["flights"]["domestic"]) == int
        assert len(entry["airport"]) == 3
        assert len(entry["courier"]) == 2
    assert data[0]["courier"] == 'FL'
    assert data[0]["month"] == 10
    assert data[-1]["airport"] == "ATL"
    assert data[-1]["flights"] == {'international': 108289, 'domestic': 701425}
    
    print "... success!"

练习四:专利数据库

描述:运行给定代码,查看报错信息,分析报错的原因

import xml.etree.ElementTree as ET

PATENTS = 'patent.data'

def get_root(fname):

    tree = ET.parse(fname)
    return tree.getroot()


get_root(PATENTS)

报错信息

File "<string>", line unknown
ParseError: junk after document element: line 657, column 0

报错信息显示在该文件的657行又有一个<?xml>标签开头,所以分析错误为重复定义的行

练习五:处理专利

描述:

  1.该文件不是有效的xml文件,因为其包含多个头部声明<?xml version="1.0" encoding="UTF-8"?>

        2.根据xml声明的头将文件拆封成多个独立有效的xml文件

思路:

  1.要把整体文件 A 拆分成单独的子文件(A1,A2,A3......)

       2. 在打开A的同时,打开文件根据序号和文件名以w模式打开句柄

       3.循环文件A,如果在A文件中遇到<?xml开头的字符串,则将子文件关闭,同时文件序号+1,并且开启一个新的子文件句柄来进行写操作

       4.写子文件

       5.当A文件循环完毕,关闭子文件

PATENTS = 'patent.data' #目标文件(A)

def split_file(filename):
#打开文件A,作为待修改的数据文件 with open(filename,
'r') as input_file: file_num = -1 #子文件的编号
#子文件命名的方式,使用'文件名-文件编号'组成,并且以w模式打开文件句柄 output_file = open('{}-{}'.format(filename,file_num),'w') for line in input_file: #循环A文件
#如果A文件中遇到声明行
if line.startswith('<?xml'):
#将子文件关闭,同时文件序号+1,并且开启一个新的文件句柄来等待写入 output_file.close() file_num
+=1 output_file = open('{}-{}'.format(filename,file_num),'w')
#如果没有遇到声明的行,则将A文件的数据写入到子文件中 output_file.write(line)
#循环结束,关闭子文件 output_file.close()
def test():
    #测试函数
    split_file(PATENTS)
    for n in range(4):
        try:
            fname = "{}-{}".format(PATENTS, n)
            f = open(fname, "r")
            if not f.readline().startswith("<?xml"):
                print "You have not split the file {} in the correct boundary!".format(fname)
            f.close()
        except:
            print "Could not find file {}. Check if the filename is correct!".format(fname)

if __name__ == "__main__":
    test()

      

       

       

       

原文地址:https://www.cnblogs.com/luhuajun/p/7900560.html