【问题标题】:Use python requests to download CSV使用 python 请求下载 CSV
【发布时间】:2016-05-24 02:25:27
【问题描述】:

这是我的代码:

import csv
import requests
with requests.Session() as s:
    s.post(url, data=payload)
    download = s.get('url that directly download a csv report')

这使我可以访问 csv 文件。我尝试了不同的方法来处理下载:

这将在一个字符串中给出 csv 文件:

print download.content

这会打印第一行并返回错误:_csv.Error: new-line character seen in unquoted field

cr = csv.reader(download, dialect=csv.excel_tab)
for row in cr:
    print row

这将在每一行打印一个字母,但不会打印整个内容:

cr = csv.reader(download.content, dialect=csv.excel_tab)
for row in cr:
    print row

我的问题是:在这种情况下读取 csv 文件的最有效方法是什么。 以及如何下载。

谢谢

【问题讨论】:

    标签: python csv python-requests


    【解决方案1】:

    要转换为 Pandas DataFrame:

    from io import StringIO
    text=StringIO(download.content.decode('utf-8'))
    df=pd.read_csv(text)
    

    【讨论】:

      【解决方案2】:

      我喜欢The Aelfinnaheld 的回答。我只能通过缩短一点、删除多余的部分、使用真实的数据源、使其与 2.x 和 3.x 兼容以及保持其他地方看到的高水平内存效率来改进它们:

      import csv
      import requests
      
      CSV_URL = 'http://web.cs.wpi.edu/~cs1004/a16/Resources/SacramentoRealEstateTransactions.csv'
      
      with requests.get(CSV_URL, stream=True) as r:
          lines = (line.decode('utf-8') for line in r.iter_lines())
          for row in csv.reader(lines):
              print(row)
      

      太糟糕了 3.x 在 CSV 方面不太灵活,因为迭代器必须发出 Unicode 字符串(而 requests 发出 bytes),而仅 2.x 的版本——for row in csv.reader(r.iter_lines()):——更像 Pythonic(更短且更更容易阅读)。无论如何,请注意,上面的 2.x/3.x 解决方案无法处理 OP 所描述的情况,即在读取的数据中发现 NEWLINE 未引用。

      对于 OP 关于下载(相对于处理)实际 CSV 文件的部分问题,这是另一个执行 、2.x 和 3.x 的脚本- 兼容、最小、可读和节省内存:

      import os
      import requests
      
      CSV_URL = 'http://web.cs.wpi.edu/~cs1004/a16/Resources/SacramentoRealEstateTransactions.csv'
      
      with open(os.path.split(CSV_URL)[1], 'wb') as f, \
              requests.get(CSV_URL, stream=True) as r:
          for line in r.iter_lines():
              f.write(line+'\n'.encode())
      

      【讨论】:

      • 最佳答案!适用于最新版本的 Python。
      • 为了支持最广泛的受众,它应该适用于所有当前部署的 Python 版本,而不仅仅是最新的......不过谢谢! :-)(最低版本为 2.6)
      • 对于下载,我认为大多数用户会想要f.write(line + '\n'.encode()) - 目前您的示例写了一大行,CSV 阅读器不容易将其加载回内存
      • 感谢您发现这一点。我通常会尝试利用带有文本文件的“免费”\n,但忽略了值得尊敬的库出于数据清理的目的而删除了这些文件,要求我们在创建我们自己的文件时将它们添加回来 w/这样的数据。
      【解决方案3】:

      为了简化这些答案并提高下载大文件时的性能,下面的方法可能会更有效。

      import requests
      from contextlib import closing
      import csv
      from codecs import iterdecode
      
      url = "http://download-and-process-csv-efficiently/python.csv"
      
      with closing(requests.get(url, stream=True)) as r:
          reader = iterdecode(csv.reader(r.iter_lines(), 'utf-8'), 
                              delimiter=',', 
                              quotechar='"')
          for row in reader:
              print(row)
      

      通过在 GET 请求中设置 stream=True,当我们将 r.iter_lines() 传递给 csv.reader() 时,我们会将 generator 传递给 csv.reader()。通过这样做,我们使 csv.reader() 能够使用 for row in reader 懒惰地遍历响应中的每一行。

      这避免了在我们开始处理之前将整个文件加载到内存中,从而大大减少了大文件的内存开销

      【讨论】:

      • 我还必须import codecs 并将r.iter_lines() 包装在codecs.iterdecode() 中,如下所示:codecs.iterdecode(r.iterlines(), 'utf-8') ... 为了解决bytestr 的问题,Unicode 解码问题和普遍的新线问题。
      • 谢谢@IrvinH。 ,我遇到了同样的问题。顺便说一句,它应该是 r.iter_lines() 你错过了下划线。
      • 在 Python 3.7 上,这会导致:错误:迭代器应该返回字符串,而不是字节(您是否以文本模式打开文件?)
      【解决方案4】:

      这对我很有效:

      from csv import DictReader
      
      f = requests.get('https://somedomain.com/file').content.decode('utf-8')
      reader = DictReader(f.split('\n'))
      csv_dict_list = list(reader)
      

      【讨论】:

        【解决方案5】:

        Python3 支持的代码

            with closing(requests.get(PHISHTANK_URL, stream=True})) as r:
                reader = csv.reader(codecs.iterdecode(r.iter_lines(), 'utf-8'), delimiter=',', quotechar='"')
                for record in reader:
                   print (record)
        

        【讨论】:

          【解决方案6】:

          我使用这段代码(我使用 Python 3):

          import csv
          import io
          import requests
          
          url = "http://samplecsvs.s3.amazonaws.com/Sacramentorealestatetransactions.csv"
          r = requests.get(url)
          r.encoding = 'utf-8'  # useful if encoding is not sent (or not sent properly) by the server
          csvio = io.StringIO(r.text, newline="")
          data = []
          for row in csv.DictReader(csvio):
              data.append(row)
          

          【讨论】:

            【解决方案7】:

            以下方法对我很有效。我也不需要使用csv.reader()csv.writer() 函数,我觉得这使代码更干净。代码兼容Python2和Python 3。

            from six.moves import urllib
            
            DOWNLOAD_URL = "https://raw.githubusercontent.com/gjreda/gregreda.com/master/content/notebooks/data/city-of-chicago-salaries.csv"
            DOWNLOAD_PATH ="datasets\city-of-chicago-salaries.csv" 
            urllib.request.urlretrieve(URL,DOWNLOAD_PATH)
            

            注意 - 六是帮助编写与 Python 2 和 Python 3 兼容的代码的包。有关六的更多详细信息,请参阅 - What does from six.moves import urllib do in Python?

            【讨论】:

              【解决方案8】:

              您还可以使用DictReader 来迭代{'columnname': 'value', ...} 的字典

              import csv
              import requests
              
              response = requests.get('http://example.test/foo.csv')
              reader = csv.DictReader(response.iter_lines())
              for record in reader:
                  print(record)
              

              【讨论】:

                【解决方案9】:

                这应该会有所帮助:

                import csv
                import requests
                
                CSV_URL = 'http://samplecsvs.s3.amazonaws.com/Sacramentorealestatetransactions.csv'
                
                
                with requests.Session() as s:
                    download = s.get(CSV_URL)
                
                    decoded_content = download.content.decode('utf-8')
                
                    cr = csv.reader(decoded_content.splitlines(), delimiter=',')
                    my_list = list(cr)
                    for row in my_list:
                        print(row)
                

                输出样本:

                ['street', 'city', 'zip', 'state', 'beds', 'baths', 'sq__ft', 'type', 'sale_date', 'price', 'latitude', 'longitude']
                ['3526 HIGH ST', 'SACRAMENTO', '95838', 'CA', '2', '1', '836', 'Residential', 'Wed May 21 00:00:00 EDT 2008', '59222', '38.631913', '-121.434879']
                ['51 OMAHA CT', 'SACRAMENTO', '95823', 'CA', '3', '1', '1167', 'Residential', 'Wed May 21 00:00:00 EDT 2008', '68212', '38.478902', '-121.431028']
                ['2796 BRANCH ST', 'SACRAMENTO', '95815', 'CA', '2', '1', '796', 'Residential', 'Wed May 21 00:00:00 EDT 2008', '68880', '38.618305', '-121.443839']
                ['2805 JANETTE WAY', 'SACRAMENTO', '95815', 'CA', '2', '1', '852', 'Residential', 'Wed May 21 00:00:00 EDT 2008', '69307', '38.616835', '-121.439146']
                [...]
                

                相关问题与答案:https://stackoverflow.com/a/33079644/295246


                编辑:如果您需要下载大文件(即stream=True),其他答案很有用。

                【讨论】:

                • 有必要将整个东西读入内存吗?这似乎不可扩展。
                【解决方案10】:

                如果文件非常大,您可以使用请求的 iter_lines 方法更新接受的答案

                import csv
                import requests
                
                CSV_URL = 'http://samplecsvs.s3.amazonaws.com/Sacramentorealestatetransactions.csv'
                
                with requests.Session() as s:
                    download = s.get(CSV_URL)
                
                    line_iterator = (x.decode('utf-8') for x in download.iter_lines(decode_unicode=True))
                
                    cr = csv.reader(line_iterator, delimiter=',')
                    my_list = list(cr)
                    for row in my_list:
                        print(row)
                

                【讨论】:

                  【解决方案11】:

                  通过一点搜索,我知道文件应该以通用换行模式打开,你不能直接使用响应内容(我猜)。

                  要完成任务,您可以将下载的内容保存到临时文件,或在内存中处理。

                  另存为文件:

                  import requests
                  import csv
                  import os
                  
                  temp_file_name = 'temp_csv.csv'
                  url = 'http://url.to/file.csv'
                  download = requests.get(url)
                  
                  with open(temp_file_name, 'w') as temp_file:
                      temp_file.writelines(download.content)
                  
                  with open(temp_file_name, 'rU') as temp_file:
                      csv_reader = csv.reader(temp_file, dialect=csv.excel_tab)
                      for line in csv_reader:
                          print line
                  
                  # delete the temp file after process
                  os.remove(temp_file_name)
                  

                  在内存中:

                  (待更新)

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2021-08-06
                    • 1970-01-01
                    • 2021-09-04
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多