Python — Пример асинхронного / поточного запроса urllib2 с использованием HTTPS

#python #multithreading #urllib2

#python #многопоточность #urllib2

Вопрос:

Мне чертовски сложно заставить асинхронные / многопоточные HTTPS-запросы работать с использованием urllib2 в Python.

Есть ли у кого-нибудь базовый пример, который реализует urllib2.Request, urllib2.build_opener и подкласс urllib2.HTTPSHandler?

Спасибо!

Комментарии:

1. добро пожаловать в SO…do у вас есть пример того, что у вас сейчас не работает? Может быть проще диагностировать, чем начинать с нуля в ответе здесь…

2. Существует ли правило, согласно которому каждый вопрос должен быть «отлаживать мой код»? Мой код полон сумасшедших ссылок на переменные, которые я бы предпочел не объяснять, конфиденциальные URL и т.д. Это 10 строк кода для тех, кто знает, как это сделать.

3. Я вижу, что принятого ответа нет. Вы все еще заинтересованы в этом? Я решил эту проблему несколько дней назад, поэтому я мог бы потратить время на написание подробного ответа с кодом..

Ответ №1:

Приведенный ниже код выполняет 7 http-запросов асинхронно одновременно. Он не использует потоки, вместо этого он использует асинхронную сеть с twisted библиотекой.

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

urls = [
 'http://www.python.org', 
 'http://stackoverflow.com', 
 'http://www.twistedmatrix.com', 
 'http://www.google.com',
 'http://launchpad.net',
 'http://github.com',
 'http://bitbucket.org',
]

def finish(results):
    for result in results:
        print 'GOT PAGE', len(result), 'bytes'
    reactor.stop()

waiting = [client.getPage(url) for url in urls]
defer.gatherResults(waiting).addCallback(finish)

reactor.run()
  

Комментарии:

1. Я бы предпочел не распространять мой скрипт с искаженным требованием. Можете ли вы сделать это с помощью встроенных urllib2.Request, urllib2.build_opener и подкласса urllib2.HTTPSHandler?

2. @SeaTurtle: Twisted имеет открытый исходный код и написан на чистом python. Вы могли бы получить соответствующие части из twisted и включить в свой код. Другими словами — рассматривайте сам twisted как пример того, как это можно сделать с помощью встроенных модулей.

Ответ №2:

есть действительно простой способ, включающий обработчик для urllib2, который вы можете найти здесь: http://pythonquirks.blogspot.co.uk/2009/12/asynchronous-http-request.html

 #!/usr/bin/env python

import urllib2
import threading

class MyHandler(urllib2.HTTPHandler):
    def http_response(self, req, response):
        print "url: %s" % (response.geturl(),)
        print "info: %s" % (response.info(),)
        for l in response:
            print l
        return response

o = urllib2.build_opener(MyHandler())
t = threading.Thread(target=o.open, args=('http://www.google.com/',))
t.start()
print "I'm asynchronous!"

t.join()

print "I've ended!"
  

Комментарии:

1. Я просто хотел бы предупредить, что, хотя этот метод прост и быстр, он очень подвержен проблемам, когда что-то ломается (например, URL недоступен). На есть хорошее руководство для начинающих по обработке потоковibm.com/developerworks/aix/library/au-threadingpython который включает в себя очень простой пример асинхронного решения urllib2.

2. нет. это блокирует ввод-вывод. здесь вы не получаете преимуществ многопоточности. вы просто разделяете всю задачу на временные отрезки. таким образом, общее время будет таким же.

Ответ №3:

вот пример использования urllib2 (с https) и потоков. Каждый поток циклически просматривает список URL-адресов и извлекает ресурс.

 import itertools
import urllib2
from threading import Thread


THREADS = 2
URLS = (
    'https://foo/bar',
    'https://foo/baz',
    )


def main():
    for _ in range(THREADS):
        t = Agent(URLS)
        t.start()


class Agent(Thread):
    def __init__(self, urls):
        Thread.__init__(self)
        self.urls = urls

    def run(self):
        urls = itertools.cycle(self.urls)
        while True:
            data = urllib2.urlopen(urls.next()).read()


if __name__ == '__main__':
    main()
  

Ответ №4:

Для этого можно использовать асинхронный ввод-вывод.

Запросы gevent = grequests

GRequests позволяет использовать запросы с Gevent для простого выполнения асинхронных HTTP-запросов.

 import grequests

urls = [
    'http://www.heroku.com',
    'http://tablib.org',
    'http://httpbin.org',
    'http://python-requests.org',
    'http://kennethreitz.com'
]

rs = (grequests.get(u) for u in urls)
grequests.map(rs)
  

Ответ №5:

вот код из eventlet

 urls = ["http://www.google.com/intl/en_ALL/images/logo.gif",
     "https://wiki.secondlife.com/w/images/secondlife.jpg",
     "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif"]

import eventlet
from eventlet.green import urllib2

def fetch(url):

  return urllib2.urlopen(url).read()

pool = eventlet.GreenPool()

for body in pool.imap(fetch, urls):
  print "got body", len(body)
  

Комментарии:

1. Привет, я бы предпочел не распространять свой скрипт с требованием eventlet. Можете ли вы сделать это с помощью встроенных urllib2.Request, urllib2.build_opener и подкласса urllib2.HTTPSHandler?

2. Нет, это невозможно. Более того, если я прав, это работает только под Linux.