
影刀RPA 网页表格数据采集解析HTML表格的正确方法作者林焱网页上的表格是结构化数据的重要载体——商品列表、财务报表、订单记录、成绩单。采集表格数据是RPA的高频需求。但很多新手只会逐个单元格获取文本一个10行5列的表格要操作50次慢得要命。而且合并单元格、嵌套表格、动态加载等特殊情况更让人头疼。这篇文章把网页表格数据采集的高效方法讲全。一、获取整个表格1.1 用影刀指令获取影刀提供【获取网页表格】指令可以一次性获取整个表格【获取网页表格】 目标元素定位到table元素 → 输出到变量 table_data二维列表返回的table_data是一个二维列表table_data[0]是第一行table_data[0][1]是第一行第二列。1.2 用JavaScript获取更灵活的方式是用JS直接提取表格数据// 获取表格数据vartabledocument.querySelector(table.data-table);varrowstable.querySelectorAll(tr);vardata[];rows.forEach(function(row){varcellsrow.querySelectorAll(td, th);varrowData[];cells.forEach(function(cell){rowData.push(cell.innerText.trim());});data.push(rowData);});returnJSON.stringify(data);在影刀的【执行JavaScript】指令中运行这段代码返回JSON字符串在Python中解析importjson table_jsonget_variable(js_result)table_datajson.loads(table_json)# table_data是二维列表print(f共{len(table_data)}行{len(table_data[0])}列)1.3 用pandas直接读取HTML表格importpandasaspd# 从HTML字符串读取表格tablespd.read_html(html_string)# 返回所有表格的列表tables[0]是第一个表格# 从URL读取tablespd.read_html(https://example.com/data)dftables[0]# 第一个表格# 从本地HTML文件读取tablespd.read_html(D:\\data\\page.html)dftables[0]# 转成字典列表datadf.to_dict(records)pandas的read_html非常强大它自动解析HTML中的table标签返回DataFrame。适合处理标准HTML表格。店群矩阵自动化突破运营极限二、逐行逐列采集2.1 按行遍历当表格不能一次性获取时如动态加载、需要逐行处理用逐行遍历# 获取所有行rowsget_element_list(//table[iddata-table]//tr)table_data[]forrowinrows:# 获取这一行的所有单元格cellsrow.find_elements_by_css_selector(td, th)row_data[cell.text.strip()forcellincells]table_data.append(row_data)# 第一行是表头headerstable_data[0]datatable_data[1:]2.2 按列获取需要获取某一列的数据# 获取第三列索引2的所有数据column_data[]rowsget_element_list(//table//tr)forrowinrows[1:]:# 跳过表头cellsrow.find_elements_by_css_selector(td)iflen(cells)2:column_data.append(cells[2].text.strip())print(f第三列数据{column_data})2.3 按单元格获取需要精确定位某个单元格# 获取第3行第2列的值cell_valueget_element_text(//table//tr[3]//td[2])# 用XPath精确定位cell_valueget_element_text(//table[iddata]//tr[3]/td[2])三、处理合并单元格3.1 行合并rowspantabletrtdrowspan2华东/tdtd上海/td/trtrtd杭州/td!-- 第一列被合并了这行只有2个td --/tr/table合并单元格导致某些行少一个td直接遍历会错位。处理方法填充合并的值# 用JS处理合并单元格js_code var table document.querySelector(table); var rows table.querySelectorAll(tr); var data []; // 第一遍收集所有单元格的位置信息 var grid []; for (var r 0; r rows.length; r) { var cells rows[r].querySelectorAll(td, th); var colIndex 0; var rowData []; for (var c 0; c cells.length; c) { // 跳过被合并占据的位置 while (grid[r] grid[r][colIndex]) { rowData.push(grid[r][colIndex]); colIndex; } var cell cells[c]; var text cell.innerText.trim(); rowData.push(text); var rowspan parseInt(cell.getAttribute(rowspan) || 1); var colspan parseInt(cell.getAttribute(colspan) || 1); // 记录合并范围 for (var rs 0; rs rowspan; rs) { if (!grid[r rs]) grid[r rs] []; for (var cs 0; cs colspan; cs) { grid[r rs][colIndex cs] text; } } colIndex colspan; } data.push(rowData); } return JSON.stringify(data); resultexecute_js(js_code)table_datajson.loads(result)3.2 列合并colspantrtdcolspan2合计/td!-- 占两列 --td100/td/tr列合并导致一行中td数量少于列数。处理方法同上用JS填充。3.3 简化方案用pandas处理importpandasaspd# pandas的read_html会自动处理合并单元格tablespd.read_html(html_string,header0)dftables[0]# 合并单元格的值会被填充到所有合并的行/列print(df)四、动态加载的表格4.1 滚动加载表格数据不是一次性加载的滚动到底部才加载更多importtime all_data[]last_height0whileTrue:# 获取当前可见的行rowsget_element_list(//table//tr)forrowinrows:cellsrow.find_elements_by_css_selector(td)row_data[cell.text.strip()forcellincells]ifrow_datanotinall_data:all_data.append(row_data)# 滚动到底部execute_js(window.scrollTo(0, document.body.scrollHeight))time.sleep(2)# 检查是否到底current_heightexecute_js(return document.body.scrollHeight)ifcurrent_heightlast_height:break# 没有新数据了last_heightcurrent_heightprint(f共采集{len(all_data)}行)4.2 翻页表格表格分页显示需要翻页采集all_data[]page1whileTrue:# 采集当前页表格rowsget_element_list(//table//tr)forrowinrows:cellsrow.find_elements_by_css_selector(td)row_data[cell.text.strip()forcellincells]ifrow_data:all_data.append(row_data)print(f第{page}页采集{len(rows)}行累计{len(all_data)}行)# 检查是否有下一页next_btnget_element(//a[classnext-page])ifnotnext_btnordisabledinnext_btn.get_attribute(class):break# 点击下一页next_btn.click()wait_for_element(//table)page1print(f共采集{len(all_data)}行数据)4.3 AJAX加载的表格表格数据通过AJAX请求加载表格HTML是动态生成的。等待表格加载完成后再采集# 触发数据加载click_element(#load-data)# 等待表格行出现wait_for_element(//table//tr,timeout30)# 等待数据加载完成行数不再变化previous_count0whileTrue:current_countexecute_js(return document.querySelectorAll(table tr).length)ifcurrent_countprevious_countandcurrent_count0:breakprevious_countcurrent_count time.sleep(1)# 采集数据rowsget_element_list(//table//tr)五、表格中的链接和按钮5.1 提取单元格中的链接rowsget_element_list(//table//tr)forrowinrows:# 获取单元格文本namerow.find_element_by_css_selector(td:nth-child(1)).text# 获取链接linkrow.find_element_by_css_selector(td:nth-child(2) a)hreflink.get_attribute(href)# 获取链接文本link_textlink.textprint(f{name}:{link_text}→{href})5.2 点击行中的操作按钮rowsget_element_list(//table//tr)forrowinrows:namerow.find_element_by_css_selector(td:nth-child(1)).text statusrow.find_element_by_css_selector(td:nth-child(3)).textifstatus待处理:[video(video-4KIWJsyQ-1784737689307)(type-csdn)(url-https://live.csdn.net/v/embed/524992)(image-https://v-blog.csdnimg.cn/asset/b59aed2f01d4fe8583467562aaf4dcfd/cover/Cover0.jpg)(title-temu店群自动化报活动案例)]# 点击该行的处理按钮btnrow.find_element_by_css_selector(button.process-btn)btn.click()wait_for_element(.process-success)print(f已处理{name})5.3 进入行详情页rowsget_element_list(//table//tr)forrowinrows[1:]:# 跳过表头# 点击行进入详情row.click()wait_for_element(.detail-page)# 采集详情数据detailget_element_text(.detail-content)# 返回列表click_element(.back-button)wait_for_element(//table)print(detail)六、表格数据转Excel6.1 直接写入importpandasaspd# table_data是采集的二维列表headerstable_data[0]datatable_data[1:]dfpd.DataFrame(data,columnsheaders)df.to_excel(D:\\output\\table_data.xlsx,indexFalse)6.2 带格式写入importopenpyxlfromopenpyxl.stylesimportFont,PatternFill,Alignment,Border,Side wbopenpyxl.Workbook()wswb.active ws.title采集数据# 写入数据forrow_idx,row_datainenumerate(table_data,1):forcol_idx,valueinenumerate(row_data,1):ws.cell(rowrow_idx,columncol_idx,valuevalue)# 表头格式header_fontFont(boldTrue,colorFFFFFF)header_fillPatternFill(start_color4472C4,end_color4472C4,fill_typesolid)forcolinrange(1,len(table_data[0])1):cellws.cell(row1,columncol)cell.fontheader_font cell.fillheader_fill cell.alignmentAlignment(horizontalcenter)# 边框thin_borderBorder(leftSide(stylethin),rightSide(stylethin),topSide(stylethin),bottomSide(stylethin))forrowinws.iter_rows(min_row1,max_rowlen(table_data),max_collen(table_data[0])):forcellinrow:cell.borderthin_border# 自适应列宽forcolinrange(1,len(table_data[0])1):max_len0forrowinrange(1,len(table_data)1):valws.cell(rowrow,columncol).valueifval:lengthsum(2iford(c)127else1forcinstr(val))max_lenmax(max_len,length)ws.column_dimensions[openpyxl.utils.get_column_letter(col)].widthmax_len4wb.save(D:\\output\\table_data.xlsx)七、避坑清单坑1表头和数据行数量不一致表头有5列但某些数据行只有4列因为合并单元格或某些列为空。用最大列数对齐max_colsmax(len(row)forrowintable_data)forrowintable_data:whilelen(row)max_cols:row.append()# 补齐空列坑2表格中有嵌套表格tabletrtdtable.../table!-- 嵌套表格 --/td/tr/table用具体的XPath避免获取到嵌套表格的数据//table[idmain-table]/tbody/tr/td !-- 只获取直接子元素 --坑3表格内容包含HTML标签单元格中可能有br、span等标签innerText会去掉标签只返回文本innerHTML会保留标签。通常用innerText。坑4表格太大数据量大一个表格几千行一次性获取可能超时或内存不足。分页或分段采集。坑5表头不在第一行有些表格前面有标题行或说明行真正的表头在第2或第3行。调整起始行headerstable_data[1]# 第2行是表头datatable_data[2:]# 第3行开始是数据