如何使用 For Loop 从 html 中获取多个链接?

How do I use For Loop to get multiple links from an html?

这是我目前拥有的:

import bs4
import requests

def getXkcdComic(comicUrl):
    for i in range(0,20):
        res = requests.get(comicUrl + str(1882 - i))
        res.raise_for_status()

        soup = bs4.BeautifulSoup(res.text, 'html.parser')
        img = soup.select_one("div#comic > img")
        return str(img['src'])


link = getXkcdComic('https://xkcd.com/')

print(link)

我解析 html,得到一个 link,第一个,因为我知道 url 在 1882 结束,下一个我想要的是 1881,所以我写了这个for-loop 得到其余的。 它只打印一个结果,就好像没有写循环一样。 奇怪的是,如果我减少 return 函数的缩进,它会 returns 一个不同的 url.

我还不太明白 For-loops 是如何工作的。 另外,这是我第一次 post 来这里,所以请原谅我的英语和无知。

你的函数returns一旦遇到return语句就把控制权交给调用者,这里是for的第一次迭代.

您可以在函数中 yield 而不是 return 以从函数中连续生成图像链接并保持 for 循环 运行 :

import bs4
import requests

def getXkcdComic(comicUrl):
    for i in range(0,20):
        ...
        yield img['src']  # <- here

# make a list of links yielded by function
links = list(getXkcdComic('https://xkcd.com/')) 

参考文献:

  1. Understanding Generators in Python

  2. Python yield expression

第一次点击 return 语句时,函数将转到 return,无论您是否处于循环中。因此,您的 for() 循环将到达第一次迭代的结尾,请参阅 return,仅此而已。其他 19 次迭代不会 运行.

如果您缩减 return,您得到不同 URL 的原因是您的 for() 循环现在可以 运行 完成。但是由于您没有保存之前的任何迭代,因此它将 return 仅保存最后一个。

您可能想要的是构建一个结果列表,return。

def getXkcdComic(comicUrl):
    images = []                           # Create an empty list for results
    for i in range(0,20):
        res = requests.get(comicUrl + str(1882 - i))
        res.raise_for_status()
        soup = bs4.BeautifulSoup(res.text, 'html.parser')
        img = soup.select_one("div#comic > img")
        images.append(str(img['src']))    # Save the result by adding it to the list
    return images                         # Return the list

请记住,您的外部范围中的 link 实际上是一个 列表 链接,并相应地处理它。

当您在第一个循环中调用 'return' 时,整个 'getXkcdComic' 函数退出并且 returns.

像这样的东西可能会像原始代码一样工作和打印:

import bs4
import requests

def getXkcdComic(comicUrl, number):
    res = requests.get(comicUrl + str(number))
    res.raise_for_status()

    soup = bs4.BeautifulSoup(res.text, 'html.parser')
    return str(soup.select_one("div#comic > img")['src'])

link = 'https://xkcd.com/'
for i in range(20):
    print(getXkcdComic(link, 1882-i))

您希望如何通过单个方法调用获得多个输出(此处为 url)? for 循环可以帮助您多次迭代一个范围并获得多个结果,但只有在您进行一次调用之前它没有用处。您可以执行以下操作之一:

  • 与其在方法内编写循环,不如在循环中调用方法。这样每次调用都会打印您的输出。
  • 将整个内容写在方法中,以便您有多个打印语句。

执行以下操作:

def getXkcdComic(comicUrl):
    for i in range(0,20):
        res = requests.get(comicUrl + str(1882 - i))
        res.raise_for_status()
        soup = bs4.BeautifulSoup(res.text, 'html.parser')
        img = soup.select_one("div#comic > img")
        print str(img['src'])
getXkcdComic('https://xkcd.com/')

发生这种情况是因为您在循环中创建了 return。试一试:

def getXkcdComic(comicUrl):
    res = list()
    for i in range(0,20):
        res = requests.get(comicUrl + str(1882 - i))
        res.raise_for_status()

        soup = bs4.BeautifulSoup(res.text, 'html.parser')
        img = soup.select_one("div#comic > img")
        res.append(str(img['src']))
    return res

你可以改变这个:

for i in range(0,20):
            res = requests.get(comicUrl + str(1882 - i))

对此:

for i in range(1862, 1883, 1):
            res = requests.get(comicUrl + str(i))

其他答案都很好,也很笼统,但对于这个特定案例,还有更好的方法。 xkcd提供了JSONAPI,所以可以使用列表理解:

def getXkcdComic(comicUrl):
    return [requests.get(comicUrl + str(1882 - i) + '/info.0.json').json()['img']
            for i in range(0,20)]

这对 xkcd 服务器也更快、更友好。