浏览代码

睿姿得数据对接

gmy 6 月之前
父节点
当前提交
92f9b27d62
共有 2 个文件被更改,包括 178 次插入129 次删除
  1. 168 129
      services/ruizide/data_processor.go
  2. 10 0
      utils/date_util.go

+ 168 - 129
services/ruizide/data_processor.go

@@ -4,6 +4,9 @@ import (
 	"context"
 	"context"
 	"eta/eta_data_analysis/utils"
 	"eta/eta_data_analysis/utils"
 	"fmt"
 	"fmt"
+	"github.com/chromedp/cdproto/cdp"
+	"github.com/xuri/excelize/v2"
+	"io"
 	"log"
 	"log"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
@@ -13,10 +16,10 @@ import (
 	"github.com/chromedp/chromedp"
 	"github.com/chromedp/chromedp"
 )
 )
 
 
-const downloadDir = "./downloads"
-
 // 定义选择器
 // 定义选择器
 var (
 var (
+	downloadDir  = "D:\\download"
+	defaultDir   = "C:\\Users\\Guo Mengyuan\\Downloads"
 	rzdLoginPath = "https://clients.rystadenergy.com/clients/"
 	rzdLoginPath = "https://clients.rystadenergy.com/clients/"
 
 
 	clientSearchLink               = `div.d-none.d-lg-flex.flex-grow-1 a[href="/clients/search/"]`
 	clientSearchLink               = `div.d-none.d-lg-flex.flex-grow-1 a[href="/clients/search/"]`
@@ -39,57 +42,6 @@ var (
 	scenarioTabSelector        = tabSelectorBase + `:contains("Scenario")`
 	scenarioTabSelector        = tabSelectorBase + `:contains("Scenario")`
 )
 )
 
 
-// 函数用于设置查询时间范围
-func setQueryTime(ctx context.Context, year string) error {
-	// 在这里可以直接操作 iframe 中的元素
-	var inputCount int
-	if err := chromedp.Run(ctx,
-		chromedp.WaitVisible(`#reportContainer`, chromedp.ByQuery),
-		// 获取 reportContainer 下的第一个 iframe 的内容文档
-		chromedp.ActionFunc(func(ctx context.Context) error {
-			// 获取 iframe 的内容文档
-			var iframeSrc string
-			// 获取 iframe 的 src
-			err := chromedp.Evaluate(`document.querySelector('#reportContainer iframe').src`, &iframeSrc).Do(ctx)
-			if err != nil {
-				return fmt.Errorf("获取 iframe ID 或 src 失败: %v", err)
-			}
-			// 在 iframe 的上下文中操作
-
-			return chromedp.Run(ctx,
-				// 等待 iframe 可见
-				chromedp.WaitVisible(`iframe[src="`+iframeSrc+`"]`, chromedp.ByQuery),
-				chromedp.Sleep(5*time.Second),
-				// 在 iframe 中执行操作
-				chromedp.ActionFunc(func(ctx context.Context) error {
-					// 选择器
-					selector := `div.landingContainer`
-					// 获取元素数量
-					if err := chromedp.Evaluate(`document.querySelectorAll("`+selector+`").length`, &inputCount).Do(ctx); err != nil {
-						return fmt.Errorf("检查输入框失败: %v", err)
-					}
-
-					if inputCount == 0 {
-						return fmt.Errorf("没有找到匹配的 div.landingContainer 标签")
-					}
-
-					return nil
-				}),
-			)
-		}),
-	); err != nil {
-		log.Fatal(err)
-	}
-
-	/*return chromedp.Run(ctx,
-		chromedp.Sleep(3*time.Second),
-		chromedp.WaitVisible(dateSlicerInputSelector, chromedp.ByQuery),
-		chromedp.SetValue(dateSlicerInputSelector, year, chromedp.ByQuery),
-		chromedp.SendKeys(dateSlicerInputSelector, "\n"), // 回车查询
-	)*/
-	return nil
-}
-
 // 函数用于点击下载按钮
 // 函数用于点击下载按钮
 func clickDownload(ctx context.Context) error {
 func clickDownload(ctx context.Context) error {
 	return chromedp.Run(ctx, chromedp.Click(downloadButtonSelector, chromedp.ByQuery))
 	return chromedp.Run(ctx, chromedp.Click(downloadButtonSelector, chromedp.ByQuery))
@@ -105,11 +57,41 @@ func downloadData(ctx context.Context) error {
 		chromedp.Click(clientSearchLink, chromedp.ByQuery),
 		chromedp.Click(clientSearchLink, chromedp.ByQuery),
 		chromedp.WaitVisible(`input[class="ais-SearchBox-input rounded border py-2 px-3 shadow-sm font-size-14 w-100"]`, chromedp.ByQuery),
 		chromedp.WaitVisible(`input[class="ais-SearchBox-input rounded border py-2 px-3 shadow-sm font-size-14 w-100"]`, chromedp.ByQuery),
 		chromedp.SetValue(`input[class="ais-SearchBox-input rounded border py-2 px-3 shadow-sm font-size-14 w-100"]`, "oil demand signals weekly report", chromedp.ByQuery),
 		chromedp.SetValue(`input[class="ais-SearchBox-input rounded border py-2 px-3 shadow-sm font-size-14 w-100"]`, "oil demand signals weekly report", chromedp.ByQuery),
-		chromedp.Click(`div.ais-InfiniteHits img[src="/Static/img/icons/xls.png"]`, chromedp.ByQuery),
+		//chromedp.Click(`div.ais-InfiniteHits li a:has(img[src="/Static/img/icons/xls.png"])`, chromedp.ByQuery),
 	); err != nil {
 	); err != nil {
 		return fmt.Errorf("下载 Analytics Library 数据错误: %v", err)
 		return fmt.Errorf("下载 Analytics Library 数据错误: %v", err)
 	}
 	}
 
 
+	xpath := `//div[@id='search-page-hits']//li//a[.//div//span[@class='align-middle' and text()='Data']]`
+	var inputCount int
+	var nodes []*cdp.Node // 使用 *cdp.Node
+	if err := chromedp.Run(ctx,
+		chromedp.ActionFunc(func(ctx context.Context) error {
+
+			// 获取匹配的节点
+			if err := chromedp.Nodes(xpath, &nodes, chromedp.BySearch).Do(ctx); err != nil {
+				return fmt.Errorf("检查节点失败: %v", err)
+			}
+
+			// 获取节点数量
+			inputCount = len(nodes)
+			fmt.Printf("找到 %d 个匹配的元素\n", inputCount)
+
+			if inputCount > 0 {
+				// 点击第一个节点
+				return chromedp.MouseClickNode(nodes[0]).Do(ctx) // 使用 []cdp.NodeID
+			}
+			return nil
+		}),
+		chromedp.Sleep(10*time.Second),
+	); err != nil {
+		return fmt.Errorf("下载 Analytics Library 数据错误: %v", err)
+	}
+	// 解析文件移动到目标目录
+	if err := waitAndRenameDownloadedFile("Oil_Demand_Signals_Weekly_Report_"+utils.GetCurrentYearMonth()+".xlsx", downloadDir); err != nil {
+		return err
+	}
+
 	// Cube Dashboards: Supply Revision Analysis
 	// Cube Dashboards: Supply Revision Analysis
 	if err := chromedp.Run(ctx,
 	if err := chromedp.Run(ctx,
 		chromedp.WaitVisible(`div.d-none.d-lg-flex.flex-grow-1`, chromedp.ByQuery),
 		chromedp.WaitVisible(`div.d-none.d-lg-flex.flex-grow-1`, chromedp.ByQuery),
@@ -141,21 +123,13 @@ func downloadData(ctx context.Context) error {
 	); err != nil {
 	); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := setQueryTime(ctx, "2020"); err != nil {
-		return err
-	}
 	if err := clickDownload(ctx); err != nil {
 	if err := clickDownload(ctx); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := waitAndRenameDownloadedFile("Supply_Revision_Analysis_2020.xlsx"); err != nil {
+	if err := waitAndRenameDownloadedFile("Supply_Revision_Analysis_2020.xlsx", downloadDir); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	// Oil Demand Analysis
-	if err := downloadOilDemandAnalysis(ctx); err != nil {
-		return fmt.Errorf("下载 Oil Demand Analysis 错误: %v", err)
-	}
-
 	// Oil Supply Analysis
 	// Oil Supply Analysis
 	if err := chromedp.Run(ctx,
 	if err := chromedp.Run(ctx,
 		chromedp.Click(`a[href="/clients/subscription/"]`, chromedp.ByQuery),
 		chromedp.Click(`a[href="/clients/subscription/"]`, chromedp.ByQuery),
@@ -163,58 +137,10 @@ func downloadData(ctx context.Context) error {
 	); err != nil {
 	); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := setQueryTime(ctx, "2010"); err != nil {
-		return err
-	}
 	if err := clickDownload(ctx); err != nil {
 	if err := clickDownload(ctx); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := waitAndRenameDownloadedFile("Oil_Supply_Analysis_2010.xlsx"); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// 下载 Oil Demand Analysis 的所有标签数据
-func downloadOilDemandAnalysis(ctx context.Context) error {
-	// 下载 "Continent" 标签的数据
-	if err := downloadOilDemandByTab(ctx, continentTabSelector, "2015", "Oil_Demand_Continent_2015.xlsx"); err != nil {
-		return err
-	}
-
-	// 下载 "Region" 标签的数据
-	if err := downloadOilDemandByTab(ctx, regionTabSelector, "2015", "Oil_Demand_Region_2015.xlsx"); err != nil {
-		return err
-	}
-
-	// 下载 "Country" 标签的数据
-	if err := downloadOilDemandByTab(ctx, countryTabSelector, "2015", "Oil_Demand_Country_2015.xlsx"); err != nil {
-		return err
-	}
-
-	// 下载 "Product_Category" 标签的数据
-	if err := downloadOilDemandByTab(ctx, productCategoryTabSelector, "2015", "Oil_Demand_Product_Category_2015.xlsx"); err != nil {
-		return err
-	}
-
-	// 下载 "Product_Detail" 标签的数据
-	if err := downloadOilDemandByTab(ctx, productDetailTabSelector, "2015", "Oil_Demand_Product_Detail_2015.xlsx"); err != nil {
-		return err
-	}
-
-	// 下载 "Sector_Category" 标签的数据
-	if err := downloadOilDemandByTab(ctx, sectorCategoryTabSelector, "2015", "Oil_Demand_Sector_Category_2015.xlsx"); err != nil {
-		return err
-	}
-
-	// 下载 "Sector_Detail" 标签的数据
-	if err := downloadOilDemandByTab(ctx, sectorDetailTabSelector, "2015", "Oil_Demand_Sector_Detail_2015.xlsx"); err != nil {
-		return err
-	}
-
-	// 下载 "Scenario" 标签的数据
-	if err := downloadOilDemandByTab(ctx, scenarioTabSelector, "2015", "Oil_Demand_Scenario_2015.xlsx"); err != nil {
+	if err := waitAndRenameDownloadedFile("Oil_Supply_Analysis_2010.xlsx", downloadDir); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -237,11 +163,6 @@ func downloadOilDemandByTab(ctx context.Context, tabSelector string, year string
 				return fmt.Errorf("等待页面加载失败: %v", err)
 				return fmt.Errorf("等待页面加载失败: %v", err)
 			}
 			}
 
 
-			// 设置时间范围
-			if err := setQueryTime(ctx, year); err != nil {
-				return fmt.Errorf("设置查询时间失败: %v", err)
-			}
-
 			// 点击下载按钮
 			// 点击下载按钮
 			if err := clickDownload(ctx); err != nil {
 			if err := clickDownload(ctx); err != nil {
 				return fmt.Errorf("点击下载按钮失败: %v", err)
 				return fmt.Errorf("点击下载按钮失败: %v", err)
@@ -253,7 +174,7 @@ func downloadOilDemandByTab(ctx context.Context, tabSelector string, year string
 	}
 	}
 
 
 	// 下载完成后,重命名文件
 	// 下载完成后,重命名文件
-	if err := waitAndRenameDownloadedFile(fileName); err != nil {
+	if err := waitAndRenameDownloadedFile(fileName, downloadDir); err != nil {
 		return fmt.Errorf("重命名文件失败: %v", err)
 		return fmt.Errorf("重命名文件失败: %v", err)
 	}
 	}
 
 
@@ -261,30 +182,81 @@ func downloadOilDemandByTab(ctx context.Context, tabSelector string, year string
 }
 }
 
 
 // 等待下载文件并重命名
 // 等待下载文件并重命名
-func waitAndRenameDownloadedFile(newFileName string) error {
+func waitAndRenameDownloadedFile(newFileName, targetDir string) error {
 	// 等待一段时间以确保文件下载完成
 	// 等待一段时间以确保文件下载完成
-	time.Sleep(5 * time.Second) // 可能需要根据实际情况调整
+	time.Sleep(60 * time.Second) // 可能需要根据实际情况调整
 
 
 	// 查找下载目录中的文件
 	// 查找下载目录中的文件
-	files, err := filepath.Glob(filepath.Join(downloadDir, "*.xlsx"))
+	files, err := filepath.Glob(filepath.Join(defaultDir, "*.xlsx"))
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("查找文件时出错: %v", err)
 		return fmt.Errorf("查找文件时出错: %v", err)
 	}
 	}
 
 
-	// 重命名最新的文件
+	// 如果没有找到文件,返回错误
+	if len(files) == 0 {
+		return fmt.Errorf("未找到任何下载的文件")
+	}
+
+	// 找到最新的文件
+	var latestFile string
+	var latestTime time.Time
+
 	for _, file := range files {
 	for _, file := range files {
-		if err := os.Rename(file, filepath.Join(downloadDir, newFileName)); err != nil {
+		info, err := os.Stat(file)
+		if err != nil {
+			return fmt.Errorf("获取文件信息时出错: %v", err)
+		}
+		if info.ModTime().After(latestTime) {
+			latestTime = info.ModTime()
+			latestFile = file
+		}
+	}
+
+	// 目标文件的完整路径
+	targetFilePath := filepath.Join(targetDir, newFileName)
+
+	// 重命名并移动到目标目录
+	if latestFile != "" {
+		if err := moveFile(latestFile, targetFilePath); err != nil {
 			return fmt.Errorf("重命名文件时出错: %v", err)
 			return fmt.Errorf("重命名文件时出错: %v", err)
 		}
 		}
 		// 打印重命名后的文件名
 		// 打印重命名后的文件名
-		fmt.Printf("文件重命名为: %s\n", newFileName)
-		break // 只重命名第一个找到的文件
+		fmt.Printf("文件重命名并移动到: %s\n", targetFilePath)
 	}
 	}
 
 
 	return nil
 	return nil
 }
 }
 
 
-func main() {
+func moveFile(source, destination string) error {
+	// 复制文件
+	srcFile, err := os.Open(source)
+	if err != nil {
+		return fmt.Errorf("打开源文件时出错: %v", err)
+	}
+	defer srcFile.Close()
+
+	dstFile, err := os.Create(destination)
+	if err != nil {
+		return fmt.Errorf("创建目标文件时出错: %v", err)
+	}
+	defer dstFile.Close()
+
+	if _, err := io.Copy(dstFile, srcFile); err != nil {
+		return fmt.Errorf("复制文件时出错: %v", err)
+	}
+	time.Sleep(60 * time.Second)
+
+	// 删除源文件
+	if err := os.Remove(source); err != nil {
+		return fmt.Errorf("删除源文件时出错: %v", err)
+	}
+
+	return nil
+}
+
+// 解析网页数据,下载文件
+// func main() {
+func resolverNet() {
 	// 创建下载目录
 	// 创建下载目录
 	if err := os.MkdirAll(downloadDir, os.ModePerm); err != nil {
 	if err := os.MkdirAll(downloadDir, os.ModePerm); err != nil {
 		fmt.Printf("创建下载目录时出错: %v\n", err)
 		fmt.Printf("创建下载目录时出错: %v\n", err)
@@ -296,9 +268,11 @@ func main() {
 		chromedp.Flag("headless", false),
 		chromedp.Flag("headless", false),
 		chromedp.Flag("disable-blink-features", "AutomationControlled"),
 		chromedp.Flag("disable-blink-features", "AutomationControlled"),
 		chromedp.UserAgent(`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36`),
 		chromedp.UserAgent(`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36`),
-		chromedp.Flag("download.default_directory", downloadDir),
-		chromedp.Flag("download.prompt_for_download", false), // 不弹出下载对话框
-		chromedp.Flag("safebrowsing.enabled", true),          // 启用安全浏览
+		// 设置了但并不生效,直接从默认下载路径读取过来
+		//chromedp.Flag("download.default_directory", downloadDir),
+		//chromedp.Flag("download.prompt_for_download", false), // 不弹出下载对话框
+		chromedp.Flag("safebrowsing.enabled", true), // 启用安全浏览
+		//chromedp.UserDataDir(filepath.Join(downloadDir, "user-data")),
 	}
 	}
 
 
 	allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
 	allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
@@ -312,6 +286,12 @@ func main() {
 		return
 		return
 	}
 	}
 
 
+	// 设置下载行为
+	/*if err := setDownloadBehavior(ctx); err != nil {
+		fmt.Printf("设置下载路径时出错: %v\n", err)
+		return
+	}*/
+
 	// 登录操作
 	// 登录操作
 	if err := login(ctx); err != nil {
 	if err := login(ctx); err != nil {
 		fmt.Printf("登录错误: %v\n", err)
 		fmt.Printf("登录错误: %v\n", err)
@@ -327,6 +307,65 @@ func main() {
 	fmt.Println("数据下载完成")
 	fmt.Println("数据下载完成")
 }
 }
 
 
+// 解析本地文件
+// func fileResolver() {
+func main() {
+	var fileName string
+
+	// 解析Oil_Demand_Signals_Weekly_Report_表格
+	fileName = "Oil_Demand_Signals_Weekly_Report_" + utils.GetCurrentYearMonth() + ".xlsx"
+	filePath := filepath.Join(downloadDir, fileName)
+
+	// 打开 Excel 文件
+	f, err := excelize.OpenFile(filePath)
+	if err != nil {
+		log.Fatalf("无法打开 Excel 文件: %v", err)
+	}
+
+	// 获取所有工作表
+	sheetNames := f.GetSheetList()
+	for _, sheetName := range sheetNames {
+		fmt.Printf("读取工作表: %s\n", sheetName)
+
+		// 获取工作表的最大行数
+		maxRow, err := f.GetRows(sheetName) // 直接获取所有行数据
+		if err != nil {
+			log.Fatalf("获取工作表数据时出错: %v", err)
+		}
+
+		// 遍历行并打印内容
+		for _, row := range maxRow {
+			for _, cell := range row {
+				fmt.Printf("%s ", cell)
+			}
+			fmt.Println()
+		}
+	}
+}
+
+// setDownloadBehavior 设置下载路径
+func setDownloadBehavior(ctx context.Context) error {
+	return chromedp.Run(ctx,
+		chromedp.ActionFunc(func(ctx context.Context) error {
+			// 使用 chromedp.Exec 提交下载行为
+			var result interface{}
+			if err := chromedp.Evaluate(`(function() {
+				return new Promise((resolve, reject) => {
+					chrome.page.setDownloadBehavior({
+						behavior: 'allow',
+						downloadPath: '`+downloadDir+`'
+					}, function() {
+						resolve();
+					});
+				});
+			})()`, &result).Do(ctx); err != nil {
+				return fmt.Errorf("设置下载行为失败: %v", err)
+			}
+			return nil
+		}),
+	)
+}
+
 func login(ctx context.Context) error {
 func login(ctx context.Context) error {
 
 
 	return chromedp.Run(ctx,
 	return chromedp.Run(ctx,

+ 10 - 0
utils/date_util.go

@@ -486,3 +486,13 @@ func GetCurrentMonth(dateText string) (string, error) {
 
 
 	return fmt.Sprintf("%d月", month), nil
 	return fmt.Sprintf("%d月", month), nil
 }
 }
+
+func GetCurrentYearMonth() string {
+	// 获取当前时间
+	now := time.Now()
+
+	// 格式化为 "YYYYMM" 形式
+	yearMonth := now.Format("200601")
+
+	return yearMonth
+}