Selenium C# 如何提取HTML div内ALTER TABLE数据写入txt文件
需求说明
- 从网页指定DOM容器中提取全部ALTER TABLE类型的SQL脚本,写入本地.txt文件
- 测试流程:遍历本地输入目录下的待转换文件,通过Selenium驱动Chrome打开转换页面,上传文件、输入密钥、触发转换后,将生成的ALTER TABLE脚本单独存储到输出目录的txt文件中
现存问题
- 之前使用的
FindElement方法只会返回匹配XPath规则的第一个DOM节点,无法一次性获取容器内全部脚本内容,原有尝试代码如下:
string value = driver.FindElement(By.XPath("//td[@style='padding:0px; white-space: nowrap;']")).Text;
- 现有代码未等待转换结果加载完成就执行后续操作,容易拿到空值
- 已编写的
create文件函数仅写入了固定测试文本,未对接实际提取到的脚本内容,且现有测试代码存在语法缺漏(循环体未加花括号、异常块未闭合、资源未释放)
现有未完成的测试代码如下:
public void TestMethod1() { try { string dir = @"D:\test\input"; // 输入目录路径 var directory = new DirectoryInfo(dir); foreach (FileInfo file in directory.GetFiles()) // 遍历目录下所有文件 IWebDriver driver = new ChromeDriver(); driver.Navigate().GoToUrl("http:abcurl//convPLSQL.html"); // 转换页面地址 driver.Manage().Window.Maximize(); string param = dir.Replace("/", "\\"); param += "\\"; param += file.Name; driver.FindElement(By.Id("fileuploader")).SendKeys(param); driver.FindElement(By.Id("keyinput")).SendKeys("convUser001");// 转换密钥 driver.FindElement(By.Id("translatebutton")).Click();// 点击转换按钮 driver.FindElement(By.LinkText("Download Results")).Click();// 点击下载结果 // 此处未完成脚本提取逻辑 // string data= driver.FindElement(By.XPath("//td[@style='padding:0px; white-space:nowrap;']")).Text; create(); // 调用文件创建函数 } } public void create() { try { string fileName = @"D:\test\output\Mahesh.txt"; // 文件已存在则先删除 if (System.IO.File.Exists(fileName)) { System.IO.File.Delete(fileName); } // 创建新文件 using (FileStream fs = System.IO.File.Create(fileName)) { // 写入的是固定测试文本,不是实际提取的脚本 Byte[] title = new UTF8Encoding(true).GetBytes("New Text File"); fs.Write(title, 0, title.Length); byte[] author = new UTF8Encoding(true).GetBytes("Mahesh Chand"); fs.Write(author, 0, author.Length); } // 读取验证文件内容 using (StreamReader sr = System.IO.File.OpenText(fileName)) { string s = ""; while ((s = sr.ReadLine()) != null) { System.Console.WriteLine(s); } } } }
修正方案
- 替换单元素查找为多元素匹配:使用
FindElements获取所有符合XPath规则的节点,遍历拼接所有节点的Text属性,即可拿到完整的ALTER TABLE脚本 - 增加显式等待:点击转换按钮后,等待结果节点加载完成再提取内容,避免空值
- 改造文件写入函数,增加入参接收提取到的脚本内容,替换原有固定测试文本的写入逻辑
- 补全代码语法缺漏,添加driver资源释放、异常处理逻辑
修正后的可运行代码:
using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Support.UI; using System.IO; using System.Text; public void TestMethod1() { string inputDir = @"D:\test\input"; string outputPath = @"D:\test\output\Mahesh.txt"; var directory = new DirectoryInfo(inputDir); // 遍历输入目录所有文件 foreach (FileInfo file in directory.GetFiles()) { IWebDriver driver = new ChromeDriver(); try { driver.Navigate().GoToUrl("http:abcurl//convPLSQL.html"); driver.Manage().Window.Maximize(); // 拼接待上传文件全路径 string uploadPath = Path.Combine(inputDir, file.Name); // 上传文件、输入密钥、触发转换 driver.FindElement(By.Id("fileuploader")).SendKeys(uploadPath); driver.FindElement(By.Id("keyinput")).SendKeys("convUser001"); driver.FindElement(By.Id("translatebutton")).Click(); // 显式等待10秒,直到结果节点加载完成 WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); wait.Until(d => d.FindElements(By.XPath("//td[@style='padding:0px; white-space: nowrap;']")).Count > 0); // 提取所有匹配节点的文本,拼接为完整脚本 var allResultNodes = driver.FindElements(By.XPath("//td[@style='padding:0px; white-space: nowrap;']")); StringBuilder scriptBuilder = new StringBuilder(); foreach (var node in allResultNodes) { scriptBuilder.AppendLine(node.Text); } string fullAlterScript = scriptBuilder.ToString(); // 写入文件 WriteScriptToFile(outputPath, fullAlterScript); } catch (Exception ex) { Console.WriteLine($"处理文件{file.Name}出错:{ex.Message}"); } finally { // 释放浏览器资源,避免Chrome进程残留 driver.Quit(); driver.Dispose(); } } } /// <summary> /// 将提取到的SQL脚本写入txt文件 /// </summary> /// <param name="filePath">输出文件路径</param> /// <param name="scriptContent">ALTER TABLE脚本内容</param> public void WriteScriptToFile(string filePath, string scriptContent) { // 文件存在则先删除 if (File.Exists(filePath)) { File.Delete(filePath); } // 写入脚本内容 File.WriteAllText(filePath, scriptContent, Encoding.UTF8); // 控制台输出验证写入结果 using (StreamReader sr = File.OpenText(filePath)) { string line = ""; while ((line = sr.ReadLine()) != null) { Console.WriteLine(line); } } }
注意事项
- 不建议依赖style属性定位元素,前端迭代调整样式后定位规则会直接失效,如果结果容器有固定id、class属性,优先使用这类稳定属性做定位;如果实际结果容器是div而非td,把XPath里的
td替换为对应的div标签即可 - 显式等待时长可以根据页面实际转换速度调整
- 如果多个文件需要分别存储,把输出文件名改为动态名称(比如和输入文件名同名的txt)即可,不需要固定为Mahesh.txt
内容的提问来源于stack exchange,提问作者Shoaib
相关产品推荐
相关产品推荐

