即使设置高/无限制,“列表索引超出范围”也会出错

时间:2014-10-05 06:08:23

标签: python list indexing range reddit

这不是我的代码,只是有人试图让它工作。 Original here该脚本首先创建所有链接的.csv文件,然后使用相应的书签数据将其转换为html。问题是它不断吐出超出范围的"列表索引"错误。如果我将限制设置为低于20或50的值,那么一切都按预期工作。 .csv文件为938行,将限制设置为1000也不起作用。

来自命令行的错误消息。

 File "export-saved.py", line 72, in <module>
    main()   
   File "export-saved.py", line 68, in main
    converter.convert()   
   File "export-saved.py", line 38, in convert
    urls = self.parse_urls()   
   File "export-saved.py", line 30, in parse_urls
    folder = url[3].strip() 
   IndexError: list index out of range

什么设定了我可以接受的数据范围?

在旁注中,有趣的是看到Reddit显示的保存链接少于实际链接。

附录:好的我想我找出了问题的根源。所以reddit有比它显示的链接更多的链接。实际上它只显示了大约300个链接,但在他们的服务器中有大约936个链接。当&#34;时间&#34;参数定义为&#34; all&#34;这意味着显示的300个链接因此600个其他链接超出范围。我怎么能包括它们呢?如果那就是问题。

#!/usr/bin/env python
'''
export-saved.py
Christopher Su
Exports saved Reddit posts into a HTML file that is ready to be imported into Google Chrome.
'''

import csv
import os
import sys
from time import time

import praw
import AccountDetails

## Converter class from https://gist.github.com/raphaa/1327761
class Converter():
    """Converts a CSV instapaper export to a Chrome bookmark file."""

    def __init__(self, file):
        self._file = file

    def parse_urls(self):
        """Parses the file and returns a folder ordered list."""
        efile = open(self._file)
        urls = csv.reader(efile, dialect='excel')
        parsed_urls = {}
        urls.next()
        for url in urls:
            folder = url[3].strip()
            if folder not in parsed_urls.keys():
                parsed_urls[folder] = []
            parsed_urls[folder].append([url[0], url[1]])
        return parsed_urls

    def convert(self):
        """Converts the file."""
        urls = self.parse_urls()
        t = int(time())
        content = ('<!DOCTYPE NETSCAPE-Bookmark-file-1>\n'
                   '<META HTTP-EQUIV="Content-Type" CONTENT="text/html;'
                   ' charset=UTF-8">\n<TITLE>Bookmarks</TITLE>'
                   '\n<H1>Bookmarks</H1>\n<DL><P>\n<DT><H3 ADD_DATE="%(t)d"'
                   ' LAST_MODIFIED="%(t)d">Reddit</H3>'
                   '\n<DL><P>\n' % {'t': t})
        for folder in urls.keys():
            content += ('<DT><H3 ADD_DATE="%(t)d" LAST_MODIFIED="%(t)d">%(n)s'
                        '</H3>\n<DL><P>\n' % {'t': t, 'n': folder})
            for url in urls[folder]:
                content += ('<DT><A HREF="%s" ADD_DATE="%d">%s</A>\n'
                            % (url[0], t, url[1]))
            content += '</DL><P>\n'
        content += '</DL><P>\n' * 3
        ifile = open('chrome-bookmarks.html', 'w')
        ifile.write(content)

def main():
    r = praw.Reddit(user_agent='Subot 1.0')
    r.login(AccountDetails.REDDIT_USERNAME, AccountDetails.REDDIT_PASSWORD)
    export_csv = 'URL,Title,Selection,Folder\n'
    for i in r.user.get_saved(limit=500, time='all'):
        if not hasattr(i, 'title'):
           i.title = i.link_title
        export_csv += ("%s,%s,,%s\n" % (i.permalink.encode('utf-8'), i.title.encode('utf-8'), str(i.subreddit)))
    with open("export-saved.csv", "w") as f:
        f.write(export_csv)
    converter = Converter("export-saved.csv")
    converter.convert()
    sys.exit(0)

if __name__ == "__main__":
    main()

1 个答案:

答案 0 :(得分:0)

主要功能中有拼写错误。 url 3正在尝试从csv中的一行中获取该索引中的值。

但是看看main函数中的第二个export_csv行。字符串格式错误 - 它忽略了&#34;选择&#34;柱。在两个连续的逗号之间添加一个%s,并为字符串格式化解压缩一个值,你应该好好去。

(请仔细阅读下面的编辑,因为错误的真正来源确实在字符串格式中,但比我原先想象的更微妙)


编辑:更多细节传入。当你提出问题时,这可能比你想知道的要多得多吗?&#34;你打开包装是什么意思?&#34;跳到最后吃鱼,或者一直阅读以了解更多关于钓鱼的信息。

我认为错误发生在main函数中。为了调试这个,我将自己解决它并对其进行一些更改。我会像这样重写main函数:

def debug_main():
    r = praw.Reddit(user_agent='Subot 1.0')
    r.login('USERNAME', 'PASSWORD')
    export_csv = 'URL,Title,Selection,Folder\n'
    for i in r.get_subreddit('all').get_hot(limit=5):
        if not hasattr(i, 'title'):
           i.title = i.link_title
        export_csv += ("%s,%s,,%s\n" % (i.permalink.encode('utf-8'),
                                        i.title.encode('utf-8'),
                                        str(i.subreddit)))

    with open("export-saved.csv", "w") as f:
        f.write(export_csv)

    print 'Complete'
    return True

现在不是一次性完成所有事情,这个函数只是为我们写CSV文件然后停止。请记住,当我们将CSV文件传递给转换器时,我们会遇到错误。这让我觉得我们会在CSV中看到一些格式错误的数据,但我们会发现。

我还做了另外一个更改,仅用于调试目的:

for i in r.get_subreddit('all').get_hot(limit=5):

原始的for i in r.user.get_saved(limit=500, time='all'):是我们想要在制作中使用的 - 但我的个人Reddit帐户没有任何已保存的帖子,所以它对我没有多大帮助。我们最终仍在迭代PRAW提交对象,这对调试这些东西很重要。

现在让我们将此文件保存为prawbot.py,在同一目录中创建一个名为export-saved.csv的文件,并打开一个shell /终端进行一些pythoning。确保您与prawbot.py位于同一目录中,然后启动python shell。

让我们导入我们的prawbot,看看他是怎么做的:

>> from prawbot import *
>> debug_main()
Complete
True

到目前为止,这么好。我们将Reddit的五个最热门提交内容导出为CSV(请记住:我们可以通过交换该行来导出我们最终想要的500个已保存的提交内容)。让我们打开CSV,看看它是什么样的。

oh god

好的,这既令人沮丧又有畸形。看看第三行的值是如何出错的?一次看一行原始代码:

export_csv = 'URL,Title,Selection,Folder\n'

这是一个结尾处带换行符的字符串。正如您在CSV文件中看到的那样,这是&#34;标题行。&#34;最后有一个换行符,所以当我们添加到这个字符串时,我们将添加到&#34;下一行。&#34;有些CSV模块可能更优雅地做到这一点,但我们在这里谈论的是原始代码。

for i in r.get_subreddit('all').get_hot(limit=5):

这将获得五个PRAW提交对象供我们使用。我们是否有五个热门提交或五百个保存的提交,PRAW提交对象是PRAW提交对象。这个函数应该能够处理我们填充的任何类型的提交。

我们现在正在迭代每个提交对象:

if not hasattr(i, 'title'):
       i.title = i.link_title

这是为了确保我们始终拥有i.title的值,但此行存在问题:PRAW提交对象始终具有title属性。这实际上并没有做任何事情。

好的,现在下一位将添加到我们的export_csv字符串。

    export_csv += ("%s,%s,,%s\n" % (i.permalink.encode('utf-8'),
                                    i.title.encode('utf-8'),
                                    str(i.subreddit)))

如果你有一个字符串,你对它+=,那意味着&#34;这个字符串现在等于原始字符串加上其他东西。&#34;所以:

>> a = 'cat'
>> b = 'dog'
>> a += b
>> print a
'catdog'

我们现在正在使用的一些代码是在&#34;下面添加一行&#34;我们创建的标题行(我说&#34;在&#34下面;因为\n表示&#34;在此字符串的末尾,放到新行)。具体来说,它正在添加此字符串:

"%s,%s,,%s\n"

那些%s的东西意味着&#34;在这个字符串之后找一个%并用我之后找到的值替换我。&#34;所以你可以这样做:

>>print "%s %s %s %s %s %s" % ("I", "think", "python", "is", "really", "great") 
I think python is really great

好的,那么我们的字符串中的%s被替换为什么?看一下%之后的值。我们可以看到第一个%s被提交的永久链接替换,第二个%s是提交的标题,第三个%s是提交的子编辑。

啊,废话。我们的标题行有四个值:URL,标题,选择和文件夹。但我们添加的每一行只是解包三个值 - URL,Title和Subreddit。 "%s,%s,,%s\n"中的两个连续逗号基本上表示&#34;当您正在撰写此行时跳过列,&#34;这意味着Selection下的条目始终为空。您可以在我们上面创建的CSV文件的图片中看到 - 除一个案例外,选择列为空。

现在,看看其余的代码 - 这可能是故意的。最终让我们失望的indexerror正在寻找url[3],这将对应于&#34;文件夹&#34;柱。空白单元格位于url[2],似乎实际上并没有被使用。我无法理解为什么作者会包含一个总是故意空白的行,但是谁真正知道在人们的心中有什么罪恶?

好的,再看看我们的示例CSV。数据在第三行格式错误。看看最初的Reddit线程,真正的标题就是&#34;发现一个棒棒糖留在存储中,蚂蚁吃了它并将包装留在后面。&#34;

我们正在处理CSV,这意味着&#34;逗号分隔值,&#34;这意味着解析器会在任何包含逗号的提交中窒息。在这种情况下,&#34;发现了一个留在存储中的棒棒糖&#34;存储为一个值,并且&#34;将包装留在后面&#34;被存储为下一个单元格中的值。然后我们跳过一个单元格,就像我们在完成标题后一样,然后我们在NEXT单元格中编写了subreddit名称。

你提到原始脚本在20-50次提交时工作正常,但是在比这大得多的任何事情上都窒息了。我打赌它第一次用逗号进入标题时会窒息。

如果您感到无聊,请跳至此处

所以,我修改了原来的答案。原始脚本确实离开了&#34;选择&#34;列空白,但似乎是神秘而有意的设计。真正的问题是,无论何时用逗号分隔标题,逗号分隔文件都将执行逗号分隔文件的设计 - 单独的值。如果我们在输入之前删除标题中的逗号,那么事情可能会正常工作。

我们之前确定,这不做任何事情:

if not hasattr(i, 'title'):
       i.title = i.link_title

每个提交对象都有一个title属性。这是给定的,你可以指望它在那里。让我们用这个替换这些行:

title = i.title.replace(',', ' ')

这会占用标题中的每个,并用空格替换它,然后将重新格式化的字符串分配给title

现在我们去这里:

        export_csv += ("%s,%s,,%s\n" % (i.permalink.encode('utf-8'),
                                        i.title.encode('utf-8'),
                                        str(i.subreddit)))

我们想添加新重新格式化的标题,而不是提交的原始标题。我们将改为:

        export_csv += ("%s,%s,,%s\n" % (i.permalink.encode('utf-8'),
                                        title.encode('utf-8'), #note the difference - no i
                                        str(i.subreddit)))

我们的debug_main()函数现在看起来像这样:

def debug_main():
    r = praw.Reddit(user_agent='Subot 1.0')
    r.login('USERNAME', 'PASSWORD')
    export_csv = 'URL,Title,Selection,Folder\n'
    for i in r.get_subreddit('all').get_hot(limit=5):
        title = i.title.replace(',', ' ')
        export_csv += ("%s,%s,,%s\n" % (i.permalink.encode('utf-8'),
                                        title.encode('utf-8'),
                                        str(i.subreddit)))

    with open("export-saved.csv", "w") as f:
        f.write(export_csv)

    print 'Complete'
    return True

跳回你的python shell并将其关闭。如果您收到权限被拒绝错误,则可能需要sudo python

>> from prawbot import *
>> debug_main()
Complete
True

很酷,现在让我们查看CSV文件。

much better without all that punctuation

看起来不错。现在一切都像它应该的那样排队。如果您查看第三行(here)中的原始Reddit提交,您会看到标题中有大量逗号 - 但它们不再导致问题。将limit=5更改为limit=1000并且它仍然可以使用,但它肯定会花一些时间。

让我们跳回原始代码并将真正的main()函数更改为我们的调试版本。

def main():
    r = praw.Reddit(user_agent='Subot 1.0')
    r.login('USERNAME', 'PASSWORD')
    export_csv = 'URL,Title,Selection,Folder\n'
    for i in r.user.get_saved(limit=500, time='all'):
        title = i.title.replace(',', ' ')
        export_csv += ("%s,%s,,%s\n" % (i.permalink.encode('utf-8'),
                                        title.encode('utf-8'),
                                        str(i.subreddit)))

    with open("export-saved.csv", "w") as f:
        f.write(export_csv)
    converter = Converter("export-saved.csv")
    converter.convert()
    sys.exit(0)

我要停在这里,因为这有望解决你遇到的索引错误。但我会注意到,parse_urlconvert方法正在打开文件而不是在它们通过后关闭它们,这让我绝对疯狂。