从python中的URL读取.csv数据:额外的行

时间:2014-06-10 01:23:21

标签: python url csv codec

stackoverflow上的第一篇文章,以及python的新手。我正在尝试从wunderground的某个位置读取天气数据。它应该是直截了当的:

import csv
import urllib2   
url = 'http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KMDLAURE4&day=9&month=6&year=2013&graphspan=day&format=1'
response = urllib2.urlopen(url)
cr = csv.reader(response)

然而,当我这样做时,我在所有数据之间得到了额外的一行。因此,如果我检查.csv输出的前几行,我会得到以下结果:

    cr.next()
    Out[210]: []

    cr.next()
    Out[211]: 
    ['Time',
   blah blah blah fields redacted
     'DateUTC<br>']

    cr.next()
    Out[212]: 
    ['2013-06-09 00:07:00',
      blah blah blah data redacted
     '2013-06-09 04:07:00',
     '']

    cr.next()
    Out[213]: ['<br>']

    cr.next()
    Out[214]: 
    ['2013-06-09 00:22:00',
     blah blah blah data redacted,
     '2013-06-09 04:22:00',
     '']

我可以循环遍历文件,扔掉所有其他行,或检查该行是否只包含&lt; br&gt;并摆脱它。对我来说,这是一个不优雅的解决方案,因为真正的“问题”是由于阅读文本。这似乎是“打开二进制”或编解码器问题,但我该如何检查?谢谢!

2 个答案:

答案 0 :(得分:1)

必须有办法告诉wunderground返回真正的CSV格式,而不是HTML。但是,您可以通过跳过那些太短的行来解决它:

import csv
import urllib2   
url = 'http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KMDLAURE4&day=9&month=6&year=2013&graphspan=day&format=1'
response = urllib2.urlopen(url)
cr = csv.reader(response)

for row in cr:
    if len(row) <= 1: continue
    print row

更新

这是一种不同的方法:创建一个类来过滤掉那些不需要的行:

import csv
import urllib2   

class RemoveBlank(object):
    def __init__(self, response):
        self.response = response
    def __iter__(self):
        return self
    def next(self):
        line = '\n'
        while line == '\n' or line == '<br>\n':
            line = next(self.response)
        return line

url = 'http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=KMDLAURE4&day=9&month=6&year=2013&graphspan=day&format=1'
response = urllib2.urlopen(url)
cr = csv.reader(RemoveBlank(response))

for row in cr:
    print row

这次,不是将响应对象提供给cdv.reader,而是将该响应对象包装在RemoveBlank对象中。请注意,在Python 3中,该方法应命名为__next__

这种方法的优点是:它使主体保持清洁,因此您可以专注于逻辑。

答案 1 :(得分:0)

首先,这不是您问题的答案。这是使用不同方法解决问题的替代解决方案。

我使用相同的API,获得相同信息的更好方法是使用Larry Lustig评论的JSON响应。

from json import loads
from urllib import urlopen

url = 'http://api.wunderground.com/api/01f4106be8822ff4/history_201300609/q/MD/Laurel.json'
response = loads(urlopen(url).read())

print 'Date', 'Temperature', 'Dew Point', 'Umidity' 
for w in response['history']['observations']:
    print w['date']['pretty'], w['tempi'], w['dewpti'], w['hum']

响应

Date Temperature Dew Point Umidity
12:15 AM EST on January 29, 2013 32.0 32.0 100
12:36 AM EST on January 29, 2013 32.0 32.0 100
12:57 AM EST on January 29, 2013 32.0 32.0 100
1:18 AM EST on January 29, 2013 32.0 32.0 100
1:39 AM EST on January 29, 2013 32.0 32.0 100

在官方API doc中,您可以找到更多信息。

在这里,您的问题的解决方案。这是一种将CSV文件作为字典读取的方法。

from urllib import urlopen
from csv import DictReader
from StrinIO import StringIO

url = 'http://api.wunderground.com/api/01f4106be8822ff4/history_201300609/q/MD/Laurel.json'
response = StringIO(urlopen(url).read())
weather = DictReader(response)

# Skips header
weather.next()

for w in weather:
    print w

响应

{None: ['2013-06-09 00:07:00', '18.5', '17.2', '1015.8', 'WNW', '285', '0.0', '-1607.4', '92', '-2539.7', '', '', '0.0', 'weatherlink.com 1.10', '2013-06-09 04:07:00', '']}
{None: ['<br>']}
{None: ['2013-06-09 00:22:00', '18.6', '17.8', '1015.8', 'WNW', '285', '0.0', '-1607.4', '93', '-2539.7', '', '', '0.0', 'weatherlink.com 1.10', '2013-06-09 04:22:00', '']}

再次,你的结果是dict。更容易处理。