【问题标题】:Error encountered after executing a print list statement in Python在 Python 中执行打印列表语句后遇到错误
【发布时间】:2021-11-12 09:33:16
【问题描述】:

我是 Python 新手,我的代码遇到了一个奇怪的问题。以下是我遇到问题的代码部分。该代码正在获取一个 csv 文件并将其存储到一个数组中。

import requests

objNSEResponse = requests.get("https://www.nseindia.com" , headers = { "Referer":"https://www.nseindia.com" , "User-Agent":"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"})
objNSECookieJar = objNSEResponse.cookies

objNSEResponse = requests.get("https://www.nseindia.com/api/reportGSM?csv=true" , headers = {"Referer":"https://www.nseindia.com" , "User-Agent":"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"} , cookies = objNSECookieJar)

arrNSEGSMList = map(lambda arrNSEGSMRecord : arrNSEGSMRecord.replace("\"","").split(","), objNSEResponse.content.decode("utf-8-sig").replace("\n\"","\"").split("\n"))

print(list(arrNSEGSMList))

# delete unnecessary values
arrNSEGSMList = numpy.array(list(arrNSEGSMList1))
arrNSEGSMList = numpy.delete(arrNSEGSMList, [0], axis=0)        # delete header row
arrNSEGSMList = numpy.delete(arrNSEGSMList, [2,3,4], axis=1)    # delete all columns except stock symbol and serial number

每当我插入语句:print(list(arrNSEGSMList)),我都会在以下语句:arrNSEGSMList = numpy.delete(arrNSEGSMList, [0], axis=0) 中得到“IndexError:index 0 is out of bounds for axis 0 with size 0”。由于此打印语句,创建了零长度的 numpy 数组。如果我删除打印语句,那么一切都会毫无问题地执行。我在数组“arrNSEGSMList”中得到了我需要的数据。我无法弄清楚它的原因。

【问题讨论】:

  • 您显然是在尝试读取 CSV - 为什么不使用 csv 模块..?

标签: python python-3.x numpy


【解决方案1】:

map在语句中的使用

arrNSEGSMList = map(lambda arrNSEGSMRecord : arrNSEGSMRecord.replace("\"","").split(","), objNSEResponse.content.decode("utf-8-sig").replace("\n\"","\"").split("\n"))

使arrNSEGSMList 成为一个迭代器,可以迭代一次。第一次调用list(arrNSEGSMList) 消耗了迭代器,所以当你第二次尝试执行list(arrNSEGSMList) 时,arrNSEGSMList 中的所有项目都已经被消耗了,你得到一个空列表。

这是一个类似的例子:

In [18]: m = map(len, ['abc', 'def', 'gh', 'ij'])  # Create a map iterator

In [19]: m
Out[19]: <map at 0x11efb9730>

In [20]: type(m)
Out[20]: map

In [21]: list(m)  # Create a list by iterating through the iterator.
Out[21]: [3, 3, 2, 2]

In [22]: list(m)  # The iterator has already been consumed.
Out[22]: []

解决办法是写

arrNSEGSMList = list(map(lambda arrNSEGSMRecord : arrNSEGSMRecord.replace("\"","").split(","), objNSEResponse.content.decode("utf-8-sig").replace("\n\"","\"").split("\n")))

因此您只需将map 转换为列表一次。或者更好的是,将 map 的使用替换为列表理解(正如 @AKX 在评论中所建议的那样):

arrNSEGSMList = [record.replace("\"","").split(",") for record in objNSEResponse.content.decode("utf-8-sig").replace("\n\"","\"").split("\n")]

从那时起,只需使用arrNSEGSMList 即可使用列表。例如

print(arrNSEGSMList)

【讨论】:

  • 感谢您的快速响应并感谢您的解决方案。我想我没有正确理解工作地图功能。但我想我现在明白了。再次感谢。
  • 使用列表解析比使用list(map(lambda 构造更符合pythonic:arrNSEGSMList = [record.replace("\"","").split(",") for record in objNSEResponse.content.decode("utf-8-sig").replace("\n\"","\"").split("\n")]
  • 这也是个好主意。谢谢。
【解决方案2】:

除了map 是一个迭代器引起的实际问题(由另一个答案回答):

  • 由于您要解析 CSV 数据,因此您可能应该使用内置的 csv 模块,而不是手动去除引号和拆分行。
  • 此外,如果您使用Requests Session 发出请求,则无需自己处理cookie。设置默认标题也更容易。
  • 第三,无需使用 Numpy 数组对数据进行切片;只需常规的列表推导和切片即可。

以下是使用这些重新编写您的代码:

import requests
import csv

headers = {
    "User-Agent": "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
    "Referer": "https://www.nseindia.com",
}
with requests.Session() as sess:
    sess.headers.update(headers)
    sess.get("https://www.nseindia.com/").raise_for_status()
    resp = sess.get("https://www.nseindia.com/api/reportGSM?csv=true")
    resp.raise_for_status()
    # The encoding of the response is actually utf-8-sig,
    # so we force the attribute here so `resp.iter_lines()`
    # works as it should.
    resp.encoding = "utf-8-sig"  
    content = list(csv.reader(resp.iter_lines(decode_unicode=True)))

# `[1:]` slices the header line off.
symbol_and_serial = [(r[0], r[1]) for r in content[1:]]
for symbol, serial in symbol_and_serial:
    print(symbol, serial)

打印出来

1 ADROITINFO
2 ALPSINDUS
3 ANTGRAPHIC
4 ASIL

等等

【讨论】:

  • 哇!我今天在 python 中学习新东西。非常感谢
  • 我可以在 with 语句中使用 for 循环或 if 语句吗? (我不知道我的问题是否有意义)。我必须下载一个在证券交易所开市时为前一天生成的文件。所以文件名不同。目前我在循环中生成文件名(包含生成日期),然后发送请求。然后我检查响应。同样在一种情况下,该文件为 zip 格式,包含一个 csv 和一个 xml 文件。
  • 是的——它只是a context manager block 确保请求会话关闭任何延迟连接。我建议将这些不同的数据获取例程包装到不同的函数中。
  • 因为我向同一个网站(不同的 URL)发出多个请求并从每个响应(csv 和 zips 文件)创建数组/列表。将整个代码放在一个“with 语句”中是否是个好主意。包括创建数组/列表的代码?或者我应该为每个请求启动新会话?谢谢
  • 取决于应用程序。对于将向同一个地方发出多个请求的大型项目,不关闭会话对于更好的性能是有意义的。
猜你喜欢
  • 2017-04-14
  • 1970-01-01
  • 2022-01-12
  • 2021-12-07
  • 2021-09-17
  • 2017-12-17
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多