Ich öffne eine Datei, die 100.000 URLs enthält. Ich muss eine HTTP-Anfrage an jede URL senden und den Statuscode ausgeben. Ich verwende Python 2.6 und habe mir bisher die vielen verwirrenden Möglichkeiten angeschaut, wie Python Threading/Concurrency implementiert. Ich habe mir sogar die Python Übereinstimmung Bibliothek, kann aber nicht herausfinden, wie man dieses Programm richtig schreibt. Ist jemand auf ein ähnliches Problem gestoßen? Ich schätze, ich muss generell wissen, wie man Tausende von Aufgaben in Python so schnell wie möglich ausführt - ich nehme an, das bedeutet "gleichzeitig".
Antworten
Zu viele Anzeigen?Verdrehungsfreie Lösung:
from urlparse import urlparse
from threading import Thread
import httplib, sys
from Queue import Queue
concurrent = 200
def doWork():
while True:
url = q.get()
status, url = getStatus(url)
doSomethingWithResult(status, url)
q.task_done()
def getStatus(ourl):
try:
url = urlparse(ourl)
conn = httplib.HTTPConnection(url.netloc)
conn.request("HEAD", url.path)
res = conn.getresponse()
return res.status, ourl
except:
return "error", ourl
def doSomethingWithResult(status, url):
print status, url
q = Queue(concurrent * 2)
for i in range(concurrent):
t = Thread(target=doWork)
t.daemon = True
t.start()
try:
for url in open('urllist.txt'):
q.put(url.strip())
q.join()
except KeyboardInterrupt:
sys.exit(1)
Diese ist etwas schneller als die verdrehte Lösung und verbraucht weniger CPU.
Die Dinge haben sich seit 2010, als dies gepostet wurde, ziemlich verändert, und ich habe nicht alle anderen Antworten ausprobiert, aber ich habe ein paar ausprobiert, und ich fand dies am besten für mich mit Python3.6 zu arbeiten.
Ich konnte ca. 150 eindeutige Domains pro Sekunde über AWS abrufen.
import concurrent.futures
import requests
import time
out = []
CONNECTIONS = 100
TIMEOUT = 5
tlds = open('../data/sample_1k.txt').read().splitlines()
urls = ['http://{}'.format(x) for x in tlds[1:]]
def load_url(url, timeout):
ans = requests.head(url, timeout=timeout)
return ans.status_code
with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor:
future_to_url = (executor.submit(load_url, url, TIMEOUT) for url in urls)
time1 = time.time()
for future in concurrent.futures.as_completed(future_to_url):
try:
data = future.result()
except Exception as exc:
data = str(type(exc))
finally:
out.append(data)
print(str(len(out)),end="\r")
time2 = time.time()
print(f'Took {time2-time1:.2f} s')
Ich weiß, dies ist eine alte Frage, aber in Python 3.7 können Sie dies tun, indem Sie asyncio
y aiohttp
.
import asyncio
import aiohttp
from aiohttp import ClientSession, ClientConnectorError
async def fetch_html(url: str, session: ClientSession, **kwargs) -> tuple:
try:
resp = await session.request(method="GET", url=url, **kwargs)
except ClientConnectorError:
return (url, 404)
return (url, resp.status)
async def make_requests(urls: set, **kwargs) -> None:
async with ClientSession() as session:
tasks = []
for url in urls:
tasks.append(
fetch_html(url=url, session=session, **kwargs)
)
results = await asyncio.gather(*tasks)
for result in results:
print(f'{result[1]} - {str(result[0])}')
if __name__ == "__main__":
import pathlib
import sys
assert sys.version_info >= (3, 7), "Script requires Python 3.7+."
here = pathlib.Path(__file__).parent
with open(here.joinpath("urls.txt")) as infile:
urls = set(map(str.strip, infile))
asyncio.run(make_requests(urls=urls))
Sie können mehr darüber lesen und ein Beispiel sehen hier .
Eine Lösung mit Tornado asynchrone Netzwerkbibliothek
from tornado import ioloop, httpclient
i = 0
def handle_request(response):
print(response.code)
global i
i -= 1
if i == 0:
ioloop.IOLoop.instance().stop()
http_client = httpclient.AsyncHTTPClient()
for url in open('urls.txt'):
i += 1
http_client.fetch(url.strip(), handle_request, method='HEAD')
ioloop.IOLoop.instance().start()
Dieser Code verwendet nicht blockierende Netzwerk-E/A und hat keine Einschränkungen. Er kann auf Zehntausende von offenen Verbindungen skaliert werden. Er wird in einem einzigen Thread ausgeführt, ist aber viel schneller als jede Threading-Lösung. Prüfen Sie nicht-blockierende E/A
- See previous answers
- Weitere Antworten anzeigen