税务数据提取

Creado el: 14 de enero de 2025

Respondido usando O1 por Chat01

Pregunta

var htmls = []string{
<table id="report1" cellspacing="0" cellpadding="0" style="width:1045px;table-layout:fixed;margin:auto;border-collapse:collapse"> <colgroup> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> <col style="width:95px;"> </colgroup> <tbody><tr rn="1" style="height:30px;"> <td colspan="11" class="report1_5">财产和行为税纳税申报表</td> <td class="report1_15" style="display:none;"></td> </tr> <tr rn="2" style="height:25px;"> <td colspan="11" class="report1_6">纳税人识别号(统一社会信用代码):91140525MA0KN94L2W</td> <td class="report1_16" style="display:none;"></td> </tr> <tr rn="3" style="height:25px;"> <td colspan="4" class="report1_12">纳税人名称:晋城市锦城工贸有限公司</td> <td class="report1_12"></td> <td class="report1_12"></td> <td colspan="5" class="report1_18" style="padding-right:3px;">金额单位:人民币元(列至角分)</td> <td class="report1_14" style="padding-right:3px;display:none;"></td> </tr> <tr rn="4" style="height:25px;"> <td rowspan="2" colspan="5" class="report1_3" style="padding-left:3px;padding-right:3px;">本期是否适用小微企业“六税两费”减征政策</td> <td rowspan="2" class="report1_3" style="padding-left:3px;padding-right:3px;">■ 是 □ 否</td> <td colspan="2" class="report1_3" style="padding-left:3px;padding-right:3px;">减征政策适用主体</td> <td colspan="3" class="report1_17">增值税小规模纳税人</td> <td class="report1_2" style="padding-left:3px;display:none;"></td> </tr> <tr rn="5" style="height:25px;"> <td colspan="2" class="report1_3" style="padding-left:3px;padding-right:3px;">适用减征政策起止时间</td> <td colspan="3" class="report1_3">2024年1月1日 至 2024年12月31日</td> <td class="report1_2" style="padding-left:3px;display:none;"></td> </tr> <tr rn="6" style="height:25px;"> <td class="report1_3" style="padding-left:3px;padding-right:3px;">序号</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">税种</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">税目</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">税款所属期起</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">税款所属期止</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">计税依据</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">税率</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">应纳税额</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">减免税额</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">已缴税额</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">应补(退)税额</td> <td class="report1_7" style="padding-left:3px;padding-right:3px;display:none;"></td> </tr> <tr rn="7" style="height:25px;"> <td class="report1_3" style="padding-left:3px;padding-right:3px;">1</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">印花税</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">营业账簿</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">2024-01-01</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">2024-12-31</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_4" style="padding-right:3px;">0.00025</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_10" style="padding-right:3px;display:none;"></td> </tr> <tr rn="8" style="height:25px;"> <td class="report1_3" style="padding-left:3px;padding-right:3px;">2</td> <td class="report1_3" style="padding-left:3px;padding-right:3px;">合计</td> <td class="report1_4" style="padding-right:3px;">-</td> <td class="report1_4" style="padding-right:3px;">-</td> <td class="report1_4" style="padding-right:3px;">-</td> <td class="report1_4" style="padding-right:3px;">-</td> <td class="report1_4" style="padding-right:3px;">-</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_4" style="padding-right:3px;">0.00</td> <td class="report1_10" style="padding-right:3px;display:none;"></td> </tr> <tr rn="9" style="height:25px;"> <td colspan="5" class="report1_11" style="padding-left:3px;">经办人: 宋逸凡</td> <td colspan="6" class="report1_8" style="padding-left:3px;">受理人:11400xdzswj</td> <td class="report1_2" style="padding-left:3px;display:none;"></td> </tr> <tr rn="10" style="height:25px;"> <td colspan="5" class="report1_1" style="padding-left:3px;">经办人身份证号: 140521*********622</td> <td rowspan="2" colspan="6" class="report1_9" style="padding-left:3px;">受理税务机关(章):国家税务总局泽州县税务局金村税务所</td> <td class="report1_2" style="padding-left:3px;display:none;"></td> </tr> <tr rn="11" style="height:25px;"> <td colspan="5" class="report1_1" style="padding-left:3px;">代理机构签章: </td> <td class="report1_2" style="padding-left:3px;display:none;"></td> </tr> <tr rn="12" style="height:25px;"> <td colspan="5" class="report1_13" style="padding-left:3px;">代理机构统一社会信用代码: </td> <td colspan="6" class="report1_13" style="padding-left:3px;">受理日期: 2025 年 1 月 7 日 </td> <td class="report1_2" style="padding-left:3px;display:none;"></td> </tr> </tbody></table>,
<table id="report1" cellspacing="0" cellpadding="0" style="width:1142px;table-layout:fixed;margin:auto;border-collapse:collapse"> <colgroup> <col style="width:1px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:60px;"> <col style="width:1px;"> </colgroup> <tbody><tr rn="1" style="height:40px;"> <td class="report1_5"></td> <td colspan="19" class="report1_5">定期定额纳税申报表</td> <td class="report1_5"></td> </tr> <tr rn="2" style="height:25px;"> <td class="report1_2"></td> <td colspan="5" class="report1_14" style="padding-left:5px;">纳税人识别号:92341225MAD1Q4LG9X</td> <td colspan="8" class="report1_16">纳税人名称:阜南县鸿鑫五金加工厂</td> <td colspan="6" class="report1_12" style="padding-right:5px;">税款所属期:2024年10月1日—2024年12月31日</td> <td class="report1_2"></td> </tr> <tr rn="3" style="height:70px;"> <td class="report1_13"></td> <td class="report1_4">征收项目</td> <td class="report1_4">征收品目</td> <td class="report1_4">征收子目</td> <td class="report1_4">应税项(2)</td> <td class="report1_4">计税依据<br>(3)</td> <td class="report1_4">税款所属<br>期起</td> <td class="report1_4">税款所属<br>期止</td> <td class="report1_4">核定计税<br>依据(4)</td> <td class="report1_4">税率(征收<br>率)(5)</td> <td class="report1_4">本期应纳<br>税额(6)</td> <td class="report1_4">核定应纳<br>税额(7)</td> <td class="report1_4">减免性质</td> <td class="report1_4">减免税额<br>(8)</td> <td class="report1_4">个体工商<br>户减半征<br>收个人所<br>得税</td> <td class="report1_4">小规模减<br>征减免性<br>质</td> <td class="report1_4">小规模减<br>征比例%</td> <td class="report1_4">小规模减<br>征额(9)</td> <td class="report1_4">本期已缴<br>税额(10)</td> <td class="report1_4">本期应补<br>(退)税额<br>(11)=6-8-<br>9-10</td> <td class="report1_17"></td> </tr> <tr rn="4" style="height:291px;"> <td rowspan="2" class="report1_15"></td> <td class="report1_4">水利建设<br>专项收入</td> <td class="report1_4">地方水利<br>建设基金</td> <td class="report1_4"></td> <td class="report1_3" style="padding-right:5px;">255,<br>000.00</td> <td class="report1_3" style="padding-right:5px;">255,<br>000.00</td> <td class="report1_4">2024-10-<br>01</td> <td class="report1_4">2024-12-<br>31</td> <td class="report1_3" style="padding-right:5px;">255,<br>000.00</td> <td class="report1_3" style="padding-right:5px;">0.0006</td> <td class="report1_3" style="padding-right:5px;">153.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4">《财政部 <br>国家税务<br>总局关于<br>扩大有关<br>政府性基<br>金免征范<br>围的通<br>知》 财税<br>〔2016〕<br>12号第一<br>条第<br>(一)款</td> <td class="report1_3" style="padding-right:5px;">153.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">《财政<br>部 国家<br>税务总<br>局关于<br>扩大有<br>关政府<br>性基金<br>免征范<br>围的通<br>知》 财<br>税<br>〔201<br>6〕12号<br>第一条<br>第<br>(一)<br>款</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_10"></td> </tr> <tr rn="5" style="height:53px;"> <td class="report1_4">个人所得<br>税</td> <td class="report1_4">经营所得</td> <td class="report1_4">(应税所<br>得率)制<br>造业5%</td> <td class="report1_3" style="padding-right:5px;">255,<br>000.00</td> <td class="report1_3" style="padding-right:5px;">12,<br>750.00</td> <td class="report1_4">2024-10-<br>01</td> <td class="report1_4">2024-12-<br>31</td> <td class="report1_3" style="padding-right:5px;">12,<br>750.00</td> <td class="report1_3" style="padding-right:5px;">0.10</td> <td class="report1_3" style="padding-right:5px;">900.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4">其他</td> <td class="report1_3" style="padding-right:5px;">900.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">其他</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_10"></td> </tr> <tr rn="6" style="height:36px;"> <td class="report1_15"></td> <td class="report1_4">合计</td> <td class="report1_4">--</td> <td class="report1_4">--</td> <td class="report1_3" style="padding-right:5px;">510,<br>000.00</td> <td class="report1_3" style="padding-right:5px;">267,<br>750.00</td> <td class="report1_4">--</td> <td class="report1_4">--</td> <td class="report1_3" style="padding-right:5px;">267,<br>750.00</td> <td class="report1_4">--</td> <td class="report1_3" style="padding-right:5px;">1,053.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4">--</td> <td class="report1_3" style="padding-right:5px;">1,053.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4">--</td> <td class="report1_4">--</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_10" style="padding-left:5px;padding-right:5px;"></td> </tr> <tr rn="7" style="height:25px;"> <td class="report1_8"></td> <td colspan="6" class="report1_6" style="padding-left:5px;">办税人:杜玲</td> <td class="report1_7"></td> <td class="report1_9"></td> <td class="report1_7"></td> <td class="report1_9"></td> <td class="report1_9"></td> <td class="report1_7"></td> <td class="report1_9"></td> <td colspan="6" class="report1_6">申报日期:2025-01-11</td> <td class="report1_8"></td> </tr> <tr rn="8" style="height:25px;"> <td class="report1_8"></td> <td colspan="6" class="report1_11" style="padding-left:5px;">办理人员身份证件类型:居民身份证</td> <td class="report1_8"></td> <td class="report1_1"></td> <td class="report1_8"></td> <td class="report1_1"></td> <td class="report1_1"></td> <td class="report1_8"></td> <td class="report1_1"></td> <td colspan="6" class="report1_11">办理人员身份证件号码:341225*********127</td> <td class="report1_8"></td> </tr> <tr rn="9" style="height:25px;"> <td class="report1_8"></td> <td colspan="6" class="report1_11" style="padding-left:5px;">受理人:新电子税务局</td> <td colspan="3" class="report1_1">受理日期:</td> <td colspan="3" class="report1_11">2025-01-11</td> <td class="report1_1"></td> <td colspan="6" class="report1_11">受理税务机关:国家税务总局阜南县税务局</td> <td class="report1_8"></td> </tr> </tbody></table> ,
<table id="report1" cellspacing="0" cellpadding="0" style="width:1734px;table-layout:fixed;margin:auto;border-collapse:collapse"> <colgroup> <col style="width:76px;"> <col style="width:76px;"> <col style="width:76px;"> <col style="width:76px;"> <col style="width:76px;"> <col style="width:76px;"> <col style="width:76px;"> <col style="width:76px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:76px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> <col style="width:70px;"> </colgroup> <tbody><tr rn="1" style="height:103px;"> <td class="report1_1"></td> <td class="report1_1"></td> <td class="report1_1"></td> <td colspan="21" class="report1_1">通用申报表(税及附征税费)</td> </tr> <tr rn="2" style="height:49px;"> <td colspan="2" class="report1_10" style="padding-right:5px;">纳税人识别号:</td> <td colspan="6" class="report1_12">91140525MA0KN94L2W</td> <td colspan="2" class="report1_10">纳税人名称:</td> <td colspan="6" class="report1_13">晋城市锦城工贸有限公司</td> <td colspan="8" class="report1_10">税款所属期起止:2024年10月1日至2024年12月31日</td> </tr> <tr rn="3" style="height:88px;"> <td class="report1_5">税源标志</td> <td class="report1_5">税源编号</td> <td class="report1_5">税源坐落</td> <td class="report1_5">征收项目</td> <td class="report1_5">征收品目</td> <td class="report1_5">征收子目</td> <td class="report1_5">税(费)款<br>所属期起</td> <td class="report1_5">税(费)款<br>所属期止</td> <td class="report1_5">应税项<br>(1)</td> <td class="report1_5">减除项<br>(2)</td> <td class="report1_5">应税所得率<br>(3)</td> <td class="report1_5">计税(费)<br>依据(4=<br>(1-2)*<br>3)</td> <td class="report1_5">税(费)率<br>或单位税额<br>(5)</td> <td class="report1_5">速算扣除数<br>(6)</td> <td class="report1_5">本期应纳税<br>(费)额<br>(7=4*5-<br>6)</td> <td class="report1_5">本期减免税<br>(费)额<br>(8)</td> <td class="report1_5">减免性质</td> <td class="report1_5">本期是否适<br>用小微企业<br>“六税两<br>费”减征政<br>策</td> <td class="report1_5">减征政策适<br>用主体</td> <td class="report1_5">小微企业<br>“六税两<br>费”减免性<br>质</td> <td class="report1_5">小微企业<br>“六税两<br>费”减征比<br>例</td> <td class="report1_5">小微企业<br>“六税两<br>费”减征额<br>(9)</td> <td class="report1_5">本期已缴税<br>(费)额<br>(10)</td> <td class="report1_5">本期应补<br>(退)税<br>(费)额<br>(11=7-8-<br>9-10)</td> </tr> <tr rn="4" style="height:30px;"> <td class="report1_4" style="padding-left:5px;padding-right:5px;"></td> <td class="report1_3" style="padding-right:5px;"></td> <td class="report1_4" style="padding-left:5px;padding-right:5px;"></td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">其他收入</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">工会筹备金</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;"></td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">2024-10-01</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">2024-12-31</td> <td class="report1_3" style="padding-right:5px;">4,500.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">1.000000</td> <td class="report1_3" style="padding-right:5px;">4,500.00</td> <td class="report1_3" style="padding-right:5px;">0.020000</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">90.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;"></td> <td class="report1_4" style="padding-left:5px;padding-right:5px;"></td> <td class="report1_4" style="padding-left:5px;padding-right:5px;"></td> <td class="report1_4" style="padding-left:5px;padding-right:5px;"></td> <td class="report1_3" style="padding-right:5px;"></td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">90.00</td> </tr> <tr rn="5" style="height:30px;"> <td class="report1_4" style="padding-left:5px;padding-right:5px;">合计</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_3" style="padding-right:5px;"></td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_3" style="padding-right:5px;">4,500.00</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_3" style="padding-right:5px;">90.00</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_4" style="padding-left:5px;padding-right:5px;">--</td> <td class="report1_3" style="padding-right:5px;">0.000000</td> <td class="report1_3" style="padding-right:5px;">0.00</td> <td class="report1_3" style="padding-right:5px;">90.00</td> </tr> <tr rn="6" style="height:30px;"> <td colspan="24" class="report1_2" style="padding-left:5px;">其他个人出租不动产租金是否分摊   □ 是  □ 否</td> </tr> <tr rn="7" style="height:30px;"> <td colspan="3" class="report1_2" style="padding-left:5px;">其他个人出租不动产租赁期起</td> <td colspan="21" class="report1_2"></td> </tr> <tr rn="8" style="height:30px;"> <td colspan="3" class="report1_2" style="padding-left:5px;">其他个人出租不动产租赁期止</td> <td colspan="21" class="report1_2" style="padding-left:5px;"></td> </tr> <tr rn="9" style="height:30px;"> <td colspan="3" class="report1_2" style="padding-left:5px;">其他个人出租不动产分摊后月租金收入</td> <td colspan="21" class="report1_2" style="padding-left:5px;"></td> </tr> <tr rn="10" style="height:30px;"> <td colspan="6" class="report1_11" style="padding-left:5px;">办税人:宋逸凡</td> <td class="report1_8" style="padding-right:5px;">申报日期:</td> <td colspan="3" class="report1_9">2025-01-07</td> <td colspan="5" class="report1_11" style="padding-left:5px;">受理人:11400xdzswj</td> <td colspan="2" class="report1_8">受理日期:</td> <td colspan="2" class="report1_11" style="padding-left:5px;">2025-01-07</td> <td colspan="2" class="report1_8" style="padding-right:5px;">受理税务机关:</td> <td colspan="3" class="report1_11">国家税务总局泽州县税务局</td> </tr> <tr rn="11" style="height:30px;"> <td colspan="6" class="report1_7" style="padding-left:5px;">办理人员身份证件类型:居民身份证</td> <td class="report1_6"></td> <td class="report1_7" style="padding-left:5px;"></td> <td class="report1_7"></td> <td class="report1_7"></td> <td colspan="7" class="report1_7" style="padding-left:5px;">办理人员身份证件号码:140521*********622</td> <td class="report1_7"></td> <td class="report1_7" style="padding-left:5px;"></td> <td colspan="2" class="report1_7" style="padding-left:5px;"></td> <td class="report1_7" style="padding-left:5px;"></td> <td class="report1_7" style="padding-left:5px;"></td> <td class="report1_7" style="padding-left:5px;"></td> </tr> </tbody></table>,
}

func TestExtractData(t *testing.T) {
for _, html := range htmls {
data, err := extractTaxData(html)
fmt.Println(data, err)
}
}
type TaxData struct {
TaxType string
TaxItem string
TaxAmount string
}

// getCellColumnIndex 计算每个单元格的实际列索引,考虑colspan属性。
// 返回一个映射,键为列索引,值为对应的单元格。
func getCellColumnIndex(cells *goquery.Selection, totalColumns int) map[int]*goquery.Selection {
columnIndex := 0
cellMap := make(map[int]*goquery.Selection)
cells.Each(func(i int, cell *goquery.Selection) {
colspan, _ := cell.Attr("colspan")
if colspan == "" {
colspan = "1"
}
colSpanInt, _ := strconv.Atoi(colspan)
for j := 0; j < colSpanInt; j++ {
cellMap[columnIndex] = cell
columnIndex++
}
})
for ; columnIndex < totalColumns; columnIndex++ {
cellMap[columnIndex] = nil
}
return cellMap
}

func extractTaxData(html string) ([]TaxData, error) {
doc, err := goquery.NewDocumentFromReader(bytes.NewReader([]byte(html)))
if err != nil {
return nil, err
}

text
var data []TaxData // 选择表格 table := doc.Find("#report1") if table.Length() == 0 { return nil, fmt.Errorf("table not found") } // 获取表格的总列数,假设是第一行的<td>数量 var totalColumns int table.Find("tbody tr").First().Find("td").Each(func(i int, _ *goquery.Selection) { totalColumns++ }) var headerRow *goquery.Selection var taxTypeCol, taxItemCol, taxAmountCol int // 遍历每一行,找到包含“税种”、“税目”和“应补(退)税额”的标题行 table.Find("tbody tr").Each(func(i int, tr *goquery.Selection) { cells := tr.Find("td") cellMap := getCellColumnIndex(cells, totalColumns) var hasTaxType, hasTaxItem, hasTaxAmount bool for colIndex, cell := range cellMap { if cell != nil { text := cell.Text() if strings.Contains(text, "税种") || strings.Contains(text, "征收项目") { hasTaxType = true taxTypeCol = colIndex } if strings.Contains(text, "税目") || strings.Contains(text, "征收品目") { hasTaxItem = true taxItemCol = colIndex } if strings.Contains(text, "应补(退)税额") { hasTaxAmount = true taxAmountCol = colIndex } } } if hasTaxType && hasTaxItem && hasTaxAmount { headerRow = tr return } }) if headerRow == nil { return nil, fmt.Errorf("header row not found") } var rows *goquery.Selection // 找到标题行之后的所有行 rows = headerRow.NextAll() // 遍历数据行 rows.Each(func(i int, tr *goquery.Selection) { cells := tr.Find("td") cellMap := getCellColumnIndex(cells, totalColumns) // 忽略包含“经办人”、“受理人”、“经办人身份证号”等无关信息的行 if cells.Text() == "" || strings.Contains(cells.Text(), "经办人") || strings.Contains(cells.Text(), "受理人") || strings.Contains(cells.Text(), "经办人身份证号") { return } if strings.Contains(cells.Text(), "代理机构签章") || strings.Contains(cells.Text(), "代理机构统一社会信用代码") || strings.Contains(cells.Text(), "受理日期") { return } var isTotalRow bool // 检查是否是合计行 cells.Each(func(j int, cell *goquery.Selection) { if cell != nil && strings.Contains(cell.Text(), "合计") { isTotalRow = true return } }) if isTotalRow { return } // 获取税种、税目和应补(退)税额的单元格 taxTypeCell := cellMap[taxTypeCol] taxItemCell := cellMap[taxItemCol] taxAmountCell := cellMap[taxAmountCol] var taxType, taxItem, taxAmount string if taxTypeCell != nil { taxType = taxTypeCell.Text() } if taxItemCell != nil { taxItem = taxItemCell.Text() } if taxAmountCell != nil { taxAmount = taxAmountCell.Text() } // 如果所有值都为空,跳过 if taxType == "" && taxItem == "" && taxAmount == "" { return } // 添加数据到结果列表 data = append(data, TaxData{ TaxType: taxType, TaxItem: taxItem, TaxAmount: taxAmount, }) }) return data, nil

}
修改extractTaxData函数,使这三条HTML数据能解析出正确的返回数据:税种 税目 应补退税额 (名称可能不同)

Pensamiento

Parsing HTML tables

I’m tasked with extracting data from three HTML samples, focusing on tax type, tax item, and tax amount. The column names might vary, so flexibility in handling different labels is required.

Defining identifying strings

I’m noting specific strings to identify tax type, tax item, and tax amount in HTML tables. Parsing will involve matching these strings to column headers and gathering data accordingly.

Thought about tax data extraction code,持续 31 秒

Respuesta

下面给出一个示例的修改方案,思路是:

  1. 放宽标题行的匹配,因为不同表格中「税种/征收项目」「税目/征收品目」「应补(退)税额/本期应补(退)税额/本期应补(退)税(费)额」等字段不完全一致;
  2. 通过关键词数组来做模糊匹配,而不是只匹配一次;
  3. 在找到标题行后,对应记录下「税种列索引」「税目列索引」「应补(退)税额列索引」;
  4. 依次读取下方行,若该行并非合计等无效行,则根据前面记录的列索引提取对应的数据。

当然,实际情况可能更复杂,比如部分报表列名不在同一行、表格中有多头表头等,需要更精细的处理。这里给出的示例仅供参考,你可以根据实际业务需求作进一步优化。


go
package main import ( "bytes" "fmt" "strconv" "strings" "testing" "github.com/PuerkitoBio/goquery" ) type TaxData struct { TaxType string TaxItem string TaxAmount string } // getCellColumnIndex 计算每个单元格的实际列索引,考虑colspan属性。 // 返回一个映射,键为列索引,值为对应的单元格。 func getCellColumnIndex(cells *goquery.Selection, totalColumns int) map[int]*goquery.Selection { columnIndex := 0 cellMap := make(map[int]*goquery.Selection) cells.Each(func(i int, cell *goquery.Selection) { colspan, _ := cell.Attr("colspan") if colspan == "" { colspan = "1" } colSpanInt, _ := strconv.Atoi(colspan) for j := 0; j < colSpanInt; j++ { cellMap[columnIndex] = cell columnIndex++ } }) // 如果本行实际列数小于 totalColumns,则用 nil 填充 for ; columnIndex < totalColumns; columnIndex++ { cellMap[columnIndex] = nil } return cellMap } // 判断某个文本是否匹配关键字列表中的任意一个 func containsAnyKeyword(text string, keywords []string) bool { for _, kw := range keywords { if strings.Contains(text, kw) { return true } } return false } // extractTaxData 提取“税种/征收项目”、“税目/征收品目”和“应补(退)税额/本期应补(退)税额”三列数据 func extractTaxData(htmlStr string) ([]TaxData, error) { doc, err := goquery.NewDocumentFromReader(bytes.NewReader([]byte(htmlStr))) if err != nil { return nil, err } var data []TaxData // 选择表格 table := doc.Find("#report1") if table.Length() == 0 { return nil, fmt.Errorf("table not found") } // 获取表格的总列数,假设是第一行的<td>数量 var totalColumns int table.Find("tbody tr").First().Find("td").Each(func(i int, _ *goquery.Selection) { totalColumns++ }) // 定义三个列的关键词,用于识别表头 taxTypeKeywords := []string{"税种", "征收项目"} // 可能会有其他,视业务需求添加 taxItemKeywords := []string{"税目", "征收品目"} // 同上 taxAmtKeywords := []string{ "应补(退)税额", "本期应补(退)税额", "应补(退)税额", "本期应补(退)税额", "本期应补(退)税(费)额", } var headerRow *goquery.Selection var taxTypeCol, taxItemCol, taxAmountCol = -1, -1, -1 // 遍历每一行,尝试找到包含上述关键词的表头行 table.Find("tbody tr").Each(func(i int, tr *goquery.Selection) { cells := tr.Find("td") cellMap := getCellColumnIndex(cells, totalColumns) // 记录当前行有哪些关键词列被匹配 currentTaxTypeCol := -1 currentTaxItemCol := -1 currentTaxAmountCol := -1 for colIndex, cell := range cellMap { if cell == nil { continue } text := strings.TrimSpace(cell.Text()) // 如果该文本中包含税种/征收项目的关键词 if containsAnyKeyword(text, taxTypeKeywords) { currentTaxTypeCol = colIndex } // 如果该文本中包含税目/征收品目的关键词 if containsAnyKeyword(text, taxItemKeywords) { currentTaxItemCol = colIndex } // 如果该文本中包含应补退税额等关键词 if containsAnyKeyword(text, taxAmtKeywords) { currentTaxAmountCol = colIndex } } // 若在同一行都找到了,则说明该行是表头行 if currentTaxTypeCol != -1 && currentTaxItemCol != -1 && currentTaxAmountCol != -1 { headerRow = tr taxTypeCol = currentTaxTypeCol taxItemCol = currentTaxItemCol taxAmountCol = currentTaxAmountCol return } }) if headerRow == nil { return nil, fmt.Errorf("header row not found") } // 找到标题行之后所有的兄弟行(剩下的行) rows := headerRow.NextAll() // 遍历数据行 rows.Each(func(i int, tr *goquery.Selection) { cells := tr.Find("td") cellMap := getCellColumnIndex(cells, totalColumns) // 忽略一些明显的无关行,比如只包含“经办人”、“受理人”、“合计”等 fullText := strings.TrimSpace(cells.Text()) if fullText == "" { return } if strings.Contains(fullText, "经办人") || strings.Contains(fullText, "受理人") || strings.Contains(fullText, "身份证号") || strings.Contains(fullText, "代理机构") || strings.Contains(fullText, "受理日期") || strings.Contains(fullText, "受理税务机关") || strings.Contains(fullText, "纳税人识别号") || strings.Contains(fullText, "纳税人名称") { return } // 判断是否是“合计”行 isTotalRow := false cells.Each(func(j int, cell *goquery.Selection) { if strings.Contains(strings.TrimSpace(cell.Text()), "合计") { isTotalRow = true } }) if isTotalRow { return } // 如果这三列的索引超出范围,也跳过 if taxTypeCol < 0 || taxTypeCol >= totalColumns { return } if taxItemCol < 0 || taxItemCol >= totalColumns { return } if taxAmountCol < 0 || taxAmountCol >= totalColumns { return } // 分别读取对应列的文本 var taxType, taxItem, taxAmount string if taxTypeCell := cellMap[taxTypeCol]; taxTypeCell != nil { taxType = strings.TrimSpace(taxTypeCell.Text()) } if taxItemCell := cellMap[taxItemCol]; taxItemCell != nil { taxItem = strings.TrimSpace(taxItemCell.Text()) } if taxAmountCell := cellMap[taxAmountCol]; taxAmountCell != nil { taxAmount = strings.TrimSpace(taxAmountCell.Text()) } // 如果所有值都为空,跳过 if taxType == "" && taxItem == "" && taxAmount == "" { return } data = append(data, TaxData{ TaxType: taxType, TaxItem: taxItem, TaxAmount: taxAmount, }) }) return data, nil } // 简单测试 func TestExtractData(t *testing.T) { htmls := []string{ // 第一份报表 ` <table id="report1" cellspacing="0" cellpadding="0" style="width:1045px;table-layout:fixed;margin:auto;border-collapse:collapse"> <colgroup> <col style="width:95px;"> ... </tbody></table>`, // 第二份报表 ` <table id="report1" cellspacing="0" cellpadding="0" style="width:1142px;table-layout:fixed;margin:auto;border-collapse:collapse"> <colgroup> <col style="width:1px;"> ... </tbody></table> `, // 第三份报表 ` <table id="report1" cellspacing="0" cellpadding="0" style="width:1734px;table-layout:fixed;margin:auto;border-collapse:collapse"> <colgroup> <col style="width:76px;"> ... </tbody></table> `, } for _, htmlStr := range htmls { datas, err := extractTaxData(htmlStr) if err != nil { fmt.Println("解析出错:", err) continue } for _, d := range datas { fmt.Printf("税种: %s, 税目: %s, 应补(退)税额: %s\n", d.TaxType, d.TaxItem, d.TaxAmount) } fmt.Println("----------------------------") } } func main() { // 仅示例运行 TestExtractData(nil) }

要点说明:

  • 通过 taxTypeKeywordstaxItemKeywordstaxAmtKeywords 来匹配表头的不同可能名称。
  • 一旦找到了「税种/税目/应补(退)税额」的列索引,就记录下来,后续数据行从对应索引取文本。
  • 根据实际业务场景,你还可以做更复杂的判断,如多表头、跨行表头、或需要合并单元格内容等。
  • 代码中保留了对“合计”“经办人”“受理人”“代理机构”等关键字的简单排除,以避免把这些行误识别成税种数据行。

这样,即使三份 HTML 的报表各自用的表头文字略有差异,也能通过关键词数组实现较为通用的解析。

Pregunta

data都是空的,也就是说都没有获取到

Pensamiento

Mapping HTML structure

I’m mapping out the HTML structure, noting the column name "应补(退)税额" and ensuring it aligns with the parsed data. The snippet matches perfectly, confirming a correct match.

Taking a closer look

I’m noting the significance of full and half-width parentheses while carefully considering whitespace or special unicode characters that might inadvertently affect text matching.

Mapping centralized data

I’m considering if the code might bypass the row with "应补(退)税额" by mistakenly treating the first row as the header, despite the data line being accurate.

Tracking columns

I'm piecing together the logic for identifying columns with specific criteria and ensuring the code can handle full width parentheses "(退)" in the HTML.

Adjusting my approach

I’m focusing on enhancing the code to handle Chinese parentheses "(退)" and considering unifying them to English parentheses, ensuring the parsing accurately aligns with the user's HTML data.

Thought about tax data extraction improvements,持续 1m 1s

Respuesta

在这些示例表格里,“应补(退)税额”普遍使用了中文全角括号 ),而你的代码里若只写了英文半角括号( () ),就会导致关键字匹配不到,从而无法定位到对应的列。于是,表头行就找不到,“data”自然也就都是空的。

下面给出几个排查与修正的方向,帮你解决“抓不到数据”这个问题。


1. 关键字包含中文括号与英文括号

如果表格中出现的是中文括号,那么请在关键词里也加上这一版。例如:

go
var taxAmtKeywords = []string{ "应补(退)税额", // 注意这里是中文括号 "本期应补(退)税额", "应补(退)税额", // 如果有英文括号,就加上 "本期应补(退)税额", "本期应补(退)税(费)额", }

把**“应补(退)税额”“应补(退)税额”都放进去,再配合 strings.Contains(),就能兼容中文括号英文括号**。如果表格还有别的写法,也可以一并补进去,比如带空格、带特殊字符等等。

同理,“税种”/“税目”/“征收项目”/“征收品目” 的列名,也可能出现类似情况,可以一并检查。


2. 可以统一把中文括号转换为英文括号再匹配

有些场景可能表格的标题里时常混用半角/全角括号,为避免不断加关键词,可以先做一次括号统一。比如:

go
func normalizeParentheses(text string) string { // 把中文括号替换为英文括号 text = strings.ReplaceAll(text, "(", "(") text = strings.ReplaceAll(text, ")", ")") return text }

然后在匹配前,先把单元格的文本做一次 text = normalizeParentheses(text),这样所有括号都变成半角,后续只要写 "应补(退)税额" 就行了:

go
text := normalizeParentheses(cell.Text()) if strings.Contains(text, "应补(退)税额") { // ... }

3. 检查是否真的找到了“表头行”

有时候表头行跨行或跨列,或者在代码里因为“包含关键字”逻辑导致没能在同一个 <tr> 里找到“税种/征收项目”、“税目/征收品目”、“应补(退)税额”,从而无法定位。常见的情况:

  • 有些报表在多行里才拼出完整列名,比如第一行写“税款所属期”,第二行写“起”、“止”。
  • 或者“税种”、“税目”并不在同一行,而是分别位于表头多行合并列中。

如果你的报表表头是跨行/跨列,就需要更复杂的处理方式;而你的“找到表头行”逻辑需要做相应调整,可能要扫描多行才能确定某一列的真正列名。


4. 确认是否不小心把真正表头给过滤掉了

有时表头行里也会出现类似“合计”或者“经办人”之类关键字(尤其是定制化表格)。如果你的代码里写了

go
if strings.Contains(fullText, "经办人") || strings.Contains(fullText, "合计") { return }

就会把那一行过早过滤掉,表头自然也就找不到了。要仔细确认过滤条件别写得太泛。


5. 示例修改

基于上面的思路,这里给出一个最常见的“中文括号问题”修复示例:在 taxAmtKeywords 里补充中文括号的写法,或统一括号再匹配。假设最简单的方法是直接把中文括号也加上,那么大致改法如下:

go
// 添加多种可能的关键词 var taxAmtKeywords = []string{ // 中文括号 "应补(退)税额", "本期应补(退)税额", // 英文括号 "应补(退)税额", "本期应补(退)税额", // 如果有其它形态比如:本期应补(退)税(费)额,也可以一并加上 "本期应补(退)税(费)额", }

并确保你没有在找到表头那一行之前就把它过滤掉,也没在匹配表头时使用仅带英文括号的字符串做 strings.Contains。然后再试一下,就应该可以正确捕获到表格里的行。


总结

  • 最常见的问题:关键字不一致,尤其是“中文括号” vs “英文括号”。
  • 解决办法:要么关键词都加上几种版本,要么先把文本统一处理(如统一把中文括号替换为英文括号)。
  • 如果依旧空:再进一步排查是否是表头行跨行/跨列,导致没有在同一个 <tr> 找到三个关键词,需要更复杂的匹配。

通常,上面这些方法即可解决大多数“解析结果为空”的情况。祝你调试顺利!

Compartir este Q&A