Обёртка для pycurl

Уже пару лет я периодически пользуюсь пакетом pycurl для того, чтобы чего-нить распарсить из сети. Библиотека pycurl хороша тем, что она предоставляет в меру простой интерфейс к мощному функционалу и, что важно для меня, позволяет работать с любыми типами прокси: http, https, socks4, socks5. Стандартная библиотека urllib2 не предоставляет возможности работать с socks проксями. Я пробовал искать решения — не нашёл. Самому написать некую обёртку urllib2 & socks у меня мозгов не хватает. Вот тут pycurl и выручает :-)

Так вот, интерфейс у него простой… даже слишком. Поэтому я довольно быстро отказался от родного pycurl API и набросал свой велосипедик. Его код показывать людям нельзя т.к. писал я его на заре изучения питона и, соответственно, он страшненький. Недавно я начал переписывать обёртку с нуля. За проектом можно следить по адресу: http://bitbucket.org/lorien/grab/ Проект назван grab т.к. кроме очевидной задачи сделать более удобный API к pycurl, я преследую цель написать инструмент облегчающий парсинг, грабинг, скрэйпинг вебсайтов.

Рассмотрим пример работы с pycurl с официального сайта http://pycurl.sourceforge.net/doc/curlobject.html

import pycurl
c = pycurl.Curl()
c.setopt(pycurl.URL, "http://www.python.org/")
import StringIO
b = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, b.write)
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(pycurl.MAXREDIRS, 5)
c.perform()
print b.getvalue()

C помощью библиотеки grab пример преобразится в:

from grab import Grab
grab = Grab()
grab.setup(url='http://python.org/')
print grab.request()['body']

На самом деле для одиночных запросов у меня есть shortcut, который позволяет:

from grab import request
print request('http://python.org/')['body']

Естественно, такие простые запросы можно и нужно делать через urllib/urllib2. Выгода использования pycurl проявляется, когда нужно реализовывать сложные запросы, типа работы с socks проксями.

Add post to:   Delicious Reddit Slashdot Digg Technorati Google
Make comment

Pingbacks

15.09.2009 16:57 Обёртки для pycurl | Python for SEO @python4seo.ru
В своё время узнал про две обёртки для pycurl. Первая – grab, вторая – pylibcurl, ctypes обертка не требует установки pycurl‘а. Собственно, я ими даже не пользовался, пытался начать, но забрасывал, зря, конечно. А на данный

Comments

hrundelok 9.03.2009 9:42

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

print requestI(‘http://python.org/’, slice=’body’)

voldmar 9.03.2009 11:00

У простых запросов через urllib2 есть серьёзный недостаток — нельзя таймаут указывать.

Можно, но он будет один для всех, насколько я понимаю:

import socket
socket.setdefaulttimeout(10)

Кстати, я смотрел маны python 2.6 — у функции urlopen появился новый параметр timeout.

Changed in version 2.6: timeout was added.
voldmar 10.03.2009 8:19

У меня были проблемы с setdefaulttimeout, а 2.6 на боевых серверах ещё ждать и ждать.

Чё-то я не вижу ничего особо питоничного тут :-) Я бы так в PHP сделал в той версии, где нельзя было по индексу обращаться к результату функции (может и до сих пор нельзя ^_^).

Кстати, я особо результатом вызова request() не пользуюсь. Дело в том, что тело http ответа сохраняется в аттрибут response_body объекта grab. К нему я и обращаюсь.

Я тут парочку примеров накидал.

А вообще, может быть, сделаю, чтобы request() возвращал объект с нужными аттрибутами т.е.

resp = g.request()
print resp.body
print resp.headers
тореодор 11.03.2009 16:19

я думую так будет лучше

* grab.py 2009-08-05 02:04:32.000000000 +0400 – grab_mod.py 2009-08-05 01:59:19.000000000 +0400


* 349,356 ** ‘status’: self.response_status, ‘get_soup’: lambda: self.soup, } ! ! return response

  def response_time(self):

– 349,357 –- ‘status’: self.response_status, ‘get_soup’: lambda: self.soup, } ! resp_class = type(‘response’,(dict,),response)() ! resp_class.update(response) ! return resp_class

  def response_time(self):

А с куками можно работать?

Можно. Вот тут я набросал документацию на русском.

Глеб 10.04.2009 22:03

в html.py сделал так: guess_encodings = [match.group(1)] + guess_encodings Иначе оно хоть и убирало дубликаты кодировок, но зато все 1251 страницы декодировало как koi8. Python2.5. Мож поможет кому )

Ага, спасибо. Внёс вашу правку в репозиторий.

Required. 30 chars of fewer.

Required.

captcha image Please, enter symbols, which you see on the image