>>469
lineは1行なんだから、<td>.*</td>¥n<td>.*</td>のように改行を含むパターンにマッチする訳がない。
body.each {|line|
puts line # ←これを追加して考えてみて
if /..../
print $1, $2
end
}

結論からいうと、この場合は1行ずつ読み込むのではなく、ファイル全体を読み込んでからパターンマッチさせる。
あと正規表現は「.*」(最長一致)ではなく「.*?」(最短一致)をつかうべし。
詳しくはマニュアルの正規表現のページをどうぞ。
s = File.read("index.html")
s.scan(/<td>気温<¥/td>¥s*<td>(.*?)<¥/td>¥s*<td>(.*?)<¥/td>/) do
puts "#{$1}, #{$2}"
end

あとこの場合は、いったん /<tr>(.*?)<¥/tr>/m にマッチさせておいてから、それから /<td>.*?<¥/td>/ で切り出したほうが柔軟性がある。
s.scan(/<tr>.*?<¥/tr>/m) do
record = $&
record =~ /<td>.*?<¥/td>¥s*<td>(.*?)<¥/td>¥s*<td>(.*?)<¥/td>/
puts "#{$1}, #{$2}"
end