功能

  • [x] 支持导出的数据:IP地址、漏洞名称、风险等级、整改建议、漏洞描述、漏洞CVE编号、漏洞对应端口、漏洞对应协议、漏洞对应服务等。
  • [x] 导出不同端口的同一个漏洞,也就是一个端口对应一个漏洞,保证导出漏洞的完整性。
  • [x] 导出端口和导出网站为单独的功能,导出网站的功能是采用正则去匹配http、www这两个服务。
    1. import os
    2. import re
    3. import sys
    4. import html
    5. import queue
    6. import shutil
    7. import zipfile
    8. import datetime
    9. import openpyxl
    10. import images_ico
    11. import PyQt5.sip
    12. from PyQt5.QtGui import QIcon
    13. from PyQt5 import QtCore, QtGui, QtWidgets
    14. from openpyxl.styles import PatternFill, Font, Alignment, Border, Side
    15.  
    16. class Vul_re(object):
    17. def __init__(self):
    18. super(Vul_re, self).__init__()
    19. self.vul_list_re = '<python>ip<python>.*?<python>host<python>.*?<td valign="top".*?<th width="120">IP地址</th>.*?<td>(.*?)</td>.*?</td>.*?<python>host</python>.*?<python>vul_list<python>(.*?)<python>vul_list</python>.*?<python>ip</python>'
    20. self.vul_ip_re = '(<python>ip<python>.*?<python>ip</python>)'
    21. self.vul_detail_re = '<python>vul_detail<python>(.*?)<python>vul_detail</python>'
    22. self.vul_details_re = '<python>vul_details<python>(.*?)<python>vul_details</python>'
    23.  
    24. self.danger_re = '<span class="level_danger_(.*?)".*?table_\d_(\d+).*?>(.*?)</span>'
    25. self.title_re = '<python>title<python>(.*?)<python>title</python>'
    26. self.time_re = '<python>host<python>.*?(\d+-\d+-\d+).*?<python>host</python>'
    27. self.other_re = '<td class="vul_port">(.*?)</td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?<td>.*?<ul>(.*?)</ul>'
    28.  
    29. class File_re(object):
    30. def __init__(self):
    31. super(File_re, self).__init__()
    32. self.file_re = '.*?.zip'
    33. self.uzip_re = '.*?.html'
    34. self.all_title_re = '<th width="120">任务名称</th>.*?<td>(.*?)</td>'
    35. self.vul_list_re = '(<table id="vuln_list" class="report_table">.*?</table>)'
    36. self.vul_detail_re = '(<div id="vul_detail">.*?</div>)'
    37. self.vul_details_re = '(<tr class="solution.*?">.*?<td>.*?<table class="report_table plumb".*?>.*?</table>.*?</td>.*?</tr>)'
    38. self.host_re = '(<td valign="top" style="width:50%;">.*?<table class="report_table plumb">.*?<tbody>.*?<th width="120">IP地址</th>.*?</tbody>.*?</table></td>)'
    39.  
    40. class Vul_content(object):
    41. def __init__(self,vul_re):
    42. super(Vul_content, self).__init__()
    43. self.vul_ip_content = re.findall(vul_re.vul_ip_re,htmlcont,re.S|re.M)
    44. self.vul_detail_content = re.findall(vul_re.vul_detail_re,htmlcont,re.S|re.M)
    45.  
    46. class Solve_re(object):
    47. def __init__(self):
    48. super(Solve_re, self).__init__()
    49. self.solve_re = '<th width="100">解决办法</th>.*?<td>(.*?)</td>'
    50. self.describe_re = '<tr class="solution.*?table_\d_(\d+).*?<th width="100">详细描述</th>.*?<td>(.*?)</td>'
    51. self.cve_re = '<th width="100">CVE编号</th>.*?<td><a target=.*?>(.*?)</a>.*?</td>'
    52.  
    53. class Other(object):
    54. def __init__(self, vul_re, all_vuln_list):
    55. super(Other, self).__init__()
    56. self.all_other = re.findall(vul_re.other_re,all_vuln_list,re.S|re.M)
    57.  
    58. class Danger(object):
    59. def __init__(self, vul_re, other):
    60. super(Danger, self).__init__()
    61. self.danger_coneent = re.findall(vul_re.danger_re,other,re.S|re.M)
    62.  
    63. class Solve(object):
    64. def __init__(self, solve, all_vul_details):
    65. super(Solve, self).__init__()
    66. self.solve_plumb = re.findall(solve.solve_re,all_vul_details,re.S|re.M)
    67. self.describe_plumb = re.findall(solve.describe_re,all_vul_details,re.S|re.M)
    68. self.cve_plumb = re.findall(solve.cve_re,all_vul_details,re.S|re.M)
    69.  
    70. class Port_File_re(object):
    71. def __init__(self):
    72. super(Port_File_re, self).__init__()
    73. self.file_re = '.*?.zip'
    74. self.uzip_re = '.*?.html'
    75. self.all_title_re = '<th width="120">任务名称</th>.*?<td>(.*?)</td>'
    76. self.host_re = '<th width="120">IP地址</th>.*?<td>(\d+.\d+.\d+.\d+)</td>.*?<th>扫描起始时间</th>.*?<td>(\d+-\d+-\d+).*?</td>.*?<thead>.*?<th>端口</th>.*?<th>协议</th>.*?<th>服务</th>.*?<th>状态</th>.*?</thead>.*?<tbody>(.*?)</tbody>'
    77. self.port_re = '<tr class=".*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?<td>(.*?)</td>.*?</tr>'
    78. self.http_re = '.*?http.*?'
    79. self.https_re = '.*?https.*?'
    80. self.www_re = '.*?www.*?'
    81.  
    82. class Ui_MainWindow(object):
    83. def setupUi(self, MainWindow):
    84.  
    85. try:
    86. with open('set.ini') as set_ini:
    87. name_ini = set_ini.readlines()[:1][0].split(':')[1].strip(' \n')
    88. with open('set.ini') as set_ini:
    89. company_ini = set_ini.readlines()[1:2][0].split(':')[1].strip(' \n')
    90. except Exception as e:
    91. QtWidgets.QMessageBox.information(MainWindow, "提示", "找不到配置文件,请查看使用说明!", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No , QtWidgets.QMessageBox.Yes )
    92.  
    93. font = QtGui.QFont()
    94. font.setFamily("宋体")
    95. font.setPointSize(10)
    96. MainWindow.setFont(font)
    97. #定义程序的标题
    98. MainWindow.setWindowTitle('RSAS漏洞数据导出工具1.5')
    99. #设定程序的最大分辨率,禁止最大化、拖动窗口
    100. MainWindow.setFixedSize(520, 310)
    101. #设置图标
    102. MainWindow.setWindowIcon(QIcon(':/favicon.ico'))
    103. #获取显示器的分辨率
    104. screen = QtWidgets.QDesktopWidget().screenGeometry()
    105. #获取程序的宽和高
    106. size = MainWindow.geometry()
    107. #实现在屏幕中间显示程序
    108. MainWindow.move((screen.width() - size.width())/2, (screen.height() - size.height())/2)
    109.  
    110. #这是底部的状态栏
    111. MainWindow.status = MainWindow.statusBar()
    112. MainWindow.status.showMessage("检查人员:%s 所属公司:%s" % (name_ini,company_ini))
    113.  
    114. #这是一个框架,用来固定按钮用的
    115. self.formLayoutWidget = QtWidgets.QWidget(MainWindow)
    116. self.formLayoutWidget.setGeometry(QtCore.QRect(10, 10, 411, 54))
    117. self.formLayoutWidget.setObjectName("formLayoutWidget")
    118. self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
    119. self.formLayout.setContentsMargins(0, 0, 0, 0)
    120. self.formLayout.setObjectName("formLayout")
    121. #文字:原始报告路径
    122. self.input_label = QtWidgets.QLabel(self.formLayoutWidget)
    123. self.input_label.setObjectName("input_label")
    124. self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.input_label)
    125. #文字:输出报告路径
    126. self.output_label = QtWidgets.QLabel(self.formLayoutWidget)
    127. self.output_label.setObjectName("output_label")
    128. self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.output_label)
    129. #原始报告路径后边的文本框
    130. self.input_lineEdit = QtWidgets.QLineEdit(self.formLayoutWidget)
    131. self.input_lineEdit.setObjectName("input_lineEdit")
    132. self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.input_lineEdit)
    133. #输出报告路径后边的文本框
    134. self.output_lineEdit = QtWidgets.QLineEdit(self.formLayoutWidget)
    135. self.output_lineEdit.setObjectName("output_lineEdit")
    136. self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.output_lineEdit)
    137. #框架的结束部分
    138. spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
    139. self.formLayout.setItem(1, QtWidgets.QFormLayout.LabelRole, spacerItem)
    140. #这玩意就是打开路径按钮的框架
    141. self.start_verticalLayoutWidget = QtWidgets.QWidget(MainWindow)
    142. self.start_verticalLayoutWidget.setGeometry(QtCore.QRect(423, 2, 91, 71))
    143. self.start_verticalLayoutWidget.setObjectName("start_verticalLayoutWidget")
    144. self.start_verticalLayout = QtWidgets.QVBoxLayout(self.start_verticalLayoutWidget)
    145. self.start_verticalLayout.setContentsMargins(0, 0, 0, 0)
    146. self.start_verticalLayout.setObjectName("start_verticalLayout")
    147. #这是原始报告路径后边的文本框后边的打开路径按钮
    148. self.input_Button = QtWidgets.QPushButton(self.start_verticalLayoutWidget)
    149. self.input_Button.setObjectName("input_Button")
    150. self.start_verticalLayout.addWidget(self.input_Button)
    151. self.input_Button.clicked.connect(self.input_Button_click)
    152. #这是输出报告路径后边的文本框后边的打开路径按钮
    153. self.output_Button = QtWidgets.QPushButton(self.start_verticalLayoutWidget)
    154. self.output_Button.setObjectName("output_Button")
    155. self.start_verticalLayout.addWidget(self.output_Button)
    156. self.output_Button.clicked.connect(self.output_Button_click)
    157. #这又是一个框架,固定用的
    158. self.horizontalLayoutWidget = QtWidgets.QWidget(MainWindow)
    159. self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 75, 411, 21))
    160. self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
    161. self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
    162. self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
    163. self.horizontalLayout.setObjectName("horizontalLayout")
    164. #文字:选择导出数据
    165. self.data_label = QtWidgets.QLabel(self.horizontalLayoutWidget)
    166. self.data_label.setObjectName("data_label")
    167. self.horizontalLayout.addWidget(self.data_label)
    168. #复选框:高危
    169. self.hight_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget)
    170. self.hight_checkBox.setObjectName("hight_checkBox")
    171. self.horizontalLayout.addWidget(self.hight_checkBox)
    172. #复选框:中危
    173. self.middle_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget)
    174. self.middle_checkBox.setObjectName("middle_checkBox")
    175. self.horizontalLayout.addWidget(self.middle_checkBox)
    176. #复选框:低危
    177. self.low_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget)
    178. self.low_checkBox.setObjectName("low_checkBox")
    179. self.horizontalLayout.addWidget(self.low_checkBox)
    180. #复选框:端口
    181. self.port_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget)
    182. self.port_checkBox.setObjectName("port_checkBox")
    183. self.horizontalLayout.addWidget(self.port_checkBox)
    184. #复选框:网站
    185. self.web_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget)
    186. self.web_checkBox.setObjectName("web_checkBox")
    187. self.horizontalLayout.addWidget(self.web_checkBox)
    188. #这又是一个框架
    189. self.end_verticalLayoutWidget = QtWidgets.QWidget(MainWindow)
    190. self.end_verticalLayoutWidget.setGeometry(QtCore.QRect(423, 69, 91, 31))
    191. self.end_verticalLayoutWidget.setObjectName("end_verticalLayoutWidget")
    192. self.end_verticalLayout = QtWidgets.QVBoxLayout(self.end_verticalLayoutWidget)
    193. self.end_verticalLayout.setContentsMargins(0, 0, 0, 0)
    194. self.end_verticalLayout.setObjectName("end_verticalLayout")
    195. #按钮:开始导出
    196. self.start_Button = QtWidgets.QPushButton(self.end_verticalLayoutWidget)
    197. self.start_Button.setObjectName("start_Button")
    198. self.start_Button.clicked.connect(self.start_Button_click)
    199. #框架结尾
    200. self.end_verticalLayout.addWidget(self.start_Button)
    201. #文字:详细输出日志
    202. self.log_label = QtWidgets.QLabel(MainWindow)
    203. self.log_label.setGeometry(QtCore.QRect(10, 101, 91, 21))
    204. self.log_label.setObjectName("log_label")
    205. #详细输出日志的文本框
    206. self.log_textEdit = QtWidgets.QTextEdit(MainWindow)
    207. self.log_textEdit.setGeometry(QtCore.QRect(10, 120, 501, 171))
    208. self.log_textEdit.setObjectName("log_textEdit")
    209.  
    210. self.retranslateUi(MainWindow)
    211. QtCore.QMetaObject.connectSlotsByName(MainWindow)
    212.  
    213. def retranslateUi(self, MainWindow):
    214. _translate = QtCore.QCoreApplication.translate
    215. self.input_label.setText(_translate("MainWindow", "原始报告路径:"))
    216. self.output_label.setText(_translate("MainWindow", "输出报告路径:"))
    217. self.input_Button.setText(_translate("MainWindow", "打开路径"))
    218. self.output_Button.setText(_translate("MainWindow", "打开路径"))
    219. self.data_label.setText(_translate("MainWindow", "选择导出数据:"))
    220. self.hight_checkBox.setText(_translate("MainWindow", "高危"))
    221. self.middle_checkBox.setText(_translate("MainWindow", "中危"))
    222. self.low_checkBox.setText(_translate("MainWindow", "低危"))
    223. self.port_checkBox.setText(_translate("MainWindow", "端口"))
    224. self.web_checkBox.setText(_translate("MainWindow", "网站"))
    225. self.start_Button.setText(_translate("MainWindow", "开始导出"))
    226. self.log_label.setText(_translate("MainWindow", "详细输出日志:"))
    227.  
    228. #原始报告路径的按钮
    229. def input_Button_click(self):
    230. self.input_Button_cent = QtWidgets.QFileDialog.getExistingDirectory(MainWindow)
    231. self.input_lineEdit.setText(self.input_Button_cent)
    232.  
    233. #输出报告路径的按钮
    234. def output_Button_click(self):
    235. self.output_Button_cent = QtWidgets.QFileDialog.getExistingDirectory(MainWindow)
    236. self.output_lineEdit.setText(self.output_Button_cent)
    237.  
    238. #开始导出的按钮
    239. def start_Button_click(self):
    240. #复选框事件
    241. self.hight_status = self.hight_checkBox.isChecked()
    242. self.middle_status = self.middle_checkBox.isChecked()
    243. self.low_status = self.low_checkBox.isChecked()
    244. self.port_status = self.port_checkBox.isChecked()
    245. self.web_status = self.web_checkBox.isChecked()
    246.  
    247. try:
    248. folder_end = self.output_Button_cent
    249. folder_start = self.input_Button_cent
    250. except Exception as e:
    251. QtWidgets.QMessageBox.information(MainWindow, "提示", "要先设置文件夹!", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No , QtWidgets.QMessageBox.Yes )
    252. return e
    253. else:
    254. try:
    255. with open('set.ini') as set_ini:
    256. name_ini = set_ini.readlines()[:1][0].split(':')[1].strip(' \n')
    257. with open('set.ini') as set_ini:
    258. company_ini = set_ini.readlines()[1:2][0].split(':')[1].strip(' \n')
    259. except Exception as e:
    260. QtWidgets.QMessageBox.information(MainWindow, "提示", "找不到配置文件,请查看使用说明!", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No , QtWidgets.QMessageBox.Yes )
    261. return e
    262.  
    263. try:
    264. shutil.rmtree('temp')
    265. except Exception as e:
    266. pass
    267.  
    268. try:
    269. shutil.rmtree(folder_end+'/汇总-漏洞跟踪表')
    270. except Exception as e:
    271. pass
    272.  
    273. try:
    274. shutil.rmtree(folder_end+'/汇总-端口对应关系表')
    275. except Exception as e:
    276. pass
    277.  
    278. try:
    279. shutil.rmtree(folder_end+'/汇总-WEB网站')
    280. except Exception as e:
    281. pass
    282.  
    283. if self.hight_status or self.middle_status or self.low_status == True:
    284. starttime = datetime.datetime.now()
    285. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    286. self.log_textEdit.insertPlainText('正在提取数据,这个过程可能很慢,请耐心等待!' + '\n')
    287. QtWidgets.QApplication.processEvents()
    288.  
    289. os.mkdir('temp')
    290. with open('temp/database.mdb', 'w',encoding='gb18030') as content:
    291. content.write('')
    292.  
    293. dirList = os.listdir(folder_start)
    294. for name in dirList:
    295. all_file_name = re.findall(File_re().file_re,name)
    296. for file_name in all_file_name:
    297. uzip = zipfile.ZipFile(folder_start+'/'+file_name)
    298. for uzip_content in uzip.namelist():
    299. all_uzip_content = re.findall(File_re().uzip_re,uzip_content)
    300. for all_uzip in all_uzip_content:
    301. htmlcont_zip = uzip.open(all_uzip).read().decode('utf8')
    302. title = re.findall(File_re().all_title_re,htmlcont_zip,re.S|re.M)
    303. for title_content in title:
    304. with open('temp/%s.mdb'%title_content, 'a',encoding='gb18030') as content:
    305. content.write('<python>title<python>')
    306. content.write(html.unescape(title_content))
    307. content.write('<python>title</python>\n')
    308.  
    309. with open('temp/database.mdb','a',encoding='gb18030') as content:
    310. content.write('temp/'+html.unescape(title_content)+'.mdb\n')
    311.  
    312. host = re.findall(File_re().host_re,htmlcont_zip,re.S|re.M)
    313. for host_content in host:
    314. with open('temp/%s.mdb'%title_content, 'a',encoding='gb18030') as content:
    315. content.write('<python>ip<python>\n')
    316. content.write('<python>host<python>\n')
    317. content.write(html.unescape(host_content))
    318. content.write('\n<python>host</python>\n')
    319.  
    320. vul_list = re.findall(File_re().vul_list_re,htmlcont_zip,re.S|re.M)
    321. for list_content in vul_list:
    322. with open('temp/%s.mdb'%title_content, 'a',encoding='gb18030') as content:
    323. content.write('<python>vul_list<python>\n')
    324. content.write(html.unescape(list_content))
    325. content.write('\n<python>vul_list</python>\n')
    326.  
    327. vul_detail = re.findall(File_re().vul_detail_re,htmlcont_zip,re.S|re.M)
    328. for detail_content in vul_detail:
    329. with open('temp/%s.mdb'%title_content, 'a',encoding='gb18030') as content:
    330. content.write('<python>vul_detail<python>\n')
    331.  
    332. vul_details = re.findall(File_re().vul_details_re,detail_content,re.S|re.M)
    333. for list_details in vul_details:
    334. with open('temp/%s.mdb'%title_content, 'a',encoding='gb18030') as content:
    335. content.write('<python>vul_details<python>\n')
    336. content.write(html.unescape(list_details))
    337. content.write('\n<python>vul_details</python>\n')
    338.  
    339. with open('temp/%s.mdb'%title_content, 'a',encoding='gb18030') as content:
    340. content.write('\n<python>vul_detail</python>\n')
    341. content.write('<python>ip</python>\n')
    342.  
    343. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    344. self.log_textEdit.insertPlainText('提取 %s'%file_name + ' 完成!\n')
    345. QtWidgets.QApplication.processEvents()
    346.  
    347. vul_list = queue.Queue()
    348. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    349. self.log_textEdit.insertPlainText('数据提取完成,正在生成漏洞跟踪表...\n')
    350. QtWidgets.QApplication.processEvents()
    351. os.mkdir(folder_end+'/汇总-漏洞跟踪表')
    352.  
    353. vul_re = Vul_re()
    354.  
    355. with open('temp/database.mdb',encoding='gb18030') as content:
    356. for zip_content in content:
    357. vul_all_list = []
    358. vul_all_detail = []
    359.  
    360. zip_cont = zip_content.strip('\n\r')
    361. content = open(zip_cont,'r',encoding='gb18030')
    362. global htmlcont
    363. htmlcont = content.read()
    364. content.close()
    365.  
    366. sheet_name = re.findall(vul_re.title_re,htmlcont,re.S|re.M)[0]
    367. sheet_time = re.findall(vul_re.time_re,htmlcont,re.S|re.M)[0]
    368. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    369. self.log_textEdit.insertPlainText('正在导出 %s\n' % sheet_name)
    370. QtWidgets.QApplication.processEvents()
    371.  
    372. wb = openpyxl.Workbook()
    373. ws = wb.active
    374. ws.title = '漏洞数据'
    375. ws.column_dimensions['A'].width = 6
    376. ws.column_dimensions['B'].width = 13
    377. ws.column_dimensions['C'].width = 24
    378. ws.column_dimensions['D'].width = 11
    379. ws.column_dimensions['E'].width = 11
    380. ws.column_dimensions['F'].width = 53
    381. ws.column_dimensions['G'].width = 6
    382. ws.column_dimensions['H'].width = 6
    383. ws.column_dimensions['I'].width = 53
    384. ws.column_dimensions['J'].width = 53
    385. ws.column_dimensions['K'].width = 15
    386. ws.column_dimensions['L'].width = 11
    387. ws.column_dimensions['M'].width = 13
    388. ws.column_dimensions['N'].width = 13
    389. ws.column_dimensions['O'].width = 13
    390. ws.column_dimensions['P'].width = 16
    391. ws.column_dimensions['Q'].width = 13
    392. ws.column_dimensions['S'].width = 9
    393. ws.column_dimensions['T'].width = 9
    394. ws.column_dimensions['U'].width = 9
    395. ws.column_dimensions['V'].width = 9
    396. ws.column_dimensions['W'].width = 9
    397. ws.column_dimensions['X'].width = 9
    398. ws.column_dimensions['Y'].width = 11
    399.  
    400. ws['A3'] = '序号'
    401. ws['B3'] = '主机名'
    402. ws['C3'] = 'IP地址'
    403. ws['D3'] = '漏洞对应端口'
    404. ws['E3'] = '漏洞对应服务'
    405. ws['F3'] = '漏洞名称'
    406. ws['G3'] = '风险分类'
    407. ws['H3'] = '风险等级'
    408. ws['I3'] = '整改建议'
    409. ws['J3'] = '漏洞描述'
    410. ws['K3'] = '漏洞CVE编号'
    411. ws['L3'] = '漏洞对应协议'
    412. ws['M3'] = '是否已备案'
    413. ws['N3'] = '是否已整改'
    414. ws['O3'] = '%s核实是否已经整改' % company_ini
    415. ws['P3'] = '漏洞复核时间'
    416. ws['Q3'] = '备注'
    417. ws['S1'] = '高风险总数'
    418. ws['T1'] = '中风险总数'
    419. ws['U1'] = '修补高风险数'
    420. ws['V1'] = '修补中风险数'
    421. ws['W1'] = '高风险修补率'
    422. ws['X1'] = '中风险修补率'
    423. ws['Y1'] = '总修补率'
    424. ws['S2'].value = '=COUNTIF(H:H,"高")'
    425. ws['T2'].value = '=COUNTIF(H:H,"中")'
    426. ws['U2'].value = '=COUNTIFS(H:H,"高",O:O,"已完成整改")'
    427. ws['V2'].value = '=COUNTIFS(H:H,"中",O:O,"已完成整改")'
    428. ws['W2'].value = '=IF(S2=0,"无高风险漏洞",TEXT(U2/S2,"0.00%"))'
    429. ws['X2'].value = '=IF(T2=0,"无中风险漏洞",TEXT(V2/T2,"0.00%"))'
    430. ws['Y2'].value = '=TEXT((U2+V2)/(S2+T2),"0.00%")'
    431.  
    432. ws['A1'] = '高中风险漏洞整改情况跟踪表'
    433. ws.merge_cells('A1:Q1')
    434. ws['A2'] = '系统名称'
    435. ws.merge_cells('A2:B2')
    436. ws['C2'] = ''
    437. ws.merge_cells('C2:F2')
    438. ws['G2'] = '管理员'
    439. ws.merge_cells('G2:H2')
    440. ws['K2'] = '检查人员'
    441. ws['L2'] = '%s'% name_ini
    442. ws.merge_cells('L2:M2')
    443. ws['O2'] = '检查时间'
    444. ws['P2'] = '%s' % sheet_time
    445. ws.merge_cells('P2:Q2')
    446.  
    447. # 样式
    448. font = Font(size=10, name='宋体')
    449. thin = Side(border_style="thin")
    450. border = Border(left=thin, right=thin, top=thin, bottom=thin)
    451. # 对齐
    452. alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
    453.  
    454. #设置第三行的格式
    455. title_font = Font(size=12, bold=True, name='宋体', color= "ff0000")
    456. ws.row_dimensions[3].height = 45
    457. for title_style in ws['A3:L3']:
    458. for title_cell in title_style:
    459. title_cell.font = title_font
    460. title_cell.border = border
    461. title_cell.alignment = alignment
    462.  
    463. #设置第三行的格式
    464. title_end_font = Font(size=12, bold=True, name='宋体', color= "0000FF")
    465. ws.row_dimensions[3].height = 45
    466. for title_end_style in ws['M3:Q3']:
    467. for title_cell in title_end_style:
    468. title_cell.font = title_end_font
    469. title_cell.border = border
    470. title_cell.alignment = alignment
    471.  
    472. #设置第一行的格式
    473. one_font = Font(size=20, bold=True, name='宋体')
    474. ws.row_dimensions[1].height = 45
    475. for one_style in ws['A1:L1']:
    476. for one_cell in one_style:
    477. one_cell.font = one_font
    478. one_cell.border = border
    479. one_cell.alignment = alignment
    480. one_cell.fill = openpyxl.styles.PatternFill(fill_type='solid',fgColor="008000")
    481.  
    482. #设置第二行的格式
    483. two_font = Font(size=14, bold=True, name='宋体')
    484. ws.row_dimensions[2].height = 20
    485. for one_style in ws['A2:Q2']:
    486. for one_cell in one_style:
    487. one_cell.font = two_font
    488. one_cell.border = border
    489. one_cell.alignment = alignment
    490. one_cell.fill = openpyxl.styles.PatternFill(fill_type='solid',fgColor="008000")
    491.  
    492. #设置统计的格式
    493. count_font = Font(size=12, bold=True, name='宋体')
    494. for count_style in ws['S1:Y2']:
    495. for count_cell in count_style:
    496. count_cell.font = count_font
    497. count_cell.border = border
    498. count_cell.alignment = alignment
    499.  
    500. count_red = openpyxl.styles.PatternFill(fill_type='solid',fgColor="FF5353")
    501. count_yellow = openpyxl.styles.PatternFill(fill_type='solid',fgColor="FCCC2C")
    502. ws['S1'].fill = count_red
    503. ws['U1'].fill = count_red
    504. ws['W1'].fill = count_red
    505. ws['T1'].fill = count_yellow
    506. ws['V1'].fill = count_yellow
    507. ws['X1'].fill = count_yellow
    508. ws['Y1'].fill = openpyxl.styles.PatternFill(fill_type='solid',fgColor="008000")
    509.  
    510. vul_content = Vul_content(vul_re)
    511.  
    512. for all_vul_ip in vul_content.vul_ip_content:
    513. vul_list_content = re.findall(vul_re.vul_list_re,all_vul_ip,re.S|re.M)
    514. for all_vul_list in vul_list_content:
    515. for other in Other(vul_re,all_vul_list[1]).all_other:
    516. for danger in Danger(vul_re,other[3]).danger_coneent:
    517. vul_all_list.append([danger[1],all_vul_list[0],danger[2],danger[0].replace('low','低').replace('middle','中').replace('high','高'),other[0],other[1],other[2]])
    518.  
    519. for all_vul_detail in vul_content.vul_detail_content:
    520. vul_details_content = re.findall(vul_re.vul_details_re,all_vul_detail,re.S|re.M)
    521. for all_vul_details in vul_details_content:
    522. vul_detail = Solve(Solve_re(),all_vul_details)
    523. for solve,describe in zip(vul_detail.solve_plumb,vul_detail.describe_plumb):
    524. cve = vul_detail.cve_plumb
    525. if cve:
    526. pass
    527. else:
    528. cve = ['漏洞暂无CVE编号']
    529. vul_all_detail.append([describe[0],re.sub('\s{2,}','\n',html.unescape(re.sub('\s{2,}','',solve)).replace('<br/>','\n')),re.sub('\s{2,}','\n',html.unescape(re.sub('\s{2,}','',describe[1])).replace('<br/>','\n')),cve[0]])
    530.  
    531. for line_vul_list in vul_all_list:
    532. vul_list.put(line_vul_list)
    533.  
    534. i = 1
    535. while not vul_list.empty():
    536. wait_list = vul_list.get()
    537. for wait_detail in vul_all_detail:
    538. if wait_list[0] == wait_detail[0] and self.hight_status == True and wait_list[3] == '高':
    539. ws.row_dimensions[i+3].height = 25
    540. ws.append([i,'',wait_list[1],wait_list[4],wait_list[6],wait_list[2],'漏洞',wait_list[3],wait_detail[1].strip('\n'),wait_detail[2].strip('\n'),wait_detail[3],wait_list[5]])
    541. for row in ws['A%s:Q%s'%(i+3,i+3)]:
    542. for cell in row:
    543. cell.font = font
    544. cell.border = border
    545. cell.alignment = alignment
    546. i += 1
    547. break
    548.  
    549. if wait_list[0] == wait_detail[0] and self.middle_status == True and wait_list[3] == '中':
    550. ws.row_dimensions[i+3].height = 25
    551. ws.append([i,'',wait_list[1],wait_list[4],wait_list[6],wait_list[2],'漏洞',wait_list[3],wait_detail[1].strip('\n'),wait_detail[2].strip('\n'),wait_detail[3],wait_list[5]])
    552. for row in ws['A%s:Q%s'%(i+3,i+3)]:
    553. for cell in row:
    554. cell.font = font
    555. cell.border = border
    556. cell.alignment = alignment
    557. i += 1
    558. break
    559.  
    560. if wait_list[0] == wait_detail[0] and self.low_status == True and wait_list[3] == '低':
    561. ws.row_dimensions[i+3].height = 25
    562. ws.append([i,'',wait_list[1],wait_list[4],wait_list[6],wait_list[2],'漏洞',wait_list[3],wait_detail[1].strip('\n'),wait_detail[2].strip('\n'),wait_detail[3],wait_list[5]])
    563. for row in ws['A%s:Q%s'%(i+3,i+3)]:
    564. for cell in row:
    565. cell.font = font
    566. cell.border = border
    567. cell.alignment = alignment
    568. i += 1
    569. break
    570.  
    571. wb.save(folder_end+'/汇总-漏洞跟踪表/高中风险漏洞跟踪表--%s.xlsx' % sheet_name)
    572. del vul_all_list[:]
    573. del vul_all_detail[:]
    574. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    575. self.log_textEdit.insertPlainText('漏洞跟踪表导出完成,保存在 %s/汇总-漏洞跟踪表 目录下。\n'%folder_end)
    576. QtWidgets.QApplication.processEvents()
    577.  
    578. shutil.rmtree('temp')
    579. endtime = datetime.datetime.now()
    580. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    581. self.log_textEdit.insertPlainText('导出花时:%s秒...\n'%(endtime - starttime).seconds)
    582. QtWidgets.QApplication.processEvents()
    583. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    584. self.log_textEdit.insertPlainText('\n' + '*'*67 + '\n')
    585. QtWidgets.QApplication.processEvents()
    586.  
    587. if self.port_status:
    588. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    589. self.log_textEdit.insertPlainText('正在导出端口,请稍后!\n')
    590. QtWidgets.QApplication.processEvents()
    591. starttime = datetime.datetime.now()
    592. os.mkdir(folder_end+'/汇总-端口对应关系表')
    593. dirList = os.listdir(folder_start)
    594. for name in dirList:
    595. all_file_name = re.findall(Port_File_re().file_re,name)
    596. for file_name in all_file_name:
    597. uzip = zipfile.ZipFile(folder_start+'/'+file_name)
    598. i = 1
    599. wb = openpyxl.Workbook()
    600. ws = wb.active
    601.  
    602. ws.column_dimensions['A'].width = 16.5
    603. ws.column_dimensions['B'].width = 16
    604. ws.column_dimensions['C'].width = 20
    605. ws.column_dimensions['D'].width = 30
    606. ws.column_dimensions['E'].width = 25
    607. ws.column_dimensions['F'].width = 28
    608. ws.column_dimensions['G'].width = 42
    609. ws.column_dimensions['H'].width = 17
    610.  
    611. ws.title = '端口数据'
    612. ws['A1'] = '设备端口和服务信息表'
    613. ws.merge_cells('A1:H1')
    614. ws['A2'] = '收集时间'
    615. ws.merge_cells('A2:B2')
    616. ws.merge_cells('C2:D2')
    617. ws['E2'] = '所属系统'
    618. ws.merge_cells('F2:H2')
    619. ws['A3'] = '填表人'
    620. ws['C3'] = name_ini
    621. ws.merge_cells('A3:B3')
    622. ws.merge_cells('C3:D3')
    623. ws['E3'] = '系统责任人'
    624. ws.merge_cells('F3:H3')
    625. ws['A4'] = 'IP地址'
    626. ws['B4'] = '端口'
    627. ws['C4'] = '协议'
    628. ws['D4'] = '服务'
    629. ws['E4'] = '状态'
    630. ws['F4'] = '访问权限开放范围'
    631. ws['G4'] = '应用说明'
    632. ws['H4'] = '备注'
    633.  
    634. # 样式
    635. font = Font(size=12, name='宋体')
    636. thin = Side(border_style="thin")
    637. border = Border(left=thin, right=thin, top=thin, bottom=thin)
    638. # 对齐
    639. alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
    640. for excel_style in ws['A2:H4']:
    641. for excel_cell in excel_style:
    642. excel_cell.font = font
    643. excel_cell.border = border
    644. excel_cell.alignment = alignment
    645. #设置第一行的格式
    646. one_font = Font(size=12, bold=True, name='宋体')
    647. for one_style in ws['A1:H1']:
    648. for one_cell in one_style:
    649. one_cell.font = one_font
    650. one_cell.border = border
    651. one_cell.alignment = alignment
    652.  
    653. for uzip_content in uzip.namelist():
    654. all_uzip_content = re.findall(Port_File_re().uzip_re,uzip_content)
    655. for all_uzip in all_uzip_content:
    656. htmlcont_zip = uzip.open(all_uzip).read().decode('utf8')
    657. vul_title = re.findall(Port_File_re().all_title_re,htmlcont_zip,re.S|re.M)
    658. for title_content in vul_title:
    659. pass
    660.  
    661. vul_host = re.findall(Port_File_re().host_re,htmlcont_zip,re.S|re.M)
    662. for host_content in vul_host:
    663. for vul_port in re.findall(Port_File_re().port_re,host_content[2],re.S|re.M):
    664. ws['C2'] = '%s' % host_content[1]
    665. ws.append([host_content[0],vul_port[0].replace(' ','').strip('\n'),vul_port[1].replace(' ','').strip('\n'),vul_port[2].replace(' ','').strip('\n'),vul_port[3].replace(' ','').strip('\n')])
    666. for row in ws['A%s:H%s'%(i+4,i+4)]:
    667. for cell in row:
    668. cell.font = font
    669. cell.border = border
    670. cell.alignment = alignment
    671. i += 1
    672.  
    673. wb.save(folder_end+'/汇总-端口对应关系表/端口服务对应关系表--%s.xlsx' % title_content)
    674. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    675. self.log_textEdit.insertPlainText('导出 %s'%title_content+' 完成!\n')
    676. QtWidgets.QApplication.processEvents()
    677.  
    678. endtime = datetime.datetime.now()
    679. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    680. self.log_textEdit.insertPlainText('所有端口导出完成,保存在 %s/汇总-端口对应关系表 目录下。\n'%folder_end)
    681. QtWidgets.QApplication.processEvents()
    682. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    683. self.log_textEdit.insertPlainText('导出花时:%s秒...\n'%(endtime - starttime).seconds)
    684. QtWidgets.QApplication.processEvents()
    685. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    686. self.log_textEdit.insertPlainText('\n' + '*'*67 + '\n')
    687. QtWidgets.QApplication.processEvents()
    688.  
    689. if self.web_status:
    690. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    691. self.log_textEdit.insertPlainText('正在WEB网站,请稍后!\n')
    692. QtWidgets.QApplication.processEvents()
    693. starttime = datetime.datetime.now()
    694. os.mkdir(folder_end+'/汇总-WEB网站')
    695. dirList = os.listdir(folder_start)
    696. for name in dirList:
    697. all_file_name = re.findall(Port_File_re().file_re,name)
    698. for file_name in all_file_name:
    699. uzip = zipfile.ZipFile(folder_start+'/'+file_name)
    700. x = 1
    701.  
    702. web = openpyxl.Workbook()
    703. wes = web.active
    704. wes.title = 'WEB网站'
    705.  
    706. wes.column_dimensions['A'].width = 16.5
    707. wes.column_dimensions['B'].width = 16
    708. wes.column_dimensions['C'].width = 20
    709. wes.column_dimensions['D'].width = 30
    710. wes.column_dimensions['E'].width = 25
    711. wes.column_dimensions['F'].width = 45
    712.  
    713. wes['A1'] = 'IP地址'
    714. wes['B1'] = '端口'
    715. wes['C1'] = '协议'
    716. wes['D1'] = '服务'
    717. wes['E1'] = '状态'
    718. wes['F1'] = 'WEB网站信息'
    719.  
    720. # 样式
    721. font = Font(size=12, name='宋体')
    722. thin = Side(border_style="thin")
    723. border = Border(left=thin, right=thin, top=thin, bottom=thin)
    724. # 对齐
    725. alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
    726. for excel_style in wes['A1:F1']:
    727. for excel_cell in excel_style:
    728. excel_cell.font = font
    729. excel_cell.border = border
    730. excel_cell.alignment = alignment
    731.  
    732. for uzip_content in uzip.namelist():
    733. all_uzip_content = re.findall(Port_File_re().uzip_re,uzip_content)
    734. for all_uzip in all_uzip_content:
    735. htmlcont_zip = uzip.open(all_uzip).read().decode('utf8')
    736. vul_title = re.findall(Port_File_re().all_title_re,htmlcont_zip,re.S|re.M)
    737. for title_content in vul_title:
    738. pass
    739.  
    740. vul_host = re.findall(Port_File_re().host_re,htmlcont_zip,re.S|re.M)
    741. for host_content in vul_host:
    742. for vul_port in re.findall(Port_File_re().port_re,host_content[2],re.S|re.M):
    743. vul_web = re.findall(Port_File_re().http_re,vul_port[2].replace(' ','').strip('\n'),re.S|re.M)
    744. if vul_web:
    745. wes.append([host_content[0],vul_port[0].replace(' ','').strip('\n'),vul_port[1].replace(' ','').strip('\n'),vul_port[2].replace(' ','').strip('\n'),vul_port[3].replace(' ','').strip('\n'),'http://'+ host_content[0] + ':' + vul_port[0].replace(' ','').strip('\n')])
    746. for row in wes['A%s:E%s'%(x+1,x+1)]:
    747. for cell in row:
    748. cell.font = font
    749. cell.border = border
    750. cell.alignment = alignment
    751. wes['F%s' % (x+1)].font = font
    752. wes['F%s' % (x+1)].border = border
    753. x += 1
    754. vul_web = re.findall(Port_File_re().https_re,vul_port[2].replace(' ','').strip('\n'),re.S|re.M)
    755. if vul_web:
    756. wes.append([host_content[0],vul_port[0].replace(' ','').strip('\n'),vul_port[1].replace(' ','').strip('\n'),vul_port[2].replace(' ','').strip('\n'),vul_port[3].replace(' ','').strip('\n'),'https://'+ host_content[0] + ':' + vul_port[0].replace(' ','').strip('\n')])
    757. for row in wes['A%s:E%s'%(x+1,x+1)]:
    758. for cell in row:
    759. cell.font = font
    760. cell.border = border
    761. cell.alignment = alignment
    762. wes['F%s' % (x+1)].font = font
    763. wes['F%s' % (x+1)].border = border
    764. x += 1
    765. vul_web = re.findall(Port_File_re().www_re,vul_port[2].replace(' ','').strip('\n'),re.S|re.M)
    766. if vul_web:
    767. wes.append([host_content[0],vul_port[0].replace(' ','').strip('\n'),vul_port[1].replace(' ','').strip('\n'),vul_port[2].replace(' ','').strip('\n'),vul_port[3].replace(' ','').strip('\n'),'http://'+ host_content[0] + ':' + vul_port[0].replace(' ','').strip('\n')])
    768. for row in wes['A%s:E%s'%(x+1,x+1)]:
    769. for cell in row:
    770. cell.font = font
    771. cell.border = border
    772. cell.alignment = alignment
    773. wes['F%s' % (x+1)].font = font
    774. wes['F%s' % (x+1)].border = border
    775. x += 1
    776.  
    777. web.save(folder_end+'/汇总-WEB网站/WEB网站--%s.xlsx' % title_content)
    778. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    779. self.log_textEdit.insertPlainText('导出 %s'%title_content+' 完成!\n')
    780. QtWidgets.QApplication.processEvents()
    781. endtime = datetime.datetime.now()
    782. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    783. self.log_textEdit.insertPlainText('所有WEB网站导出导出完成,保存在 %s/汇总-WEB网站 目录下。\n'%folder_end)
    784. QtWidgets.QApplication.processEvents()
    785. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    786. self.log_textEdit.insertPlainText('导出花时:%s秒...\n'%(endtime - starttime).seconds)
    787. QtWidgets.QApplication.processEvents()
    788. self.log_textEdit.moveCursor(QtGui.QTextCursor.End)
    789. self.log_textEdit.insertPlainText('*'*67 + '\n')
    790. QtWidgets.QApplication.processEvents()
    791.  
    792. if __name__ == '__main__':
    793. app = QtWidgets.QApplication(sys.argv)
    794. MainWindow = QtWidgets.QMainWindow()
    795. ui = Ui_MainWindow()
    796. ui.setupUi(MainWindow)
    797. MainWindow.show()
    798. sys.exit(app.exec_())

      

python打造漏洞数据导出工具的更多相关文章

  1. 用Python编写博客导出工具

    用Python编写博客导出工具 罗朝辉 (http://kesalin.github.io/) CC 许可,转载请注明出处   写在前面的话 我在 github 上用 octopress 搭建了个人博 ...

  2. oracle数据导出工具sqluldr2

    oracle数据导出工具sqluldr2可以将数据以csv.txt等格式导出,适用于大批量数据的导出,导出速度非常快.导出后可以使用oracle loader工具将数据导入.下载完sqluldr2,工 ...

  3. DB数据导出工具分享

    一个根据数据库链接字符串,sql语句 即可将结果集导出到Excel的工具 分享,支持sqlserver,mysql. 前因 一个月前朋友找到我,让我帮忙做一个根据sql导出查询结果到Excel的工具( ...

  4. Mongodb数据导出工具mongoexport和导入工具mongoimport介绍

    一.导出工具mongoexport Mongodb中的mongoexport工具可以把一个collection导出成JSON格式或CSV格式的文件.可以通过参数指定导出的数据项,也可以根据指定的条件导 ...

  5. python测试框架&&数据生成&&工具最全资源汇总

    xUnit frameworks 单元测试框架frameworks 框架unittest - python自带的单元测试库,开箱即用unittest2 - 加强版的单元测试框架,适用于Python 2 ...

  6. Mongodb数据导出工具mongoexport和导入工具mongoimport介绍(转)

    原文地址:http://chenzhou123520.iteye.com/blog/1641319 一.导出工具mongoexport Mongodb中的mongoexport工具可以把一个colle ...

  7. 很多人都没用过的轻量级Oracle数据库数据导出工具SQLLDR2——性能超赞

    SQLLDR2 介绍 每周发表一篇数据库或大数据相关的帖子,敬请关注 1. 工具介绍 Sqluldr2(SQL * UnLoader 第二版)是灵活与强大的 Oracle 文本导出程序,已被大众使 用 ...

  8. Mongodb数据导出工具mongoexport和导入工具mongoimport使用

    如图所示,两个工具位于mongodb安装目录的bin目录下 下面介绍一下两者的使用方法: 一.导出工具mongoexport Mongodb中的mongoexport工具可以把一个collection ...

  9. MySQL--mysqldump(数据导出工具)

    mysqldump 客户端工具用来备份数据库或在不同数据库之间进行数据迁移.备份内容包含创建表或装载表的 SQL 语句.mysqldump 目前是 MySQL 中最常用的备份工具. 有 3 种方式来调 ...

随机推荐

  1. [ARM-Linux开发]linux 里 /etc/passwd 、/etc/shadow和/etc/group 文件内容解释

    linux 里 /etc/passwd ./etc/shadow和/etc/group 文件内容解释 一./etc/passwd 是用户数据库,其中的域给出了用户名.加密口令和用户的其他信息 /etc ...

  2. 使用objcopy实现将文件编译进执行程序

    一.简介  工作中可能遇到将一个文件编译进执行程序的需求,例如bin文件.jpg文件等等.实现的方法可以使用脚本来将文件内容写入一个新的C源文件数组,达成编译进程序的目的. 现在介绍一种简单.快捷的方 ...

  3. 【Linux】守护进程的定义,作用,创建流程

    本文内容: 1.守护进程的定义 2.守护进程的作用 3.守护进程的创建过程 一.守护进程的定义 1.守护进程是脱离于终端并且在后台运行的进程 2.守护进程脱离终端是为了避免在执行过程中的信息在任何终端 ...

  4. IDEA 自定义代码模板

    IDEA 自定义代码模板操作步骤:

  5. [转帖]Linux教程(20)- Linux中的Shell变量

    Linux教程(20)- Linux中的Shell变量 2018-08-24 11:30:16 钱婷婷 阅读数 37更多 分类专栏: Linux教程与操作 Linux教程与使用   版权声明:本文为博 ...

  6. [Oracle] - 查看数据库中每个表占用空间大小,及进行表压缩

    查询用户创建的表 select * from user_tab_comments; -- 查询本用户的表,视图等. select * from user_col_comments; -- 查询本用户的 ...

  7. Python开发之virtualenv和virtualenvwrapper详解

    在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题: 亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾难. 此时,我们需要对于不同的工程使用 ...

  8. flink linux安装 单机版

    1.下载二进制的Flink,根据你喜欢的Hadoop/Scala版本选择对应的Flink版本. https://flink.apache.org/downloads.html2.选择存放目录 解压 f ...

  9. IP核——FIFO

    一.Quartus 1.打开Quartus ii,点击Tools---MegaWizard Plug-In Manager 2.弹出创建页面,选择Creat a new custom megafunc ...

  10. 全面学习 Python 包:包的构建与分发

    首发于公众号:Python编程时光 1. 为什么需要对项目分发打包? 平常我们习惯了使用 pip 来安装一些第三方模块,这个安装过程之所以简单,是因为模块开发者为我们默默地为我们做了所有繁杂的工作,而 ...