前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >还在写日报?python来帮你

还在写日报?python来帮你

作者头像
赵云龙龙
发布2019-10-22 15:26:19
1.3K0
发布2019-10-22 15:26:19
举报
文章被收录于专栏:python爱好部落python爱好部落

工作中,每天要写报告,要将各种数据汇总,发给相关人员。有的时候,系统或者工具不能满足我们快速拿到数据,很费时。关键有的时候太忙,还容易忘记。

看到同事每天花很多时间来写测试报告,从jira里面总结数据,然后编辑各种格式,写成邮件发出来。虽然jira里面dashboard也可以看到一些,也能导出excel,但是管理人员不会去看,要看最终能得出结论的数据。 我都是每天自动发报告,通过自动调用jira接口,数据分析总结,生成报表,给自己发邮件,自己审核一下,就可以快速下班了。 先看看效果:

这个是部分的柱状图,这样相关人士一眼就能得到结论,比冰冷的数据更直观。

如果关心数据,这个表能很好体现。

虽然jira接口很强大,基本上手工操作的,接口里面都有方法,我觉得还是有点不好的地方,就是太琐碎,没有模块化。如果你要组装成一个你想要的,还得费很大功夫。所以我还利用了爬虫,直接得一个完整的表。建了个filter,直接登陆进去,通过pandas 的read_html就可以得到一个完整的矩阵表,比调用jira接口去组装快多了。

先看看jira接口是如何使用的,先要安装jira的这个包。

代码语言:javascript
复制
pip install jira

装完后就可以直接使用了, 先要登陆

代码语言:javascript
复制
from jira import JIRA
jira = JIRA(server='http://127.0.0.1:8080', basic_auth=('user_name', 'password'))
print(jira.user(jira.current_user()))#当前用户

jira的功能很多,用得多的可能是查询。

代码语言:javascript
复制
result=jira.search_issues("labels =Snake AND status not in (Closed, Resolved, 'UAT GLed')")

但是这样查询有个问题,只显示50个数据。 所以还得加个字段,maxResults,给个大点的值得。

代码语言:javascript
复制
result = jira.search_issues(sql, maxResults=600)

如果要对某个数据的某个字段查询,是这样的:

代码语言:javascript
复制
issues = jira.issue("ME-8431")
print(issues)
print(issues.fields.priority)

fields根据你的需要选择。好了,jira这块就说这么多,下面来说用爬虫如何操作。 jira也提供了session式的登陆接口:

代码语言:javascript
复制
rest/gadget/1.0/login 登录URI rest/gadget/1.0/login
os_username 用户名 JIRA登录用户名
os_password 用户密码 JIRA登录用户密码
os_cookie cookie模式 true为使用cookie方式登录模式,false为关闭

这样就能登陆进去了:

代码语言:javascript
复制
filter_url = "xxx/?filter=163201"
base_url = "Snakeisthebest/rest/gadget/1.0/login"
data = {
"os_username": jira_username,
"os_password": jira_password,
"os_cookie": True
}

res=requests.session()
res.post(base_url,data)

result=res.get(filter_url)

import pandas as pd
result2=pd.read_html(result.text)
print(result2)
b = pd.DataFrame(result2)

这样,数据就拿到了。对数据清洗,画图表,都可以了。可以写个公用的画各种图表的函数,类似这样的。

代码语言:javascript
复制
def bug_status_picture(df):
    df.plot.bar()
    plt.xlabel('Develop')
    # 设置y周标签
    plt.ylabel('Bug number')
    # 设置图表标题
    plt.title('OneApp bug status')
    # # 设置图例的文字和在图表中的位置
    # plt.legend(, loc='upper right')
    # 设置背景网格线的颜色,样式,尺寸和透明度
    plt.grid(color='#95a5a6', linestyle='--', linewidth=1, axis='y', alpha=0.4)
    plt.show()
    plt.savefig("bug_{}.png".format(datetimenow))

这样有个问题,生成的图片中x轴的字是竖着的,可以加个参数解决。

代码语言:javascript
复制
df.plot.bar(alpha=0.75, rot=0)

将生成的结果,发邮件,如果用text,黑乎乎的,不美观。用html的,可以搞样式,就美观很多。 问题来了,我知道pandas 的to_html可以弄成一个html的图表,但是多个dataframe怎么弄。 网上我搜到了例子。

代码语言:javascript
复制
def write_htmls(df_list):
    HEADER = '''
        <html>
            <head>
                <meta charset="UTF-8">
            </head>
            <body>
        '''
    FOOTER = '''
            </body>
        </html>
        '''
    with open(os.path.join(os.getcwd(), 'test.html'), 'w') as f:
        f.write(HEADER)

        for each_df in df_list:
            print(type(each_df))
            # f.write('<h1><strong>' + '自定义dataframe名' +'</strong></h1>')
            f.write(each_df.to_html(classes='classname'))
        f.write(FOOTER)

生成的结果很丑,尝试换个样式。

代码语言:javascript
复制
def generate_df_html(arg):
    html_str = ""
    html_temp = """
                <h2>{}</h2>

            <div>
                <h4></h4>
                {}

            </div>
            <hr>
    """

    for k in sorted(arg.keys()):
        df_html = arg[k].to_html(escape=False)

        html_str = html_str + html_temp.format(k, df_html)

        if k == 'Total_bugs':
            html_str = html_str + """<table><tr><td><img src="cid:Total_bugs"></td></tr></table>"""


    return html_str


def get_html_msg(df):
    head = \
        """
        <head>
            <meta charset="utf-8">
            <STYLE TYPE="text/css" MEDIA=screen>

                table.dataframe {
                    border-collapse: collapse;
                    border: 2px solid #a19da2;
                    /*居中显示整个表格*/
                    margin: left;
                }

                table.dataframe thead {
                    border: 2px solid #91c6e1;
                    background: #f1f1f1;
                    padding: 10px 10px 10px 10px;
                    color: #333333;
                }

                table.dataframe tbody {
                    border: 2px solid #91c6e1;
                    padding: 10px 10px 10px 10px;
                }

                table.dataframe tr {

                }

                table.dataframe th {
                    vertical-align: top;
                    font-size: 14px;
                    padding: 10px 10px 10px 10px;
                    color: #105de3;
                    font-family: arial;
                    text-align: center;
                }

                table.dataframe td {
                    text-align: center;
                    padding: 10px 10px 10px 10px;
                }

                # body {
                #     font-family: 宋体;
                # }

                # h1 {
                #     color: #5db446
                # }

                div.header h2 {
                    color: #0002e3;
                    font-family: 黑体;
                }

                div.content h2 {
                    text-align: left;
                    font-size: 18px;
                    # text-shadow: 2px 2px 1px #de4040;
                    #color: #fff;
                    color:#008eb7
                    font-weight: bold;
                    #background-color: #008eb7;
                    # line-height: 1.5;
                    # margin: 20px 0;
                    # box-shadow: 10px 10px 5px #888888;
                    # border-radius: 5px;
                }

                h3 {
                    font-size: 22px;
                    background-color: rgba(0, 2, 227, 0.71);
                    text-shadow: 2px 2px 1px #de4040;
                    color: rgba(239, 241, 234, 0.99);
                    line-height: 1.5;
                }

                h4 {
                    color: #e10092;
                    font-family: 楷体;
                    font-size: 20px;
                    text-align: center;
                }

            </STYLE>
        </head>
        """

    # 构造模板的附件(100)

    message = """
    Hi all,

  Latest bug status for snake, FYI
  
  """
    body = \
        """
        <body>

        <div align="left" class="header">
            <!--标题部分的信息-->
            <h1 align="left">{}</h1>
        </div>

        <hr>

        <div class="content">
            <!--正文内容-->

            {}
            <p style="text-align: left">
                Any question, please let me know, Thanks!
            </p>
        </div>
        </body>
        """.format(message, df)
    html_msg = "<html>" + head + body + "</html>"
    print(html_msg)
    # 这里是将HTML文件输出,作为测试的时候,查看格式用的,正式脚本中可以注释掉
    fout = open('{}.html'.format(datetimenow), 'w', encoding='UTF-8', newline='')
    fout.write(html_msg)
    fout.close()
    return html_msg

结果看起来还凑合:

现在开始需要利用stmp来发邮件了,选择用html加附件的模式,网上找了个例子,一般我喜欢用yagmail,好像不能满足。

代码语言:javascript
复制
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
msg['From'] = "XXX@XXX.com"   #邮件发件人
msg['To'] = "YYY@YYY.com"     #邮件接收人
msg['Subject'] = "hello world"   ##邮件主题
def addimg(img_src,imgid):
  fp = open(img_src,'rb')
  msgImage = MIMEImage(fp.read())
  fp.close()
  msgImage.add_header('Conteng-ID',imgid)
  return msgImage                ##返回msgImage对象
msg_text = MIMEText("""<table><tr><td><img src="cid:aa"></td></tr></table>""","html","utf-8")
#创建MIMEMultipart对象,采用related定义内嵌资源
msg = MIMEMultipart('related')
msg.attach(msg_text)
msg.attach(addimg("C:\aa.img",aa))      ##这里的aa要与msg_text里的aa对应
#发送邮件
server = smtplib.SMTP()
server.connect('smtp.XXX.com',"25")
server.starttls()    ##启动安全传输模式
server.login('XXX','XXXXX')      #XXX为用户名,XXXXX为密码
server.sendmail(msg['From'], msg['To'],msg.as_string())  #这里的前两个参数自定义
server.quit()

测试,发现了一个问题,就是如果用爬虫方式弄的数据,jira里面的priority拿不到,因为页面用的是图标。 这个可以用接口来查询一下,在datafram里面来替换。 对某列的操作,可以用apply或map就可以了

代码语言:javascript
复制
对某列操作,可以用map或者apply
eg: df["FullName"]=df["Name"].map(lambda x: x.split(",")[1].strip())

对一列数据去空格的方法:
def qukong(hang):
  return hang['city'].strip()
dataframe['city']=dataframe.apply(qukong,axis=1) # axis=1表示对每一行做相同的操作

我用的是map。

代码语言:javascript
复制
    bug_result_df["Priority"]=bug_result_df["Key"].map(lambda x: (jira.issue(x)).fields.priority)
    show_list = ["Key", "Summary", "Assignee", "Status","Priority", "Created"]
    bug_detail_df = bug_result_df[show_list]

选择需要展示的列切片就完美解决了这个问题。

总结

由于这块太久没弄了,也有段时间没写代码了,写起来不是那么顺,各种问题,但都被解决了。 这个玩意作用虽然很小,如果这么多人,天天能节省几分钟,一年下来也是个很可观的效率提升。 虽然公司不能写代码,晚上在家熬夜写点东西,也是很爽的。

然后跟同事分享了,他们都觉得好,这样就推广起来了。有的时候,独乐乐,不如众乐乐。

更多精彩,请关注微信公众号:python爱好部落

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 python爱好部落 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云 BI
腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档