这不是我的代码,只是有人试图让它工作。 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()
答案 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,看看它是什么样的。
好的,这既令人沮丧又有畸形。看看第三行的值是如何出错的?一次看一行原始代码:
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是提交的子编辑。
"%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文件。
看起来不错。现在一切都像它应该的那样排队。如果您查看第三行(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_url
和convert
方法正在打开文件而不是在它们通过后关闭它们,这让我绝对疯狂。