4

我想弄清楚如何使用代理和多线程。

此代码有效:

requester = urllib3.PoolManager(maxsize = 10, headers = self.headers)
thread_pool = workerpool.WorkerPool()

thread_pool.map(grab_wrapper, [item['link'] for item in products])

thread_pool.shutdown()
thread_pool.wait()  

然后在grab_wrapper

requested_page = requester.request('GET', url, assert_same_host = False, headers = self.headers)

标头包括:Accept、Accept-Charset、Accept-Encoding、Accept-Language 和 User-Agent

但这在生产中不起作用,因为它必须通过代理,不需要授权。

我尝试了不同的东西(传递proxies给请求,在标头中等)。唯一有效的是:

requester = urllib3.proxy_from_url(self._PROXY_URL, maxsize = 7, headers = self.headers)
thread_pool = workerpool.WorkerPool(size = 10)

thread_pool.map(grab_wrapper, [item['link'] for item in products])

thread_pool.shutdown()
thread_pool.wait()  

现在,当我运行程序时,它将发出 10 个请求(10 个线程),然后……停止。没有错误,没有任何警告。这是我可以绕过代理的唯一方法,但它似乎无法同时proxy_from_url使用WorkerPool

任何想法如何将这两者结合成一个工作代码?由于时间限制,我宁愿避免将其重写为scrapy等

问候

4

2 回答 2

3

首先,我建议避免像瘟疫一样使用 urllib,而是使用请求,它对代理的支持非常简单:http: //docs.python-requests.org/en/latest/user/advanced/#proxies
接下来,我没有将它与多线程一起使用,但与多处理一起使用并且效果非常好,你唯一需要弄清楚的是你是否有一个动态队列或一个相当固定的列表,你可以分布在工作人员身上,后者的示例将 url 列表均匀地分布在 x 个进程上:

# *** prepare multi processing
nr_processes = 4
chunksize = int(math.ceil(total_nr_urls / float(nr_processes)))
procs = []
# *** start up processes
for i in range(nr_processes):
    start_row = chunksize * i
    end_row = min(chunksize * (i + 1), total_nr_store)
    p = multiprocessing.Process(
            target=url_loop,
            args=(start_row, end_row, str(i), job_id_input))
    procs.append(p)
    p.start()
# *** Wait for all worker processes to finish
for p in procs:
    p.join()

每个 url_loop 进程都会将自己的数据集写入数据库中的表中,因此我不必担心在 python 中将它们连接在一起。

编辑:关于在进程之间共享数据 -> 有关详细信息,请参阅:http ://docs.python.org/2/library/multiprocessing.html?highlight=multiprocessing#multiprocessing

from multiprocessing import Process, Value, Array

def f(n, a):
    n.value = 3.1415927
    for i in range(len(a)):
        a[i] = -a[i]

if __name__ == '__main__':
    num = Value('d', 0.0)
    arr = Array('i', range(10))

    p = Process(target=f, args=(num, arr))
    p.start()
    p.join()

    print num.value
    print arr[:]

但正如您所看到的,基本上这些特殊类型(值和数组)可以在进程之间共享数据。如果您改为寻找队列来执行类似循环的过程,则可以使用 JoinableQueue。希望这可以帮助!

于 2013-03-04T10:32:57.690 回答
2

看来您正在丢弃调用thread_pool.map() Try 将其分配给变量的结果:

requester = urllib3.proxy_from_url(PROXY, maxsize=7)
thread_pool = workerpool.WorkerPool(size=10)


def grab_wrapper(url):
    return requester.request('GET', url)


results = thread_pool.map(grab_wrapper, LINKS)

thread_pool.shutdown()
thread_pool.wait()

注意:如果您使用的是 python 3.2 或更高版本,则可以使用concurrent.futures.ThreadPoolExecutor. 它的引用类似于workerpool但包含在标准库中。

于 2013-03-07T17:40:39.710 回答