需求场景:
获取指定confluence文档中的表格数据,同时将页面中的附件下载在指定的文件夹中。
实现步骤:
-
开启confluence的远程api端口
-
选择使用的接口。 可以参考 官方接口文档 。
-
当前示例用到的接口为:
Get content
/rest/api/content/{content_id}
Content - attachments
/rest/api/content/{content_id}/child/attachment
-
调用接口,查看接口返回的数据是否满足要求。
-
首先获取文档内容:
/rest/api/content/{content_id}
没有需要的表格内容。
先来看一下如果使用接口创建一个content需要传递什么参数,参考 官方文档 , 示例参数中有一个body结构体,而获取文档接口返回值中没有该内容。
在获取文档内容结构中添加参数
?expand=body.storage
, 即获取body结构体中的storage对象。再次查看接口返回值:注意: 接口返回的表格数据和我们在页面看到的表格相比,缺失了部分内容。比如含有json、zip文件的列。 接口返回的表格数据不会包含其他页面的引入数据。可以点击编辑查看本页面的数据。
接口返回值中,多的内容像是html的表格内容。我们可以`pandas.read_html()`直接读取这个表数据。
-
查看文档附件接口的内容:
/rest/api/content/{content_id}/child/attachment
-
-
编码实现功能:
import os import re from datetime import datetime import pandas as pd import requests from clint.textui import progress from sqlalchemy import create_engine def confirm_path_exists(path): if not os.path.exists(path): os.makedirs(path) def is_url(url): pattern = re.compile("^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\/])+$") match_obj = pattern.match(url) if match_obj != None: return True else: return False def get_df_from_html(html, table_index=0): """ 获取html中的表格 :param html: html数据 :param table_index: 表格的编号,标定数据表格一般是第一个,drsu数据表格一般为最后一个 :return: 表格数据 """ df = pd.read_html(html) # 表数据处理 # 获取table数据 if len(df) == 0: print('页面没有table结构') return False, '页面没有table结构' df_with_zip = df[table_index] return df_with_zip confluence_host = 'http://172.18.3.2:8090' mmp_host = 'http://127.0.0.1:5000' def get_content(session, content_id=7209464): """ 获取指定页面的内容 :param session: :param content_id: :return: """ url = confluence_host + f'/rest/api/content/{content_id}?expand=body.storage' res = session.get(url) return res def get_attachments(session, content_id=7209464): """ 获取页面的附件 :param session: 会话 :param content_id: 页面id :return: 附件列表 """ url = confluence_host + f'/rest/api/content/{content_id}/child/attachment' res = session.get(url) content_attachments = [] if res.status_code == 200: res_data = res.json() content_attachments.extend(res_data['results']) while res_data['size'] >= res_data['limit']: if 'next' in res_data['_links']: next_url = confluence_host + res_data['_links']['next'] else: print(f'缺少翻页的链接: {res_data["_links"]}') break res = session.get(next_url) if res.status_code == 200: res_data = res.json() content_attachments.extend(res_data['results']) else: print(f'获取附件出错:{res.text}') return content_attachments def get_zip_file_list(attachments_list): """ 筛选出zip类型的附件信息 :param attachments_list: 附件列表 :return: """ zip_file_list = [] for attachment in attachments_list: # 判断是否是zip文件 if attachment['extensions']['mediaType'] == 'application/zip': # 将节点中的信息格式化处理 down_host = attachment['_links']['self'].split('/rest')[0] zip_file_list.append({ 'file_name': attachment['title'], 'file_href': down_host + attachment['_links']['download'], }) print(zip_file_list) return zip_file_list def write_db(df, table_name, engine): # 写入数据库 df.to_sql(table_name, con=engine, if_exists='append', index=False) def download_file(session, url, save_dir='./', file_name=None): """ 根据url将文件下载至指定位置 :param save_dir: :param url: 下载地址 :param save_path: 保存路径 :return: """ # 确认路径是否存在 confirm_path_exists(save_dir) # url合法性校验 if not is_url(url): return False, 'url 不合法' if file_name is None: if '?' in url: url = url.split('?')[0] file_name = url.split('/')[-1] save_path = os.path.join(save_dir, file_name) # 文件下载 res = session.get(url) if res.status_code != 200: print(res.text) return False, res.text try: with open(save_path, 'wb') as f: # 添加进度条 total_length = int(res.headers.get('content-length')) for chunk in progress.bar(res.iter_content(chunk_size=2391975), expected_size=(total_length / 1024) + 1): if chunk: f.write(chunk) f.flush() if not os.path.isfile(save_path): return False, '文件下载失败。' except Exception as e: print(f'错误信息: {str(e)}') return False, str(e) return True, '成功' def inset_table(session, html_id=7209464, table_name='version_upgrade', engine=create_engine(f'sqlite:///cal.db', encoding='utf8')): res = get_content(session, html_id) if res.status_code == 200: # 标定文件表数据 html_view = res.json()['body']['storage']['value'] df = get_df_from_html(html_view) write_db(df, table_name, engine) def download_cal_and_update_table(session, html_id, save_dir): # 标定附件 attachments = get_attachments(session, html_id) # 标定文件下载信息 file_info = get_zip_file_list(cal_attachments) for zip_file in file_info: url = zip_file['file_href'] file_name = zip_file['file_name'] download_status, msg = download_file(session, url, save_dir) def main(): # 登录cookies,因为confluence设置了登录验证码,所以这里直接使用cookie跳过登录操作 header = { 'Cookie': 'JSESSIONID=404FEBB859A8D689A590BCE4BE574F' } # 导入的表名 table_name = 'cal_version_upgrade' # 导入的数据库 db_path = r'D:\work\drsu_mmp\drsu_mmp_backend\config\drsu.db' engine = create_engine(f'sqlite:///{db_path}', encoding='utf8') # 下载标定文件保存位置 save_dir = r'D:\home\drsu_mmp\upgrade\calibration\' # confluence标定文档id html_id = 7209464 session = requests.session() session.headers = header # 将标定文档中的数据插入表数据 inset_cal_table(session, html_id=html_id, table_name=table_name, engine=engine) # 根据标定文档和drsu文档信息更新标定版本记录表数据 download_zip_and_update_table(session, cal_html_id, proj_id, save_dir)