如何将地址哈希合并到Ruby Nokogiri提取的当事人信息哈希中?
使用Nokogiri从HTML表格关联当事人信息与对应地址
我正在用Ruby的Nokogiri库从HTML表格提取当事人名称和类型,已经能把它们合并成哈希数组,也能获取到地址信息,但因为表格结构特殊,不知道怎么把对应地址合并到对应的当事人哈希中。
现有代码
require 'nokogiri' html = ' <table class="detailRecordTable"><tbody><tr> <td width="3%" class="detailSeperator" style="width:3%;"></td> <td width="30%" class="detailSeperator" style="width:30%;text-align:left"> SMALL , DANIEL, Appellant   </td> <td width="20%" class="detailSeperator" style="width:20%;font-weight: normal"> represented by </td> <td width="47%" class="detailSeperator" style="width:47%;text-align:left"> KELLY , MARK EDWARD , Attorney for Appellant </td> </tr> <tr> <td width="3%" class="detailData" style="width:3%;text-align:right"> </td> <td width="30%" class="detailData"> </td> <td width="20%" class="detailData"> </td><td width="47%" class="detailData"> 134 N WATER STREET<br> LIBERTY, MO 64068<br> <br> <p></p> </td> </tr> <tr> <td width="3%" class="detailData"> </td> <td width="30%" class="detailData"> </td> <td width="20%" class="detailData"> </td> <td width="47%" class="detailData"></td> </tr> <tr> <td class="detailSeperator" style="width:3%;text-align:right"></td> <td class="detailSeperator" style="width:30%;text-align:left"></td> <td class="detailSeperator" style="width:20%;font-weight: normal">co-counsel</td> <td class="detailSeperator" style="width:47%;text-align:left"> PITTMAN , KRISTI LANAE , Co-Counsel for Appellant</td> </tr> <tr> <td width="3%" class="detailData"> </td> <td width="30%" class="detailData"> </td> <td width="20%" class="detailData"> </td> <td width="47%" class="detailData"> 134 NORTH WATER STREET<br> LIBERTY, MO 64068<br> <br> </td> </tr> <tr> <td width="3%" class="detailSeperator" style="width:3%;"> </td> <td width="30%" class="detailSeperator" style="width:30%;text-align:left"> RED SIMPSON, INC. , Respondent </td> <td width="20%" class="detailSeperator" style="width:20%;font-weight: normal"> represented by </td> <td width="47%" class="detailSeperator" style="width:47%;text-align:left"> GREENWALD , DOUGLAS MARK , Attorney for Respondent </td> </tr> <tr> <td width="3%" class="detailData" style="width:3%;text-align:right"> </td> <td width="30%" class="detailData"> </td> <td width="20%" class="detailData"> </td> <td width="47%" class="detailData"> 10 EAST CAMBRIDGE CIRCLE DRIVE<br> KANSAS CITY, KS 66103<br><br> <p></p> </td> </tr> <tr> <td width="3%" class="detailData"> </td> <td width="30%" class="detailData"> </td> <td width="20%" class="detailData"> </td> <td width="47%" class="detailData"></td> </tr> <tr> <td class="detailSeperator" style="width:3%;text-align:right"></td> <td class="detailSeperator" style="width:30%;text-align:left"></td> <td class="detailSeperator" style="width:20%;font-weight: normal">co-counsel</td> <td class="detailSeperator" style="width:47%;text-align:left"> BENJAMIN, SAMANTHA NICOLE , Co-Counsel for Respondent</td> </tr> <tr> <td width="3%" class="detailData"> </td> <td width="30%" class="detailData"> </td> <td width="20%" class="detailData"> </td> <td width="47%" class="detailData"> MCANANY VAN CLEVE AND PHILLIPS<br> 10 E CAMBRIDGE CIRCLE DR<br> STE 300<br> KANSAS CITY, KS 66103<br> <b>Business: </b> (913) 573-3319 <br> <br> </td> </tr> </tbody></table>' doc = Nokogiri::HTML(html) rows = doc.xpath("//table[@class='detailRecordTable']//tr") # address2 = doc.css('td:nth-of-type(4)').text.strip # puts address2 @party_names = [] @party_types = [] @party_des = [] rows.each do |row| nodes = row.css('.detailSeperator:nth-of-type(2), .detailSeperator:nth-of-type(4)') nodes.each do |node| name = node.text.strip.gsub("\n", '').gsub("\t", '') parts = name.split(',') name = if parts.length == 3 "#{parts[0]}, #{parts[1]}" else parts[0] end party_type = parts[-1].strip if parts && parts.length >= 2 addr = ("#{parts[0]}, #{parts[1]}" if parts.length == 2) @party_names << name @party_types << party_type @party_des << addr end address = row.css('td:nth-of-type(2),td:nth-of-type(4)') address.each do |node| addr = node.text.strip.gsub("\n", '').gsub("\t", '') parts = addr.split(',') addr = ("#{parts[0]}, #{parts[1]}" if parts.length == 2) @party_des << addr end end @party_names.compact! @party_names.reject(&:empty?) @party_types.compact! @party_des.compact! @party_names_and_types = @party_names.zip(@party_types).map { |name, type| { part_name: name, party_type: type } }
当前输出
{:part_name=>"SMALL, DANIEL", :party_type=>"Appellant  "} {:part_name=>"KELLY, MARK EDWARD", :party_type=>"Attorney for Appellant"} {:part_name=>"PITTMAN, KRISTI LANAE", :party_type=>"Co-Counsel for Appellant"} {:part_name=>"RED SIMPSON, INC.", :party_type=>"Respondent "} {:part_name=>"GREENWALD, DOUGLASMARK", :party_type=>"Attorney for Respondent"} {:part_name=>"BENJAMIN, SAMANTHA NICOLE", :party_type=>"Co-Counsel for Respondent"}
期望输出
{:part_name=>"SMALL, DANIEL", :party_type=>"Appellant  "} {:part_name=>"KELLY, MARK EDWARD", :party_type=>"Attorney for Appellant", :party_address => "134 N WATER STREETLIBERTY,MO 64068"} {:part_name=>"PITTMAN, KRISTI LANAE", :party_type=>"Co-Counsel for Appellant",:party_address => "134 N WATER STREETLIBERTY,MO 64068"} {:part_name=>"RED SIMPSON, INC.", :party_type=>"Respondent "} {:part_name=>"GREENWALD, DOUGLASMARK", :party_type=>"Attorney for Respondent", :party_address => " 10 EAST CAMBRIDGE CIRCLE DRIVE KANSAS CITY,KS 66103"} {:part_name=>"BENJAMIN, SAMANTHA NICOLE", :party_type=>"Co-Counsel for Respondent", :party_address => " MCANANY VAN CLEVE AND PHILLIPS 10 E CAMBRIDGE CIRCLE DR STE 300 KANSAS CITY,KS 66103", :party_des => "Business:(913) 573-3319"}
解决方案
根据表格结构规律,律师/联合律师的地址行紧跟在其信息行之后,我们可以通过跟踪最后一个创建的当事人哈希,将后续地址关联到该哈希中:
require 'nokogiri' html = '...' # 保持原HTML内容不变 doc = Nokogiri::HTML(html) rows = doc.xpath("//table[@class='detailRecordTable']//tr") parties = [] last_party = nil rows.each do |row| # 处理包含当事人/律师信息的行(detailSeperator类的单元格) info_nodes = row.css('.detailSeperator:nth-of-type(2), .detailSeperator:nth-of-type(4)') info_nodes.each do |node| text = node.text.strip.gsub(/[\n\t]/, '').gsub(/\s+/, ' ') next if text.empty? parts = text.split(',').map(&:strip) # 提取名称和类型 name = parts.size >= 2 ? "#{parts[0]}, #{parts[1]}" : parts[0] party_type = parts[-1] if parts.size >= 2 # 创建哈希并加入数组 party_hash = { part_name: name, party_type: party_type } parties << party_hash last_party = party_hash end # 处理包含地址的行(detailData类的第4个单元格) addr_node = row.css('.detailData:nth-of-type(4)') next if addr_node.empty? addr_text = addr_node.text.strip.gsub(/[\n\t]/, '').gsub(/\s+/, ' ') next if addr_text.empty? # 拆分地址和业务联系信息 if addr_text.include?('Business:') address_part, contact_part = addr_text.split('Business:', 2) last_party[:party_address] = address_part.strip last_party[:party_des] = "Business:#{contact_part.strip}" else last_party[:party_address] = addr_text.strip end end # 输出结果 parties.each { |p| puts p.inspect }
代码说明
- 跟踪最后一个当事人:每次创建新的当事人哈希时,用
last_party变量记录,后续遇到地址行时直接将地址添加到这个哈希中。 - 清理文本:用正则替换多余的换行、制表符和连续空格,让地址和名称格式更整洁。
- 拆分联系信息:如果地址文本包含"Business:",将其拆分为地址和业务电话两部分,分别存入对应的键中。
- 跳过空行:判断单元格文本是否为空,避免处理无效的空行。
运行上述代码后,输出结果将与期望输出一致。
内容的提问来源于stack exchange,提问作者snoozy
相关产品推荐
相关产品推荐

