2016-07-08 9 views
3

Ich benutze das Requests-Modul, um csv-Inhalte von einer Web-API zu autorisieren und dann zu ziehen, damit es in Python 2.7 funktioniert. Ich möchte jetzt das gleiche Skript in Python 3.5 aber erleben einige Probleme schreiben:Umwandlung von Bytes in Zeichenfolge übergeben, wenn ich nicht explizit eine Datei in Python 3 öffne

"iterator should return strings, not bytes (did you open the file in text mode?)" 

Die requests.get scheint Bytes und kein String zurück, die, wenn sie zu Python gesehen auf die Codierung Fragen im Zusammenhang zu sein scheint 3 bewegt. x. Der Fehler wird am 3. von letzter Zeile ausgelöst: next(reader). In Python 2.7 war dies kein Problem, da die csv-Funktionen im 'wb'-Modus behandelt wurden.

Dieser Artikel ist sehr ähnlich, aber wie ich bin nicht eine CSV-Datei direkt zu öffnen, kann ich nicht scheinen, um den Antworttext zu zwingen, auf diese Weise codiert werden: csv.Error: iterator should return strings, not bytes

countries = ['UK','US','CA'] 
datelist = [1,2,3,4] 
baseurl = 'https://somewebsite.com/exporttoCSV.php' 

#--- For all date/cc combinations 
for cc in countries: 
    for d in datelist: 

     #---Build API String with variables 
     url = (baseurl + '?data=chart&output=csv' + 
       '&dataset=' + d + 
       '&cc=' + cc) 

     #---Run API Call and create reader object 
     r = requests.get(url, auth=(username, password)) 
     text = r.iter_lines() 
     reader = csv.reader(text,delimiter=',') 

     #---Write csv output to csv file with territory and date columns 
     with open(cc + '_'+ d +'.csv','wt', newline='') as file: 
      a = csv.writer(file) 
      a.writerow(['position','id','title','kind','peers','territory','date']) #---Write header line 
      next(reader) #---Skip original headers 
      for i in reader: 
       a.writerow(i +[countrydict[cc]] + [datevalue]) 
+0

Haben Sie versucht, die Bytes Umwandlung zu eine Python-Zeichenfolge? Wie hier gezeigt? http://StackOverflow.com/Questions/606191/convert-bytes-to-a-python-string – Bamcclur

+0

@Bamcclur Ich habe versucht, '.decode (" utf-8 ")', aber nicht sicher, wo Sie dies setzen, um es zu versuchen aus. An jedem Ort, an dem ich versuche, es einzufügen, heißt es, dass das Objekt nicht über das Attribut decode verfügt? – Steve

+0

Ich denke, es ist, weil Iter_lines() wahrscheinlich eine Liste ist, müssten Sie jede Zeichenfolge dekodieren. Vielleicht kann dies helfen: http://stackoverflow.com/questions/36971345/csv-should-return-strings-not-bytes-error?rq=1 – Bamcclur

Antwort

1

ohne in der Lage zu testen Ihre genaue Szenario, ich glaube, das durch text = r.iter_lines() an sich ändernde lösende sollte:

von einem Byte-String
text = [line.decode('utf-8') for line in r.iter_lines()] 

Dies sollte jede Zeile dekodieren nutzbar csv.reader in einen String eingelesen von r.iter_lines()

Mein Testfall ist wie folgt:

>>> iter_lines = [b'1,2,3,4',b'2,3,4,5',b'3,4,5,6'] 
>>> text = [line.decode('utf-8') for line in iter_lines] 
>>> text 
['1,2,3,4', '2,3,4,5', '3,4,5,6'] 
>>> reader = csv.reader(text,delimiter=',') 
>>> next(reader) 
['1', '2', '3', '4'] 
>>> for i in reader: 
...  print(i) 
... 
['2', '3', '4', '5'] 
['3', '4', '5', '6'] 
+0

Verwendet Python 3.5.2. – Bamcclur

0

Einige Dateien als Bytes eingelesen werden müssen, beispielsweise aus DjangoSimpleUploadedFile, die eine Test Klasse verwendet Bytes nur ist. Hier einige Beispiel-Code von meinem Test-Suite, wie ich habe es funktioniert:

test_code.py

import os 
from django.core.files.uploadedfile import SimpleUploadedFile 
from django.test import TestCase 

class ImportDataViewTests(TestCase): 

    def setUp(self): 
     self.path = "test_in/example.csv" 
     self.filename = os.path.split(self.file)[1] 

    def test_file_upload(self): 
     with open(self.path, 'rb') as infile: 
      _file = SimpleUploadedFile(self.filename, infile.read()) 

     # now an `InMemoryUploadedFile` exists, so test it as you shall! 

prod_code.py

import csv 

def import_records(self, infile): 
    csvfile = (line.decode('utf8') for line in infile) 
    reader = csv.DictReader(csvfile) 

    for row in reader: 
     # loop through file and do stuff!