вторник, 11 декабря 2012 г.

Python PycURL HTTP запросы на получение контента

Получение какого-либо содержимого, находящегося по данному URL через PycURL.


import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://news.ycombinator.com')
c.perform()


Данный код выполнит GET-запрос по заданному URL и выведет полученные в ответе данные в стандартный поток вывода stdout.

Сначала создается новый объект Curl, затем устанавливаются опции для передачи URL внутрь объекта для дальнейшей обработки, после чего вызывается метод объект perform(), который выполняет HTTP-запрос по заданному URL.

Данный код является типичным примером работы PycURL: создание объекта, установка опций и выполнение запроса.

Далее мы рассмотрим как выводить полученный от сервера ответ в переменную вместо стандартного потока вывода stdout.


import pycurl
import cStringIO

buf = cStringIO.StringIO()

c = pycurl.Curl()
c.setopt(c.URL, 'http://news.ycombinator.com')
c.setopt(c.WRITEFUNCTION, buf.write)
c.perform()

print buf.getvalue()
buf.close()


Здесь мы используем строковый буфер, который позволяет cURL записывать полученный от сервера ответ в него. Устанавливая опцию WRITEFUNCTION и указывая ей записать ответ сервера в буфер, мы можем перехватить поток вывода как только будет вызван метод perform(). Вы так же можете использовать StringIO вместо cStringIO, но последний работает быстрее.
Обратите внимание, что опять поведение объекта задается через опции setopt().


Если вам надо, чтобы ваш запрос прошел через прокси, а также установить таймауты на соединение и чтение полученных данных, то используйте этот код:



import pycurl
import cStringIO

buf = cStringIO.StringIO()

c = pycurl.Curl()
c.setopt(c.URL, 'http://news.ycombinator.com')
c.setopt(c.WRITEFUNCTION, buf.write)
c.setopt(c.CONNECTTIMEOUT, 5)
c.setopt(c.TIMEOUT, 8)
c.setopt(c.PROXY, 'http://inthemiddle.com:8080')
c.perform()

print buf.getvalue()
buf.close()


Откуда мы знаем какую опцию мы можем использовать и что она делает? Легко! Перейдите по ссылке http://curl.haxx.se/libcurl/c/curl_easy_setopt.html и найдите опцию, которая вам нужна. Установите опцию в метод setopt(). Но не устанавливайте опцию "CURLOPT_" так как PycURL устанавливает ее за вас автоматически, так что вам не нужно вводить "CURLOPT_" каждый раз).

Далее попробуем выполнить POST-запрос.


import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://myfavpizzaplace.com/order')
c.setopt(c.POSTFIELDS, 'pizza=Quattro+Stagioni&extra=cheese')
c.perform()


Установкой опции POSTFIELDS запрос автоматически будет послан как POST-запрос. POST-запрос предназначен для передачи значений из форм. Значения должны быть закодированы через URL-encode (использую urllib.urlencode()).

Если что-то происходит не так как вы ожидали, то вы можете вывести сырой запрос, используя опцию VERBOSE.


import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://myfavpizzaplace.com/order')
c.setopt(c.POSTFIELDS, 'pizza=Quattro+Stagioni&extra=cheese')
c.setopt(c.VERBOSE, True)
c.perform()


Установка опции VERBOSE выведет информацию в стандартный поток вывода stdout, после чего вы сможете разобраться с тем, что происходит с соединением при создании HTTP-запроса и узнать какие заголовки и ответ возвращаются обратно от сервера.

Далее поработаем с cookie. Установить в запросе cookie очень просто.


import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://myappserver.com/ses1')
c.setopt(c.COOKIEFILE, '')
c.setopt(c.VERBOSE, True)
c.perform()

c.setopt(c.URL, 'http://myappserver.com/ses2')
c.perform()


Давайте представим, что myappserver.com/ses1 создает сессию, используя сессионную cookie, а так же устанавливает обычные cookie, которые необходимо передать myappserver.com/ses1. Так что cookie надо послать серверу во время второго запроса.
Здесь мы создаем 1 объект Curl и выполняем 2 запроса. В этом случае при повторном запросе используются те же опции, что и для первого до тех пор пока они не будут перезаписаны. В этом случае мы устанавливаем опцию COOKIEFILE которая обычно используется для установки пути для записи файла c cookie, посланного сервером как HTTP Cookie header. Однако мы устанавливаем значение пути в виде пустой строки, что делает cURL cookie-безопасным,  врезультате чего все присланные cookie будут пересланы подзапросам.
Поскольку мы установили опцию VERBOSE, то мы увидим что происходит во время выполнения запросов.

Вот более эффективная версия предыдущего кода.

import pycurl

c = pycurl.Curl()
c.setopt(c.URL, 'http://myappserver.com/ses1')
c.setopt(c.CONNECTTIMEOUT, 5)
c.setopt(c.TIMEOUT, 8)
c.setopt(c.COOKIEFILE, '')
c.setopt(c.FAILONERROR, True)
c.setopt(c.HTTPHEADER, ['Accept: text/html', 'Accept-Charset: UTF-8'])
try:
    c.perform()

    c.setopt(c.URL, 'http://myappserver.com/ses2')
    c.setopt(c.POSTFIELDS, 'foo=bar&bar=foo')
    c.perform()
except pycurl.error, error:
    errno, errstr = error
    print 'An error occurred: ', errstr



В данном примере мы просто прописали таймауты. Вы всегда должны так делать в реальных проектах. А также добавили HTTP заголовки и установили опцию FAILONERROR чтобы cURL в случае получения HTTP-кода больше или равного коду 400 завершал программу. В этом случае PycURL выбросит исключение, которое позволит разобраться в ситуации.

Для выполнения нескольких параллельных запросов одновременно вы можете использовать объект CurlMulti, о котором вы можете прочитать в документации по адресу http://pycurl.sourceforge.net/doc/curlmultiobject.html

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

Отправить комментарий