从 Tumblr 打印 20 多个帖子 API

Print more than 20 posts from Tumblr API

下午好,

我是 Python 的新手,但我正在尝试编写一个代码,让我可以下载所有 post(包括 "notes") 从指定的 Tumblr 帐户到我的电脑。

鉴于我缺乏编码经验,我试图找到一个预制脚本来执行此操作。我在 GitHub 上发现了几个很棒的脚本,但其中 none 实际上是 return 来自 Tumblr posts 的注释(据我所知,尽管请纠正我,如果任何人都知道这样做的人!)。

因此,我试着写了自己的脚本。我在下面的代码中取得了一些成功。它从给定的 Tumblr 打印最近的 20 posts(尽管格式相当丑陋——基本上数百行文本都打印到记事本文件的一行中):

#This script prints all the posts (including tags, comments) and also the 
#first 20notes from all the Tumblr blogs.

import pytumblr

# Authenticate via API Key
client = pytumblr.TumblrRestClient('myapikey')

#offset = 0

# Make the request
client.posts('staff', limit=2000, offset=0, reblog_info=True, notes_info=True, 
filter='html')
#print out into a .txt file
with open('out.txt', 'w') as f:
print >> f, client.posts('staff', limit=2000, offset=0, reblog_info=True, 
notes_info=True, filter='html')

但是,我希望脚本连续打印 posts 直到到达指定博客的末尾。

我搜索了这个站点,发现了一个非常相似的问题(Getting only 20 posts returned through PyTumblr),已经被Whosebug用户poke回答了。但是,我似乎无法真正实施 poke 的解决方案以使其适用于我的数据。事实上,当我 运行 以下脚本时,根本没有输出。

import pytumblr

# Authenticate via API Key
client = pytumblr.TumblrRestClient('myapikey')
blog = ('staff')
def getAllPosts (client, blog):
offset = 0
while True:
    posts = client.posts(blog, limit=20, offset=offset, reblog_info=True, notes_info=True)
    if not posts:
        return

    for post in posts:
        yield post


    offset += 20

我应该注意到这个网站上有几个 posts(例如 Getting more than 50 notes with Tumblr API)关于 Tumblr 笔记,他们中的大多数询问如何为每个 post 下载超过 50 个笔记秒。我非常满意每个 post 只有 50 个音符,这是我想增加的 post 的数量。

此外,我已将此 post 标记为 Python,但是,如果有更好的方法来使用另一种编程语言获取我需要的数据,那就更好了。

非常感谢您的宝贵时间!

tl;dr 如果您只想查看答案,它位于标题 A Corrected Version

之后的底部

第二个代码片段是一个生成器,一个接一个地生成 post,因此您必须将它用作循环之类的东西的一部分,然后对输出执行一些操作。这是您的代码,其中包含一些附加代码,这些代码遍历生成器并打印出它返回的数据。

import pytumblr

def getAllPosts (client, blog):
    offset = 0
    while True:
        posts = client.posts(blog, limit=20, offset=offset, reblog_info=True, notes_info=True)
        if not posts:
            return

        for post in posts:
            yield post

        offset += 20

# Authenticate via API Key
client = pytumblr.TumblrRestClient('myapikey')
blog = ('staff')

# use the generator getAllPosts
for post in getAllPosts(client, blog):
    print(post)

但是,该代码中有几个错误。 getAllPosts 不会只产生每个 post,它还会 return 其他东西,因为它会遍历 API 响应,正如你从这个例子中看到的那样,我 运行 在我的 ipython shell.

In [7]: yielder = getAllPosts(client, 'staff')

In [8]: next(yielder)
Out[8]: 'blog'

In [9]: next(yielder)
Out[9]: 'posts'

In [10]: next(yielder)
Out[10]: 'total_posts'

In [11]: next(yielder)
Out[11]: 'supply_logging_positions'

In [12]: next(yielder)
Out[12]: 'blog'

In [13]: next(yielder)
Out[13]: 'posts'

In [14]: next(yielder)
Out[14]: 'total_posts'

发生这种情况是因为 getAllPosts 中的 posts object 是一个字典,它包含的不仅仅是 staff 博客中的每个 post - 它还有诸如博客包含多少 post、博客的描述、上次更新时间等项目。代码 as-is 可能会导致无限循环,因为以下条件:

if not posts:
    return

由于响应结构的原因永远不会是真的,因为来自 pytumblr 的空 Tumblr API 响应看起来像这样:

{'blog': {'ask': False,
  'ask_anon': False,
  'ask_page_title': 'Ask me anything',
  'can_send_fan_mail': False,
  'can_subscribe': False,
  'description': '',
  'followed': False,
  'is_adult': False,
  'is_blocked_from_primary': False,
  'is_nsfw': False,
  'is_optout_ads': False,
  'name': 'asdfasdf',
  'posts': 0,
  'reply_conditions': '3',
  'share_likes': False,
  'subscribed': False,
  'title': 'Untitled',
  'total_posts': 0,
  'updated': 0,
  'url': 'https://asdfasdf.tumblr.com/'},
 'posts': [],
 'supply_logging_positions': [],
 'total_posts': 0}

if not posts 将根据该结构进行检查,而不是 posts 字段(此处为空列表),因此条件永远不会失败,因为响应字典不为空(参见:Truth Value Testing in Python).


更正版本

这是修复 getAllPosts 实现中的循环的代码(主要是 tested/verified),然后使用该函数检索 posts 并将它们转储到名称为(BLOG_NAME)-posts.txt.

import pytumblr


def get_all_posts(client, blog):
    offset = 0
    while True:
        response = client.posts(blog, limit=20, offset=offset, reblog_info=True, notes_info=True)

        # Get the 'posts' field of the response        
        posts = response['posts']

        if not posts: return

        for post in posts:
            yield post

        # move to the next offset
        offset += 20


client = pytumblr.TumblrRestClient('secrety-secret')
blog = 'staff'

# use our function
with open('{}-posts.txt'.format(blog), 'w') as out_file:
    for post in get_all_posts(client, blog):
        print >>out_file, post
        # if you're in python 3.x, use the following
        # print(post, file=out_file)

这只是 API 的 post 回复的直接文本转储,所以如果您需要让它看起来更好或其他任何东西,这取决于您。