import csv import os import re from datetime import datetime import mysql.connector import requests from bs4 import BeautifulSoup from common import upload_to_minio, save_to_db_import_record, db_config, get_md5, fetch_db_import_record # 设置下载目录 download_dir = 'downloaded_files/ESA' os.makedirs(download_dir, exist_ok=True) # 获取网页内容 url = 'https://esarad.esa.int/' def scrape(): esa_connection = mysql.connector.connect(**db_config) try: response = requests.get(url) # 确保请求成功 if response.status_code == 200: # 解析网页内容 soup = BeautifulSoup(response.content, 'html.parser') # 找到所有表格 tables = soup.find_all('table') # 提取第一个表格的内容 tab_content = tables[0].find_all('tr')[2:] tab_content.reverse() for row in tab_content: # 跳过标题行 cells = row.find_all(['td', 'th']) table_id = get_md5('ESA-' + cells[0].get_text(strip=True)) # count = fetch_db_import_record(esa_connection, (table_id,)) # if count > 0: # continue folder_name = table_id # cells[1].get_text(strip=True) # 第2列 file_id = cells[0].get_text(strip=True) # 第1列 download_url = f'https://esarad.esa.int/?id={file_id}&handler=DownloadDb' # 创建文件夹 folder_path = os.path.join(download_dir, folder_name) os.makedirs(folder_path, exist_ok=True) # 下载文件并获取文件名 file_response = requests.get(download_url) if file_response and file_response.status_code == 200: # 从响应头获取文件名 content_disposition = file_response.headers.get('Content-Disposition') filename = '' if content_disposition: match = re.search(r'filename="([^"]+)"', content_disposition) if match: filename = match.group(1) if not filename: # 如果没有找到,则使用默认文件名 filename = f'{file_id}.pdf' file_path = os.path.join(folder_path, filename) if not os.path.exists(file_path): with open(file_path, 'wb') as f: f.write(file_response.content) print(f'ESA Downloaded: {file_path}') else: print(f'file exist: {file_path}') # 创建 CSV 文件 csv_file_path = os.path.join(folder_path, 'data.csv') with open(csv_file_path, 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile) # 写入标题行 writer.writerow([ '序号', '试验对象类型', '试验开始日期', '试验结束日期', '试验对象名称', '试验对象型号', '试验对象数量', '试验性质', '试验目的', '装置名称', '数据提供单位', '试验委托单位', '失效判据', '失效数量', '试验结果描述', '成果', '来源项目名称', '来源项目类型', '分类', '元器件名称', '元器件型号', '元器件批号', '生产单位', '是否国产', '元器件成熟度', '晶圆材料', '晶圆批号', '封装材料', '封装技术', '是否倒装', '制造工艺', '工艺特征尺寸', '工艺平台', '工艺代号', '工艺版本', '质量等级', '加固措施', '工作原理', '供货能力', '应用经历', '规范手册', '器件图片', '电子系统分类', '电子系统名称', '电子系统型号', '生产单位', '电子系统功能', '电子系统加固措施', '电子系统图片', '材料名称', '材料型号', '材料组分', '材料用途', '材料生产单位', '材料物理结构', '材料使用经历', '辐照试验大纲', '大纲审核专家类别', '辐照试验所依据的标准规范', '试验步骤(过程)描述', '辐照过程是否加电', '直流偏置条件描述', '交流偏置条件描述', '时钟频率', '测试图形', '其他偏置条件', '辐照偏置原理图', '测试方式', '测试原理图', '试验用仪器名称', '试验用仪器型号', '试验用仪器生产厂家', '试验用仪器检定证书', '试验用软件名称', '试验用软件开发单位', '试验用软件版本号', '试验现场照片', '测试人员姓名', '测试人员单位', '测试人员电话', '装置运行人员', '第三方人员', '第三方人员单位', '第三方人员电话', '其他需要说明的事项', '是否采用铅铝屏蔽', '剂量率', '总剂量', '剂量等效材料', '试验对象编号', '测试参数名称', '测试参数单位', '测试参数结果', '是否为加速试验后数据', '是否为退火数据', '退火温度', '退火时间', '原始数据', '数据处理方法', '其他需要说明的事项' ]) # 写入数据行并保存到数据库 data_row = [ file_id, # 序号 '', # 试验对象类型(可以根据需要填充) cells[11].get_text(strip=True), # 试验开始日期(第12列) '', # 试验结束日期(可以根据需要填充) '', # 试验对象名称(可以根据需要填充) cells[1].get_text(strip=True), # 试验对象型号(第2列) '', # 试验对象数量(可以根据需要填充) cells[5].get_text(strip=True), # 试验性质(第6列) '', # 试验目的(可以根据需要填充) '', # 装置名称(可以根据需要填充) '', # 数据提供单位(可以根据需要填充) '', # 试验委托单位(可以根据需要填充) '', # 失效判据(可以根据需要填充) '', # 失效数量(可以根据需要填充) '', # 试验结果描述(可以根据需要填充) '', # 成果(可以根据需要填充) '', # 来源项目名称(可以根据需要填充) '', # 来源项目类型(可以根据需要填充) '', # 分类(可以根据需要填充) '', # 元器件名称(可以根据需要填充) '', # 元器件型号(可以根据需要填充) '', # 元器件批号(可以根据需要填充) cells[3].get_text(strip=True), # 生产单位(第4列) '', # 是否国产(可以根据需要填充) '', # 元器件成熟度(可以根据需要填充) '', # 晶圆材料(可以根据需要填充) '', # 晶圆批号(可以根据需要填充) '', # 封装材料(可以根据需要填充) '', # 封装技术(可以根据需要填充) '', # 是否倒装(可以根据需要填充) '', # 制造工艺(可以根据需要填充) '', # 工艺特征尺寸(可以根据需要填充) '', # 工艺平台(可以根据需要填充) '', # 工艺代号(可以根据需要填充) '', # 工艺版本(可以根据需要填充) '', # 质量等级(可以根据需要填充) '', # 加固措施(可以根据需要填充) '', # 工作原理(可以根据需要填充) '', # 供货能力(可以根据需要填充) '', # 应用经历(可以根据需要填充) '', # 规范手册(可以根据需要填充) '', # 器件图片(可以根据需要填充) '', # 电子系统分类(可以根据需要填充) '', # 电子系统名称(可以根据需要填充) '', # 电子系统型号(可以根据需要填充) '', # 生产单位(可以根据需要填充) '', # 电子系统功能(可以根据需要填充) '', # 电子系统加固措施(可以根据需要填充) '', # 电子系统图片(可以根据需要填充) '', # 材料名称(可以根据需要填充) '', # 材料型号(可以根据需要填充) '', # 材料组分(可以根据需要填充) '', # 材料用途(可以根据需要填充) '', # 材料生产单位(可以根据需要填充) '', # 材料物理结构(可以根据需要填充) '', # 材料使用经历(可以根据需要填充) '', # 辐照试验大纲(可以根据需要填充) '', # 大纲审核专家类别(可以根据需要填充) '', # 辐照试验所依据的标准规范(可以根据需要填充) '', # 试验步骤(过程)描述(可以根据需要填充) '', # 辐照过程是否加电(可以根据需要填充) '', # 直流偏置条件描述(可以根据需要填充) '', # 交流偏置条件描述(可以根据需要填充) '', # 时钟频率(可以根据需要填充) '', # 测试图形(可以根据需要填充) '', # 其他偏置条件(可以根据需要填充) '', # 辐照偏置原理图(可以根据需要填充) '', # 测试方式(可以根据需要填充) '', # 测试原理图(可以根据需要填充) '', # 试验用仪器名称(可以根据需要填充) '', # 试验用仪器型号(可以根据需要填充) '', # 试验用仪器生产厂家(可以根据需要填充) '', # 试验用仪器检定证书(可以根据需要填充) '', # 试验用软件名称(可以根据需要填充) '', # 试验用软件开发单位(可以根据需要填充) '', # 试验用软件版本号(可以根据需要填充) '', # 试验现场照片(可以根据需要填充) '', # 测试人员姓名(可以根据需要填充) '', # 测试人员单位(可以根据需要填充) '', # 测试人员电话(可以根据需要填充) '', # 装置运行人员(可以根据需要填充) '', # 第三方人员(可以根据需要填充) '', # 第三方人员单位(可以根据需要填充) '', # 第三方人员电话(可以根据需要填充) '', # 其他需要说明的事项(可以根据需要填充) '', # 是否采用铅铝屏蔽(可以根据需要填充) '', # 剂量率(可以根据需要填充) '', # 总剂量(可以根据需要填充) '', # 剂量等效材料(可以根据需要填充) '', # 试验对象编号(可以根据需要填充) '', # 测试参数名称(可以根据需要填充) '', # 测试参数单位(可以根据需要填充) '', # 测试参数结果(可以根据需要填充) '', # 是否为加速试验后数据(可以根据需要填充) '', # 是否为退火数据(可以根据需要填充) '', # 退火温度(可以根据需要填充) '', # 退火时间(可以根据需要填充) '', # 原始数据(可以根据需要填充) '', # 数据处理方法(可以根据需要填充) '' # 其他需要说明的事项(可以根据需要填充) ] writer.writerow(data_row) # (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `sys_org_code`, `device_type`, # `device_name`, `device_mode`, `device_function`, `device_batch`, `manufacturer`, `experiment_date`, `data_source`, `experiment_user`, `total_count`, `file_list`) print(f'CSV created and data saved to MySQL: {csv_file_path}') else: print(f'Failed to download: {download_url}') upload_ids = upload_to_minio(esa_connection, folder_path, 'ESA') origin_data = ','.join([c.get_text(strip=True) for c in cells]) data_db = [table_id, 'Crawler', datetime.now(), None, None, None, cells[5].get_text(strip=True), cells[1].get_text(strip=True), cells[1].get_text(strip=True), cells[8].get_text(strip=True), cells[7].get_text(strip=True), cells[2].get_text(strip=True), cells[11].get_text(strip=True), 'ESA', None, None, str(upload_ids), origin_data ] save_to_db_import_record(esa_connection, data_db) else: print(f'Error: {response.status_code}') except Exception as e: print(e) finally: # 关闭游标和连接 esa_connection.close()