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