Pregunta

Tengo un script que va a buscar a varias páginas web y analiza la información.

(Un ejemplo puede verse en http://bluedevilbooks.com/search/ ? DTO = MATH & Clase = 103 y SEC = 01 )

Me encontré cprofile en él, y ya que asumí, urlopen ocupa mucho tiempo. ¿Hay una manera de recuperar las páginas de más rápido? O una manera de buscar a varias páginas a la vez? Haré lo que es más simple, ya que soy nuevo en Python y desarrollo web.

Gracias de antemano! :)

ACTUALIZACIÓN: Tengo una función llamada fetchURLs(), que utilizo para hacer una serie de direcciones URL que la necesidad así que algo como urls = fetchURLS().The URL son todos los archivos XML de Amazon y eBay API (que me confunde en cuanto a por qué se tarda tanto en cargar, tal vez mi servicio de hosting es lento?)

Lo que usted debe hacer es cargar cada URL, leer cada página, y enviar esos datos a otra parte de la secuencia de comandos que analizar y mostrar los datos.

Tenga en cuenta que yo no puedo hacer la última parte hasta que todas las páginas se han exagerado, eso es lo que mi problema es.

Además, mis anfitriones me limita a 25 procesos a la vez, creo, así que lo que es más fácil en el servidor estaría bien:)


Aquí es por el tiempo:

Sun Aug 15 20:51:22 2010    prof

         211352 function calls (209292 primitive calls) in 22.254 CPU seconds

   Ordered by: internal time
   List reduced from 404 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10   18.056    1.806   18.056    1.806 {_socket.getaddrinfo}
     4991    2.730    0.001    2.730    0.001 {method 'recv' of '_socket.socket' objects}
       10    0.490    0.049    0.490    0.049 {method 'connect' of '_socket.socket' objects}
     2415    0.079    0.000    0.079    0.000 {method 'translate' of 'unicode' objects}
       12    0.061    0.005    0.745    0.062 /usr/local/lib/python2.6/HTMLParser.py:132(goahead)
     3428    0.060    0.000    0.202    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:1306(endData)
     1698    0.055    0.000    0.068    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:1351(_smartPop)
     4125    0.053    0.000    0.056    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:118(setup)
     1698    0.042    0.000    0.358    0.000 /usr/local/lib/python2.6/HTMLParser.py:224(parse_starttag)
     1698    0.042    0.000    0.275    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:1397(unknown_starttag)
¿Fue útil?

Solución

Editar : Estoy ampliando la respuesta para incluir un ejemplo más pulido. He encontrado una gran cantidad de hostilidad y falta de información en este post con respecto V.S. enhebrado async I / O. Por lo tanto, además de darle más argumentos para refutar cierta reclamo válido. Espero que esto ayudará a las personas a elegir la herramienta adecuada para el trabajo correcto.

Este es un DUP a una pregunta hace 3 días.

Python urllib2.open es lento, necesita una mejor manera de leer varias direcciones URL - desbordamiento de pila    Python urllib2 .urlopen () es lento, necesita una mejor manera de leer varias direcciones URL

Estoy puliendo el código para mostrar cómo para ir a buscar la página múltiple en hilos paralelos utilizando.

import time
import threading
import Queue

# utility - spawn a thread to execute target for each args
def run_parallel_in_threads(target, args_list):
    result = Queue.Queue()
    # wrapper to collect return value in a Queue
    def task_wrapper(*args):
        result.put(target(*args))
    threads = [threading.Thread(target=task_wrapper, args=args) for args in args_list]
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    return result

def dummy_task(n):
    for i in xrange(n):
        time.sleep(0.1)
    return n

# below is the application code
urls = [
    ('http://www.google.com/',),
    ('http://www.lycos.com/',),
    ('http://www.bing.com/',),
    ('http://www.altavista.com/',),
    ('http://achewood.com/',),
]

def fetch(url):
    return urllib2.urlopen(url).read()

run_parallel_in_threads(fetch, urls)

Como se puede ver, el código específico de la aplicación sólo tiene 3 líneas, que pueden colapsarse en 1 línea si usted es agresivo. No creo que nadie pueda justificar su afirmación de que esto es complejo y imposible de mantener.

Desafortunadamente la mayoría otro código enhebrado publicado aquí tiene algunos defectos. Muchos de ellos lo hacen de sondeo activo que esperar a que el código a fin. join() es una mejor manera de sincronizar el código. Creo que este código ha mejorado todos los ejemplos de roscado hasta ahora.

conexión de mantenimiento de conexión

La sugerencia de WoLpH sobre el uso de la conexión de mantenimiento de conexión podría ser muy útil si todo lo que los URLs apuntan al mismo servidor.

torcido

Aaron Gallagher es un fans de marco twisted y él es hostil a cualquier personas que sugieren hilo. Desafortunadamente muchos de sus afirmaciones son información errónea. Por ejemplo, dijo "-1 por sugerir hilos Esto es IO-obligado;.. Roscas son inútiles aquí" Esta contrario a la evidencia ya que tanto Nick T e I han demostrado el aumento de la velocidad del uso de hilo. De hecho I O application / unido tiene más que ganar con el uso de hilo de Python (V.S. no hay ganancia en CPU aplicación enlazada). la crítica equivocada de Aaron en programas de rosca que está bastante confusa acerca de la programación paralela en general.

herramienta adecuada para el trabajo correcto

Soy muy consciente de los temas pertenecen a la programación paralela utilizando hilos, Python, asíncronas de E / S y así sucesivamente. Cada herramienta tiene sus pros y contras. Para cada situación hay una herramienta adecuada. No estoy en contra trenzado (aunque no he desplegado una yo). Pero no creo que podemos decir que de plano hilo trenzado es malo y es bueno en todas las situaciones.

Por ejemplo, si los requerimientos de la OP es a buscar a 10.000 sitio web en paralelo, async E / S será prefereable. Threading no será apropiable (a menos que tal vez sin pérdida de velocidad con Python).

La oposición de Aaron a las discusiones son en su mayoría generalizaciones. Él deja de reconocer que esta es una tarea trivial paralelización. Cada tarea es independiente y no comparten recursos. Así que la mayor parte de su ataque no se aplican.

Dada mi código no tiene ninguna dependencia externa, lo llamaré herramienta adecuada para el trabajo correcto.

Rendimiento

creo que la mayoría estaría de acuerdo en que el desempeño de esta tarea es en gran parte dependerá del código de red y el servidor externo, en el que el rendimiento del código de plataforma debe tener un efecto insignificante. Sin embargo referencial de Aaron muestran un aumento de velocidad del 50% sobre el código de roscado. Creo que es necesario respuesta a este aumento de velocidad aparente.

En el código de Nick, hay un defecto obvio que causó la ineficiencia. Pero ¿cómo se explica el aumento de la velocidad de 233ms por encima de mi código? Creo que incluso los aficionados retorcidos se abstengan de saltar a la conclusión atribuir esto a la eficiencia de trenzado. Hay, después de todo, una gran cantidad de variables fuera del código del sistema, como el de rendimiento, red, almacenamiento en caché y la implementación diferencia entre urllib2 y cliente web trenzado y así en el servidor remoto.

Sólo para asegurarse de enhebrado de Python no lo harát incurrir en una gran cantidad de ineficiencia, hago un punto de referencia rápida para desovar 5 hilos y luego 500 hilos. Estoy muy cómodo decir la sobrecarga de desove 5 hilo es insignificante y no puede explicar la diferencia de velocidad 233ms.

In [274]: %time run_parallel_in_threads(dummy_task, [(0,)]*5)
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.00 s
Out[275]: <Queue.Queue instance at 0x038B2878>

In [276]: %time run_parallel_in_threads(dummy_task, [(0,)]*500)
CPU times: user 0.16 s, sys: 0.00 s, total: 0.16 s
Wall time: 0.16 s

In [278]: %time run_parallel_in_threads(dummy_task, [(10,)]*500)
CPU times: user 1.13 s, sys: 0.00 s, total: 1.13 s
Wall time: 1.13 s       <<<<<<<< This means 0.13s of overhead

La prueba adicional en mis espectáculos captación en paralelo una gran variabilidad en el tiempo de respuesta en 17 carreras. (Por desgracia no me he torcido para verificar el código de Aaron).

0.75 s
0.38 s
0.59 s
0.38 s
0.62 s
1.50 s
0.49 s
0.36 s
0.95 s
0.43 s
0.61 s
0.81 s
0.46 s
1.21 s
2.87 s
1.04 s
1.72 s

Mi prueba no apoya la conclusión de que Aaron roscado es consistentemente más lento que asíncrono de E / S por un margen medible. Dado el número de variables implicadas, tengo que decir que esto no es una prueba válida para medir la diferencia de rendimiento sistemática entre asíncrono de E / S y roscado.

Otros consejos

trenzado ! Esto hace que este tipo de cosas absurdamente fácil en comparación con, por ejemplo, el uso de hilos.

from twisted.internet import defer, reactor
from twisted.web.client import getPage
import time

def processPage(page, url):
    # do somewthing here.
    return url, len(page)

def printResults(result):
    for success, value in result:
        if success:
            print 'Success:', value
        else:
            print 'Failure:', value.getErrorMessage()

def printDelta(_, start):
    delta = time.time() - start
    print 'ran in %0.3fs' % (delta,)
    return delta

urls = [
    'http://www.google.com/',
    'http://www.lycos.com/',
    'http://www.bing.com/',
    'http://www.altavista.com/',
    'http://achewood.com/',
]

def fetchURLs():
    callbacks = []
    for url in urls:
        d = getPage(url)
        d.addCallback(processPage, url)
        callbacks.append(d)

    callbacks = defer.DeferredList(callbacks)
    callbacks.addCallback(printResults)
    return callbacks

@defer.inlineCallbacks
def main():
    times = []
    for x in xrange(5):
        d = fetchURLs()
        d.addCallback(printDelta, time.time())
        times.append((yield d))
    print 'avg time: %0.3fs' % (sum(times) / len(times),)

reactor.callWhenRunning(main)
reactor.run()

Este código también se comporta mejor que cualquiera de las otras soluciones dejados (editadas después cerré algunas cosas que estaban utilizando una gran cantidad de ancho de banda):

Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 29996)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.518s
Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 30349)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.461s
Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 30033)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.435s
Success: ('http://www.google.com/', 8117)
Success: ('http://www.lycos.com/', 30349)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.449s
Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 30349)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.547s
avg time: 0.482s

Y el uso de código de Nick T, manipulado hasta también dan el promedio de cinco y muestran la mejor salida:

Starting threaded reads:
...took 1.921520 seconds ([8117, 30070, 15043, 8386, 28611])
Starting threaded reads:
...took 1.779461 seconds ([8135, 15043, 8386, 30349, 28611])
Starting threaded reads:
...took 1.756968 seconds ([8135, 8386, 15043, 30349, 28611])
Starting threaded reads:
...took 1.762956 seconds ([8386, 8135, 15043, 29996, 28611])
Starting threaded reads:
...took 1.654377 seconds ([8117, 30349, 15043, 8386, 28611])
avg time: 1.775s

Starting sequential reads:
...took 1.389803 seconds ([8135, 30147, 28611, 8386, 15043])
Starting sequential reads:
...took 1.457451 seconds ([8135, 30051, 28611, 8386, 15043])
Starting sequential reads:
...took 1.432214 seconds ([8135, 29996, 28611, 8386, 15043])
Starting sequential reads:
...took 1.447866 seconds ([8117, 30028, 28611, 8386, 15043])
Starting sequential reads:
...took 1.468946 seconds ([8153, 30051, 28611, 8386, 15043])
avg time: 1.439s

Y el uso de código de Albert Tung:

Fetched 8117 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30051 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.704s
Fetched 8117 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30114 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.845s
Fetched 8153 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30070 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.689s
Fetched 8117 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30114 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.647s
Fetched 8135 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30349 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.693s
avg time: 0.715s

Tengo que decir, me gusta que las recuperaciones secuenciales realizadas mejor para mí.

Aquí está un ejemplo utilizando Threads pitón. Los otros ejemplos roscados aquí lanzan un hilo por url, que no es un comportamiento muy amable si causa demasiados resultados para el servidor de manipular (por ejemplo, es común que las arañas que tienen muchas URL en el mismo host)

from threading import Thread
from urllib2 import urlopen
from time import time, sleep

WORKERS=1
urls = ['http://docs.python.org/library/threading.html',
        'http://docs.python.org/library/thread.html',
        'http://docs.python.org/library/multiprocessing.html',
        'http://docs.python.org/howto/urllib2.html']*10
results = []

class Worker(Thread):
    def run(self):
        while urls:
            url = urls.pop()
            results.append((url, urlopen(url).read()))

start = time()
threads = [Worker() for i in range(WORKERS)]
any(t.start() for t in threads)

while len(results)<40:
    sleep(0.1)
print time()-start

Nota: Los tiempos indicados aquí son para 40 direcciones URL y dependerán en gran medida de la velocidad de su conexión a Internet y la latencia al servidor. Estar en Australia, mi ping es> 300 ms

Con WORKERS=1 tardó 86 segundos para ejecutar
Con WORKERS=4 tardó 23 segundos para ejecutar
con WORKERS=10 tardó 10 segundos para ejecutar

así que tener 10 hilos de la descarga es de 8,6 veces más rápido que un solo hilo.

Esta es una versión mejorada que utiliza una cola. Hay por lo menos un par de ventajas.
1. Las direcciones URL se solicitan en el orden en que aparecen en la lista
2. ¿Se puede utilizar q.join() para detectar cuando las solicitudes se han completado todas
3. Los resultados se mantienen en el mismo orden que la lista de URL

from threading import Thread
from urllib2 import urlopen
from time import time, sleep
from Queue import Queue

WORKERS=10
urls = ['http://docs.python.org/library/threading.html',
        'http://docs.python.org/library/thread.html',
        'http://docs.python.org/library/multiprocessing.html',
        'http://docs.python.org/howto/urllib2.html']*10
results = [None]*len(urls)

def worker():
    while True:
        i, url = q.get()
        # print "requesting ", i, url       # if you want to see what's going on
        results[i]=urlopen(url).read()
        q.task_done()

start = time()
q = Queue()
for i in range(WORKERS):
    t=Thread(target=worker)
    t.daemon = True
    t.start()

for i,url in enumerate(urls):
    q.put((i,url))
q.join()
print time()-start

La espera real es probablemente no en urllib2 pero en el servidor y / o la conexión de red al servidor.

Hay 2 formas de acelerar esto.

  1. mantener la conexión viva (véase la pregunta sobre cómo hacer eso: Python urllib2 con mantener viva )
  2. Uso conexiones multiplle, se pueden utilizar hilos o un enfoque asíncrono como Aaron Gallagher sugerido. Para ello, basta con utilizar cualquier ejemplo roscado y que debe hacer bien :) También puede utilizar el lib multiprocessing para hacer las cosas bastante fácil.

La mayoría de las respuestas se centró en ir a buscar varias páginas desde diferentes servidores al mismo tiempo, (Threading), pero no en la reutilización de la conexión HTTP ya está abierto. Si OP está haciendo solicitud múltiple al mismo servidor / sitio.

En urlib2 se crea una conexión independiente con cada solicitud, que afecta al rendimiento y, y como resultado tasa más lenta de las páginas ir a buscar. urllib3 resuelve este problema utilizando un pool de conexiones. Puede leer más aquí urllib3 [También apta para subprocesos]

También hay solicitudes rel="nofollow"> una biblioteca de HTTP que utiliza urllib3

Esto, combinado con rosca debe aumentar la velocidad de ir a buscar páginas

Hoy en día existe una excelente lib Python que lo haga por usted llama href="http://docs.python-requests.org/" .

El uso de la API estándar de solicitudes si quieres solución basada en hilos o API asíncrona (utilizando GEvent bajo el capó) si desea que la solución basada en la no-bloqueo de IO.

Dado que esta cuestión se publicó, parece que hay un mayor nivel de abstracción disponibles, ThreadPoolExecutor:

https://docs.python.org/3/ biblioteca / # threadpoolexecutor-ejemplo concurrent.futures.html

El ejemplo de allí pegado aquí por conveniencia:

import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the url and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

También hay map que creo que hace que el código sea más fácil: https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.map

Ray ofrece una manera elegante de hacer esto (tanto en Python 2 y Python 3) . Ray es una biblioteca para la escritura paralela y distribuida Python.

Simplemente definir la función fetch con el decorador @ray.remote. A continuación, se puede recuperar una dirección URL en el fondo llamando fetch.remote(url).

import ray
import sys

ray.init()

@ray.remote
def fetch(url):
    if sys.version_info >= (3, 0):
        import urllib.request
        return urllib.request.urlopen(url).read()
    else:
        import urllib2
        return urllib2.urlopen(url).read()

urls = ['https://en.wikipedia.org/wiki/Donald_Trump',
        'https://en.wikipedia.org/wiki/Barack_Obama',
        'https://en.wikipedia.org/wiki/George_W._Bush',
        'https://en.wikipedia.org/wiki/Bill_Clinton',
        'https://en.wikipedia.org/wiki/George_H._W._Bush']

# Fetch the webpages in parallel.
results = ray.get([fetch.remote(url) for url in urls])

Si también desea procesar las páginas en paralelo, puede poner el código de procesamiento directamente en fetch, o puede definir una nueva función remota y componer juntos.

@ray.remote
def process(html):
    tokens = html.split()
    return set(tokens)

# Fetch and process the pages in parallel.
results = []
for url in urls:
    results.append(process.remote(fetch.remote(url)))
results = ray.get(results)

Si usted tiene una larga lista de direcciones URL que se desea obtener, es posible que desee emitir algunas tareas y luego procesarlos en el orden en que completen. Esto se puede hacer usando ray.wait.

urls = 100 * urls  # Pretend we have a long list of URLs.
results = []

in_progress_ids = []

# Start pulling 10 URLs in parallel.
for _ in range(10):
    url = urls.pop()
    in_progress_ids.append(fetch.remote(url))

# Whenever one finishes, start fetching a new one.
while len(in_progress_ids) > 0:
    # Get a result that has finished.
    [ready_id], in_progress_ids = ray.wait(in_progress_ids)
    results.append(ray.get(ready_id))
    # Start a new task.
    if len(urls) > 0:
        in_progress_ids.append(fetch.remote(urls.pop()))

Ray documentación .

Obtención las páginas web, obviamente, va a tomar un tiempo, ya que no está accediendo a nada local. Si tiene varios para el acceso, se puede utilizar la threading módulo para ejecutar una pareja en una vez.

Este es un ejemplo muy burdo

import threading
import urllib2
import time

urls = ['http://docs.python.org/library/threading.html',
        'http://docs.python.org/library/thread.html',
        'http://docs.python.org/library/multiprocessing.html',
        'http://docs.python.org/howto/urllib2.html']
data1 = []
data2 = []

class PageFetch(threading.Thread):
    def __init__(self, url, datadump):
        self.url = url
        self.datadump = datadump
        threading.Thread.__init__(self)
    def run(self):
        page = urllib2.urlopen(self.url)
        self.datadump.append(page.read()) # don't do it like this.

print "Starting threaded reads:"
start = time.clock()
for url in urls:
    PageFetch(url, data2).start()
while len(data2) < len(urls): pass # don't do this either.
print "...took %f seconds" % (time.clock() - start)

print "Starting sequential reads:"
start = time.clock()
for url in urls:
    page = urllib2.urlopen(url)
    data1.append(page.read())
print "...took %f seconds" % (time.clock() - start)

for i,x in enumerate(data1):
    print len(data1[i]), len(data2[i])

Esta fue la salida cuando me encontré con él:

Starting threaded reads:
...took 2.035579 seconds
Starting sequential reads:
...took 4.307102 seconds
73127 19923
19923 59366
361483 73127
59366 361483

Agarrando los datos de la rosca añadiendo a una lista es probablemente poco aconsejable (cola sería mejor) pero ilustra que hay una diferencia.

Aquí hay una solución biblioteca estándar. No es tan rápido, pero utiliza menos memoria que las soluciones de rosca.

try:
    from http.client import HTTPConnection, HTTPSConnection
except ImportError:
    from httplib import HTTPConnection, HTTPSConnection
connections = []
results = []

for url in urls:
    scheme, _, host, path = url.split('/', 3)
    h = (HTTPConnection if scheme == 'http:' else HTTPSConnection)(host)
    h.request('GET', '/' + path)
    connections.append(h)
for h in connections:
    results.append(h.getresponse().read())

Además, si la mayor parte de sus peticiones son a la misma máquina, a continuación, volver a utilizar la misma conexión HTTP, probablemente ayuda a más de hacer las cosas en paralelo.

Por favor, encontrar Python red guión de referencia para la identificación única conexión lentitud:

"""Python network test."""
from socket import create_connection
from time import time

try:
    from urllib2 import urlopen
except ImportError:
    from urllib.request import urlopen

TIC = time()
create_connection(('216.58.194.174', 80))
print('Duration socket IP connection (s): {:.2f}'.format(time() - TIC))

TIC = time()
create_connection(('google.com', 80))
print('Duration socket DNS connection (s): {:.2f}'.format(time() - TIC))

TIC = time()
urlopen('http://216.58.194.174')
print('Duration urlopen IP connection (s): {:.2f}'.format(time() - TIC))

TIC = time()
urlopen('http://google.com')
print('Duration urlopen DNS connection (s): {:.2f}'.format(time() - TIC))

Y el ejemplo de los resultados con Python 3.6:

Duration socket IP connection (s): 0.02
Duration socket DNS connection (s): 75.51
Duration urlopen IP connection (s): 75.88
Duration urlopen DNS connection (s): 151.42

Python 2.7.13 tiene resultados muy similares.

En este caso, DNS y lentitud urlopen se identifican fácilmente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top