Python urllib3与代理

4 投票
2 回答
1972 浏览
提问于 2025-04-17 16:29

我正在尝试弄清楚如何使用代理和多线程。

这段代码是可以正常工作的:

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_urlWorkerPool 一起使用。

有没有什么想法可以把这两者结合成一个有效的代码?由于时间有限,我更希望避免重写成其他的形式。

祝好

2 个回答

3

首先,我建议你尽量避免使用urllib,像躲避瘟疫一样,建议使用requests库,它对代理的支持非常简单易用:http://docs.python-requests.org/en/latest/user/advanced/#proxies
接下来,我没有用它来做多线程,但用多进程的方式效果很好。你需要搞清楚的是,你是有一个动态的队列,还是一个相对固定的列表可以分配给多个工作进程。后者的一个例子是把一组网址均匀分配到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[:]

但正如你所看到的,这些特殊类型(Value和Array)可以实现进程间的数据共享。 如果你想要一个可以进行轮询处理的队列,可以使用JoinableQueue。 希望这对你有帮助!

2

看起来你把调用 thread_pool.map() 的结果给丢掉了。试着把它赋值给一个变量:

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 很相似,但它是标准库的一部分。

撰写回答