税务数据提取
Creado el: 14 de enero de 2025
Creado el: 14 de enero de 2025
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
}
textvar 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数据能解析出正确的返回数据:税种 税目 应补退税额 (名称可能不同)
下面给出一个示例的修改方案,思路是:
当然,实际情况可能更复杂,比如部分报表列名不在同一行、表格中有多头表头等,需要更精细的处理。这里给出的示例仅供参考,你可以根据实际业务需求作进一步优化。
gopackage 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) }
要点说明:
taxTypeKeywords
、taxItemKeywords
、taxAmtKeywords
来匹配表头的不同可能名称。这样,即使三份 HTML 的报表各自用的表头文字略有差异,也能通过关键词数组实现较为通用的解析。
data都是空的,也就是说都没有获取到
在这些示例表格里,“应补(退)税额”普遍使用了中文全角括号( (
、)
),而你的代码里若只写了英文半角括号( (
、)
),就会导致关键字匹配不到,从而无法定位到对应的列。于是,表头行就找不到,“data”自然也就都是空的。
下面给出几个排查与修正的方向,帮你解决“抓不到数据”这个问题。
如果表格中出现的是中文括号,那么请在关键词里也加上这一版。例如:
govar taxAmtKeywords = []string{ "应补(退)税额", // 注意这里是中文括号 "本期应补(退)税额", "应补(退)税额", // 如果有英文括号,就加上 "本期应补(退)税额", "本期应补(退)税(费)额", }
把**“应补(退)税额”和“应补(退)税额”都放进去,再配合 strings.Contains()
,就能兼容中文括号和英文括号**。如果表格还有别的写法,也可以一并补进去,比如带空格、带特殊字符等等。
同理,“税种”/“税目”/“征收项目”/“征收品目” 的列名,也可能出现类似情况,可以一并检查。
有些场景可能表格的标题里时常混用半角/全角括号,为避免不断加关键词,可以先做一次括号统一。比如:
gofunc normalizeParentheses(text string) string { // 把中文括号替换为英文括号 text = strings.ReplaceAll(text, "(", "(") text = strings.ReplaceAll(text, ")", ")") return text }
然后在匹配前,先把单元格的文本做一次 text = normalizeParentheses(text)
,这样所有括号都变成半角,后续只要写 "应补(退)税额"
就行了:
gotext := normalizeParentheses(cell.Text()) if strings.Contains(text, "应补(退)税额") { // ... }
有时候表头行跨行或跨列,或者在代码里因为“包含关键字”逻辑导致没能在同一个 <tr>
里找到“税种/征收项目”、“税目/征收品目”、“应补(退)税额”,从而无法定位。常见的情况:
如果你的报表表头是跨行/跨列,就需要更复杂的处理方式;而你的“找到表头行”逻辑需要做相应调整,可能要扫描多行才能确定某一列的真正列名。
有时表头行里也会出现类似“合计”或者“经办人”之类关键字(尤其是定制化表格)。如果你的代码里写了
goif strings.Contains(fullText, "经办人") || strings.Contains(fullText, "合计") { return }
就会把那一行过早过滤掉,表头自然也就找不到了。要仔细确认过滤条件别写得太泛。
基于上面的思路,这里给出一个最常见的“中文括号问题”修复示例:在 taxAmtKeywords
里补充中文括号的写法,或统一括号再匹配。假设最简单的方法是直接把中文括号也加上,那么大致改法如下:
go// 添加多种可能的关键词 var taxAmtKeywords = []string{ // 中文括号 "应补(退)税额", "本期应补(退)税额", // 英文括号 "应补(退)税额", "本期应补(退)税额", // 如果有其它形态比如:本期应补(退)税(费)额,也可以一并加上 "本期应补(退)税(费)额", }
并确保你没有在找到表头那一行之前就把它过滤掉,也没在匹配表头时使用仅带英文括号的字符串做 strings.Contains
。然后再试一下,就应该可以正确捕获到表格里的行。
<tr>
找到三个关键词,需要更复杂的匹配。通常,上面这些方法即可解决大多数“解析结果为空”的情况。祝你调试顺利!