python:从阿里ODPS(maxcomputer)读取数据写入Excel

0. 背景及目标

在使用阿里maxcomputer进行数据库查询过程中,当查询结果超过一万行时无法直接导出csv文件,解决方法比较多:
1、MaxCompute Studio的基础平台IntelliJ IDEA,将查询结果写入临时表中,在客户端进行导出
(阿里教程:https://help.aliyun.com/document_detail/50891.html?spm=5176.10695662.1996646101.searchclickresult.3dc41598EQEYGm&aly_as=Vu68vGZA);
2、安装Navicat Premium(可链接多个数据库的管理工具),查询并导出;
3、其他。
因为嫌安装和配置软件比较麻烦,且最近在学习python,所以想练习下,写代码实现将查询结果直接写入Excel中。
本文仅作为自己的学习记录。

1.用到的工具及软件包

python集成开发环境:pycharm
Python版本: Python3.7
ODPS:第三方库,连接maxcomputer查询数据
openpyxl:第三方库,处理xlsx格式的Excel文件
datetime:处理时间

2.遇到的问题

1、第一次接触odps,不太会o(╥﹏╥)o。引用知乎上周田的回答:pyodps提供了用python去操作odps的接口,你可以用你熟悉的python与odps交互,操作odps上的表、任务、函数、资源等。pyodps说明文档:https://pyodps.readthedocs.io/zh_CN/latest/?spm=a2c4g.11186623.2.2.OXF9Bx
2、在将sql查询结果写入Excel时,因含有反斜杠等特殊字符导致写入失败,故需要进行处理,我用的方法比较笨,用遍历sql查询结果将特殊字符替换为空的方式来实现的,总之是达到目的了,毕竟目前是小白,先实现效果再说。

3.实现代码

下面定义了三个基本功能模块,分别是连接odps,异常字符串处理,写入Excel

from odps import ODPS
#链接odps
o = ODPS(access_id='xxxxxxx', #登陆账号
         secret_access_key='xxxxxxxx', #登陆密码
         project='xxxxxx', #odps上的项目名称
         endpoint='http://service.odps.aliyun.com/api') #官方提供的接口

#定义处理非法字符的方法
def illegal_char_rm(l):
    la = list()
    from openpyxl.cell.cell import ILLEGAL_CHARACTERS_RE
    for record in l: #遍历每条表记录
        for index,value in enumerate(record.values): #遍历记录的每一列的值,record.values类型为list,取list的index和value需要用enumerate,不然会报错
            record[index]=ILLEGAL_CHARACTERS_RE.sub('', value) if isinstance(value,str) else value #如果值类型为字符串,替换为空,否则保留原值
        la.append(record)
    return la

#定义写Excel的方法
def write_excel(workbook_name,sheet_name,data):
    data = illegal_char_rm(data) #写入前进行非法字符处理
    import openpyxl
    workbook = openpyxl.Workbook() #创建工作簿workbook
    sheet = workbook.active #创建工作表sheet,默认使用active页
    sheet.title = sheet_name #给工作表赋名
    sheet.append(list(data[0]._name_indexes.keys())) #取sql查询结果的字段名
    for record in data:
        sheet.append(record.values) #取每条记录
    workbook.save(workbook_name) #保存工作薄并命名

下面是将我在工作中用两种方式获取的数据导入Excel的方法
方法一:

#定义用sql查询结果写入Excel方法
def write_excel_form_sql(workbook_name,sheet_name,sql):
    #定义查询语句的分区参数(取昨日)
    import datetime
    ds = (datetime.datetime.now() + datetime.timedelta(days=-1)).strftime('%Y%m%d')
    sql = sql.replace('${bdp.system.bizdate}', ds)
    #读取查询记录
    instance = o.execute_sql(sql)
    reader =instance.open_reader()
    #写入表格
    write_excel(workbook_name,sheet_name,reader)
    
#将sql临时查询结果写入Excel
workbook_name=r'E:\test'+'.xlsx'  #这里可以定义存储路径,不要忘了前边的r,即保留字符串,反斜杠不转义
sheet_name='maydata' 
sql = '''
SELECT  user_id 用户id
        ,wechat_name 微信昵称
        ,user_name 用户名字
FROM    dim_user u
WHERE   u.ds = '${bdp.system.bizdate}' --系统参数。定义为一个实例运行时对应的业务日期,业务日期默认为运行日期的前一天,默认以 yyyymmdd 的格式显示。
'''
write_excel_form_sql(workbook_name,sheet_name,sql)

方法二:

#定义将odps中已存在的表写入Excel方法
def write_excel_form_odpstable(workbook_name,sheet_name,odps_table_name):
    data = [value for value in o.read_table(odps_table_name)]
    write_excel(workbook_name,sheet_name,data)

#将odps中已存在的表写入Excel方法
workbook_name=r'E:\test'+'.xlsx'  #这里可以定义存储路径,不要忘了前边的r,即保留字符串,反斜杠不转义
sheet_name='aa'

#将odps中已存在的表写入Excel
odps_table_name='table_name' #odps中已存在的表的名字,没有分区的
write_excel_form_odpstable(workbook_name,sheet_name,odps_table_name)

你可能感兴趣的:(python)