如何使用python请求和事件挂钩编写带有回调函数的web爬虫程序?

如何使用python请求和事件挂钩编写带有回调函数的web爬虫程序?,python,callback,web-scraping,python-requests,Python,Callback,Web Scraping,Python Requests,我最近看了一下这个模块,我想用它编写一个简单的网络爬虫。给定一组起始URL,我想编写一个Python函数,该函数在起始URL的网页内容中搜索其他URL,然后以新URL作为输入再次调用同一函数作为回调函数,以此类推。起初,我认为这是用于此目的的正确工具,但其文档部分非常稀少。在上一篇文章中,我了解到用于事件挂钩的函数必须返回传递给它们的相同对象。因此,事件挂钩显然不适用于此类任务。或者我就是没弄好 下面是我想做的一些伪代码(从伪痒蜘蛛那里借来): 有人能告诉我如何处理python请求吗?事件挂钩是

我最近看了一下这个模块,我想用它编写一个简单的网络爬虫。给定一组起始URL,我想编写一个Python函数,该函数在起始URL的网页内容中搜索其他URL,然后以新URL作为输入再次调用同一函数作为回调函数,以此类推。起初,我认为这是用于此目的的正确工具,但其文档部分非常稀少。在上一篇文章中,我了解到用于事件挂钩的函数必须返回传递给它们的相同对象。因此,事件挂钩显然不适用于此类任务。或者我就是没弄好

下面是我想做的一些伪代码(从伪痒蜘蛛那里借来):


有人能告诉我如何处理python请求吗?事件挂钩是实现这一点的正确工具,还是我需要一些不同的工具?(注意:由于各种原因,刮痧对我来说不是一个选择。)非常感谢

以下是我的做法:

import grequests
from bs4 import BeautifulSoup


def get_urls_from_response(r):
    soup = BeautifulSoup(r.text)
    urls = [link.get('href') for link in soup.find_all('a')]
    return urls


def print_url(args):
    print args['url']


def recursive_urls(urls):
    """
    Given a list of starting urls, recursively finds all descendant urls
    recursively
    """
    if len(urls) == 0:
        return
    rs = [grequests.get(url, hooks=dict(args=print_url)) for url in urls]
    responses = grequests.map(rs)
    url_lists = [get_urls_from_response(response) for response in responses]
    urls = sum(url_lists, [])  # flatten list of lists into a list
    recursive_urls(urls)
我还没有测试代码,但总体思路是存在的

请注意,我正在使用而不是
请求
来提高性能
grequest
基本上是
gevent+request
,根据我的经验,这类任务的执行速度要快得多,因为您可以使用
gevent
异步检索链接


编辑:以下是不使用递归的相同算法:

import grequests
from bs4 import BeautifulSoup


def get_urls_from_response(r):
    soup = BeautifulSoup(r.text)
    urls = [link.get('href') for link in soup.find_all('a')]
    return urls


def print_url(args):
    print args['url']


def recursive_urls(urls):
    """
    Given a list of starting urls, recursively finds all descendant urls
    recursively
    """
    while True:
        if len(urls) == 0:
            break
        rs = [grequests.get(url, hooks=dict(args=print_url)) for url in urls]
        responses = grequests.map(rs)
        url_lists = [get_urls_from_response(response) for response in responses]
        urls = sum(url_lists, [])  # flatten list of lists into a list

if __name__ == "__main__":
    recursive_urls(["INITIAL_URLS"])

非常感谢您的详细回答。如果我错了,请纠正我,但您在这里使用的不是回调,而是一个简单的递归函数调用。当达到某个递归深度时,这不会导致问题吗?据我所知,Python尚未针对递归进行优化,因此您的设置可能会在某个时候抛出一个
运行时错误
,或者我错了吗?@PeterStahl您是对的,它最多只能递归
sys.getrecursionlimit()
,在我的框中是1000。如果需要的话,我会尝试找出一个没有这个限制的答案。那确实很好,因为这是我的主要问题。我想我需要并行编程,但我没有这方面的经验。如果你想到了一些东西,那就太好了,因为我真的不知道从哪里开始(使用线程或进程,一个外部库,比如芹菜等等)。提前谢谢。@PeterStahl没问题,我添加了相同的代码,没有使用递归。我还没有深入研究如何在
grequests
中使用worker,但我想这是一个不同的问题。非常感谢。)天哪,一段时间。真的很简单。我本来可以自己想出来的。哦,天哪,我还得学很多。但这是一个很好的开始,也是我想知道的一切
import grequests
from bs4 import BeautifulSoup


def get_urls_from_response(r):
    soup = BeautifulSoup(r.text)
    urls = [link.get('href') for link in soup.find_all('a')]
    return urls


def print_url(args):
    print args['url']


def recursive_urls(urls):
    """
    Given a list of starting urls, recursively finds all descendant urls
    recursively
    """
    while True:
        if len(urls) == 0:
            break
        rs = [grequests.get(url, hooks=dict(args=print_url)) for url in urls]
        responses = grequests.map(rs)
        url_lists = [get_urls_from_response(response) for response in responses]
        urls = sum(url_lists, [])  # flatten list of lists into a list

if __name__ == "__main__":
    recursive_urls(["INITIAL_URLS"])