2013-02-20 91 views
4

我想弄清楚如何使用代理和多線程。Python urllib3和代理

此代碼:

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) 

頁眉包括

然後:接受,接收字符集,接受編碼,接受語言和用戶代理

但是這在生產中不起作用,因爲它必須通過代理,不需要授權。

我嘗試了不同的事情(通過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

任何想法如何將這兩個結合到一個工作代碼?我寧願避免它改寫成零碎等由於時間限制

問候

+0

您是否嘗試過爲每個線程創建一個(代理)請求者(每個請求者僅從一個線程發出請求)?免責聲明:我不直接使用'urllib3'。 – jfs 2013-03-06 22:13:17

回答

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() 

注: 如果您使用的是蟒蛇3.2或更高版本可以使用concurrent.futures.ThreadPoolExecutor。這是類似於workerpool的報價,但包含在標準庫中。

+0

嗨,只是爲了驗證:thread_pool.shutdown()thread_pool.wait()應results.shutdown()results.wait()吧? (結果是創建的thread_pool實例的對象/指針) – Carst 2013-03-10 20:04:53

+0

@Carl:'results'是一個* list */iterable值,通過每個url調用'grab_wrapper()'來計算。所以這些方法必須在'thread_pool'上調用 – 2013-03-10 20:19:41

3

首先我建議避免的urllib瘟疫一樣,而使用的要求,這對代理很容易支持: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[:] 

但正如你看到的,基本上這些特殊類型(價值&陣列)使進程之間的數據共享。 如果您尋找一個隊列來執行類似roundrobin的進程,則可以使用JoinableQueue。 希望這有助於!

+0

我不認爲這會削減它。目前該程序有3個部分:1.獨立的一個URL處理,2.多個URL處理(你的例子可以工作),但是3.是一個多重URL和數據處理,其中的數據在它們之間共享數據。你可以在進程間共享數據嗎? – realshadow 2013-03-04 20:50:16

+0

海報正在使用urllib * 3 *,這實際上是請求的基礎。 – 2013-03-05 15:18:57

+0

他剛剛在他的例子中提到過,而不是解決方案要求。只是試圖幫助在這裏和imho請求比任何urllibs更容易和更快實施... – Carst 2013-03-05 21:28:06