如何在scrapy(Python)中间件中实现并发

时间:2014-03-12 16:53:25

标签: python scrapy

修改2

第二种方法。目前,我放弃了使用多个实例并配置了scrapy设置,不使用并发请求。它虽然缓慢但稳定。 我开了赏金。谁可以帮助同时完成这项工作?如果我将scrapy配置为同时运行,则会出现分段错误。

class WebkitDownloader( object ):

    def __init__(self):
        os.environ["DISPLAY"] = ":99"
        self.proxyAddress = "a:b@" + PROXY_DEFAULT_HOST + ":" + str(PROXY_DEFAULT_PORT)


    def process_response(self, request, response, spider):
        self.request = request
        self.response = response
        if 'cached' not in response.flags:
            webkitBrowser = webkit.WebkitBrowser(proxy = self.proxyAddress, gui=False, timeout=0.5, delay=0.5, forbidden_extensions=['js','css','swf','pdf','doc','xls','ods','odt'])
            #print "added to queue: " + str(self.counter)
            webkitBrowser.get(html=response.body, num_retries=0)
            html = webkitBrowser.current_html()
            respcls = responsetypes.from_args(headers=response.headers, url=response.url)
            kwargs = dict(cls=respcls, body=killgremlins(html))
            response = response.replace(**kwargs)
            webkitBrowser.setPage(None)
            del webkitBrowser
        return response

修改

我试图在此期间回答我自己的问题并实现了一个队列,但由于某种原因它不会异步运行。基本上当webkitBrowser.get(html=response.body, num_retries=0)忙时,scrapy会被阻止,直到方法完成。新请求未分配给self.queue中的剩余空闲实例。

任何人都可以指出我正确的方向来完成这项工作吗?

class WebkitDownloader( object ):

    def __init__(self):
        proxyAddress = "http://" + PROXY_DEFAULT_HOST + ":" + str(PROXY_DEFAULT_PORT)
        self.queue = list()
        for i in range(8):
            self.queue.append(webkit.WebkitBrowser(proxy = proxyAddress, gui=True, timeout=0.5, delay=5.5, forbidden_extensions=['js','css','swf','pdf','doc','xls','ods','odt']))

    def process_response(self, request, response, spider):

        i = 0
        for webkitBrowser in self.queue:
            i += 1
            if webkitBrowser.status == "WAITING":
                break
        webkitBrowser = self.queue[i]

        if webkitBrowser.status == "WAITING":
            # load webpage
            print "added to queue: " + str(i)
            webkitBrowser.get(html=response.body, num_retries=0)
            webkitBrowser.scrapyResponse = response

        while webkitBrowser.status == "PROCESSING":
            print "waiting for queue: " + str(i)  

        if webkitBrowser.status == "DONE":
            print "fetched from queue: " + str(i)
            #response = webkitBrowser.scrapyResponse
            html = webkitBrowser.current_html()
            respcls = responsetypes.from_args(headers=response.headers, url=response.url)
            kwargs = dict(cls=respcls, body=killgremlins(html))
            #response = response.replace(**kwargs)
            webkitBrowser.status = "WAITING"
            return response

我在scrapy中间件中使用WebKit来呈现JavaScript。目前,scrapy配置为一次处理1个请求(无并发)。

我想使用并发(例如,一次8个请求)但是我需要确保8个WebkitBrowser()实例根据其各自的处理状态接收请求(尽快提出新请求)当WebkitBrowser.get()完成并准备好接收下一个请求时)

如何使用Python实现这一目标?这是我目前的中间件:

class WebkitDownloader( object ):

    def __init__(self):
        proxyAddress = "http://" + PROXY_DEFAULT_HOST + ":" + str(PROXY_DEFAULT_PORT)
        self.w = webkit.WebkitBrowser(proxy = proxyAddress, gui=True, timeout=0.5, delay=0.5, forbidden_extensions=['js','css','swf','pdf','doc','xls','ods','odt'])

    def process_response(self, request, response, spider):
        if not ".pdf" in response.url:
            # load webpage
            self.w.get(html=response.body, num_retries=0)
            html = self.w.current_html()
            respcls = responsetypes.from_args(headers=response.headers, url=response.url)
            kwargs = dict(cls=respcls, body=killgremlins(html))
            response = response.replace(**kwargs)

        return response 

2 个答案:

答案 0 :(得分:2)

我没有关注你问题中的所有内容,因为我不知道scrapy而且我不明白会导致段错误的原因,但我想我可以解决一个问题:为什么当webkitBrowser.get忙时scrapy被阻止?

我的“队列”示例中没有看到任何可以提供并行性的内容。通常,可以使用threadingmultiprocessing模块,以便多个内容可以“并行”运行。而不是简单地调用webkitBrowser.get,我怀疑你可能想在一个线程中运行它。检索网页是python线程应该运行得相当好的情况。 Python不能同时执行两个CPU密集型任务(由于GIL),但它可以等待来自Web服务器的并行响应。

Here's a recent SO Q/A with example code that might help.

以下是如何帮助您入门的想法。创建Queue。定义一个将此队列作为参数的函数,获取网页并将响应放入队列中。在主程序中,在生成所有get线程后输入while True:循环:检查队列并处理下一个条目,或time.sleep(.1)如果它是空的。

答案 1 :(得分:0)

我知道这是一个老问题,但我有类似的问题,希望我偶然发现的这些信息可以帮助其他人解决这个问题:

  1. 如果scrapyjs + splash适合您(鉴于您使用的是webkit浏览器,它们很可能,因为它是基于webkit的),它可能是最简单的解决方案;

  2. 如果1不起作用,您可以使用scrapydmultiprocessing with scrapy同时运行多个蜘蛛;

  3. 根据您的浏览器渲染主要是等待(对于要渲染的页面),IO密集型或CPU密集型,您可能希望使用扭曲,多线程或多处理的非阻塞睡眠。对于后者,坚持使用scrapy的价值会减少,你可能想要破解一个简单的刮刀(例如A. Jesse Jiryu Davis和Guido van Rossum撰写的网络爬虫:codedocument)或创建你自己的。