2016-07-30 10 views
1

Für meine Bachelor-Thesis muss ich einige Daten aus etwa 40000 Websites abrufen. Daher verwende ich Python-Anfragen, aber im Moment ist es wirklich langsam mit einer Antwort vom Server.Multithread-Python-Anfragen

Gibt es trotzdem, um es zu beschleunigen und meine aktuelle Header-Einstellung zu behalten? Alle Tutorials, die ich ohne Header gefunden habe.

Hier ist mein Code snipped:

def parse(url): 
    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) ' 
         'Chrome/39.0.2171.95 Safari/537.36'} 
    r = requests.get(url, headers=headers) 

    for line in r.iter_lines(): 
     ... 
+0

Vielleicht 'aiohttp'? – grooveplex

+0

Wie wäre es mit 'Multiprocessing'? http://stackoverflow.com/questions/28393617/python-requests-module-multithreading – bsa

+0

@bsa keine Notwendigkeit für Multiprocessing, der Overhead des neuen Prozesses ist zu groß, Threads sind besser für io gebunden. –

Antwort

1

Nun, Sie verwenden müssen Verwenden Sie Threads, da dies I/O Bound Problem ist. Mit der eingebauten threading Bibliothek ist Ihre beste Wahl. Ich habe das Objekt Semaphore verwendet, um zu zählen, wie viele Threads gerade ausgeführt werden.

import time 
import threading 

# Number of parallel threads 
lock = threading.Semaphore(2) 


def parse(url): 
    """ 
    Change to your logic, I just use sleep to mock http request. 
    """ 

    print 'getting info', url 
    sleep(2) 

    # After we done, subtract 1 from the lock 
    lock.release() 


def parse_pool(): 
    # List of all your urls 
    list_of_urls = ['website1', 'website2', 'website3', 'website4'] 

    # List of threads objects I so we can handle them later 
    thread_pool = [] 

    for url in list_of_urls: 
     # Create new thread that calls to your function with a url 
     thread = threading.Thread(target=parse, args=(url,)) 
     thread_pool.append(thread) 
     thread.start() 

     # Add one to our lock, so we will wait if needed. 
     lock.acquire() 

    for thread in thread_pool: 
     thread.join() 

    print 'done' 
+0

Was ist, wenn eine Website in dieser 40000 Website-Liste mehrfach vorhanden ist? (Wenn ich Daten von mehr als 1 Seite benötige) Wie kann ich sie nicht ddo? Wartet nur eine zufällige Zeit vor einer Anfrage? – QDA

+0

Sie müssen dict verwenden: die Schlüssel sind die URL der Webseite und der Wert wird 'Semaphore' Sperre sein. Das ist ein bisschen komplizierter. wenn die Antwort richtig ist, bitte akzeptieren Sie es, danke :) @QDA –

-1

Ich denke, es ist eine gute Idee mutil-thread wie threading oder multiprocess zu verwenden, oder Sie können grequests (Asynchron-Anfragen) auf Grund gevent

0

Sie können asyncio verwenden, um Tasks gleichzeitig auszuführen. Sie können die URL-Antworten (die sowohl als abgeschlossen als auch als ausstehend aufgeführt sind) mit dem zurückgegebenen Wert asyncio.wait() auflisten und Coroutinen asynchron aufrufen. Die Ergebnisse werden in einer unerwarteten Reihenfolge sein, aber es ist ein schnellerer Ansatz.

import asyncio 
import functools 


async def parse(url): 
    print('in parse for url {}'.format(url)) 

    info = await #write the logic for fetching the info, it waits for the responses from the urls 

    print('done with url {}'.format(url)) 
    return 'parse {} result from {}'.format(info, url) 


async def main(sites): 
    print('starting main') 
    parses = [ 
     parse(url) 
     for url in sites 
    ] 
    print('waiting for phases to complete') 
    completed, pending = await asyncio.wait(parses) 

    results = [t.result() for t in completed] 
    print('results: {!r}'.format(results)) 


event_loop = asyncio.get_event_loop() 
try: 
    websites = ['site1', 'site2', 'site3'] 
    event_loop.run_until_complete(main(websites)) 
finally: 
    event_loop.close() 
+0

Was ist, wenn eine Website mehrmals in dieser 40000 Website-Liste ist? (Wenn ich Daten von mehr als 1 Seite benötige) Wie kann ich sie nicht ddo? – QDA

+0

Wird 'repeat' von' itertools' helfen? 'von itertools Importwiederholung'; 'websites.extend ('sitex', 100)'. Was genau brauchst du? Richten Sie die Seiten separat und dynamisch ein? Diese Wiederholung hilft nur beim Anhängen einer bestimmten Website für eine bestimmte Anzahl von Malen. – tworitdash