如何检测并抓取维基百科机场页面的Airlines & Destinations板块数据
解决维基百科机场页面"Airlines & Destinations"板块数据抓取问题
嘿,我之前也做过类似的维基百科数据抓取工作,用Nokogiri确实是个非常合适的选择——直接解析HTML结构比处理维基文本或者靠API的有限返回要灵活得多。下面给你一步步拆解解决方案:
1. 定位目标板块的存在性
维基百科的板块标题都是用<h2>标签包裹的,里面的<span>会带有mw-headline类,所以我们可以用XPath精准定位"Airlines & Destinations"板块:
require 'nokogiri' require 'open-uri' require 'json' # 推荐用维基API获取页面HTML,更合规且避免反爬 def get_airport_page_html(airport_title) api_url = "https://en.wikipedia.org/w/api.php?action=parse&page=#{URI.encode(airport_title)}&format=json&prop=text" response = JSON.parse(URI.open(api_url).read) response['parse']['text']['*'] end # 示例:希思罗机场页面 html = get_airport_page_html("Heathrow Airport") doc = Nokogiri::HTML(html) # 定位板块(兼容大小写差异,比如有的页面是小写标题) destinations_h2 = doc.at_xpath( "//h2[span[@class='mw-headline' and translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='airlines & destinations']]" ) if destinations_h2 puts "找到'Airlines & Destinations'板块!" else puts "未找到目标板块,跳过处理" end
这里用translate函数统一转成小写,避免因为页面标题大小写不一致导致定位失败,比精确匹配更鲁棒。
2. 抓取板块内的所有表格
找到目标<h2>后,我们需要抓取它后面的所有表格,直到遇到下一个<h2>(也就是下一个大板块)。可以用XPath的following-sibling结合过滤条件实现:
if destinations_h2 # 获取该板块下的所有表格(直到下一个h2为止) tables = destinations_h2.xpath( "following-sibling::table[preceding-sibling::h2[1] = current()]" ) puts "共找到#{tables.size}个表格" # 遍历处理每个表格 tables.each_with_index do |table, idx| puts "\n=== 处理第#{idx+1}个表格 ===" # 提取表头 headers = table.css('tr:first-child th').map { |th| th.text.strip } puts "表头:#{headers.join(', ')}" # 提取数据行 table.css('tr:not(:first-child)').each do |tr| cells = tr.css('td').map { |td| td.text.strip } puts "数据行:#{cells.join(', ')}" end end end
这个XPath的逻辑是:找到目标<h2>之后的所有<table>,并且这些<table>的前一个最近的<h2>就是目标板块的<h2>,这样就不会把后面其他板块的表格包含进来。即使板块下有Passenger、Cargo这类<h3>子板块,也不会影响——因为我们只以<h2>作为板块边界。
关于你提到的其他思路
- wikipedia-client gem:这个gem主要是处理维基文本(Wikitext),而不是渲染后的HTML,所以确实拿不到结构化的板块和表格数据,放弃是对的。
- 匹配全球航空公司列表:这个思路计算成本太高,而且维基百科的表格格式可能有差异(比如有的会包含代码、航站楼信息),直接解析HTML结构要靠谱得多。
额外提示
- 维基百科的API有请求频率限制,批量处理时记得加延迟(比如每请求一次等待1-2秒),避免被封禁。
- 有些机场页面的表格可能带有
wikitable类,可以在XPath里加上[contains(@class, 'wikitable')]来过滤掉非标准表格。
内容的提问来源于stack exchange,提问作者dsp_099
相关产品推荐
相关产品推荐

