Jaki jest najszybszy sposób na HTTP GET w Pythonie?

613

Jaki jest najszybszy sposób na HTTP GET w Pythonie, jeśli wiem, że zawartość będzie ciągiem? Przeszukuję dokumentację w celu znalezienia szybkiego linku, takiego jak:

contents = url.get("http://example.com/foo/bar")

Ale wszystko, co mogę znaleźć za pomocą Google są httplibi urllib- i jestem w stanie znaleźć skrót w tych bibliotekach.

Czy standardowy Python 2.5 ma skrót w jakiejś formie jak wyżej, czy powinienem napisać funkcję url_get?

  1. Wolałbym nie wychwytywać wyniku ostrzału do wgetlub curl.
Frank Krueger
źródło
Znalazłem to, czego potrzebowałem tutaj: stackoverflow.com/a/385411/1695680
ThorSummoner

Odpowiedzi:

870

Python 3:

import urllib.request
contents = urllib.request.urlopen("http://example.com/foo/bar").read()

Python 2:

import urllib2
contents = urllib2.urlopen("http://example.com/foo/bar").read()

Dokumentacja dla urllib.requesti read.

Nick Presta
źródło
44
Czy wszystko ładnie się porządkuje? Wygląda na to, że powinienem zadzwonić closepo ciebie read. Czy to konieczne?
Frank Krueger
4
Dobrą praktyką jest jej zamknięcie, ale jeśli szukasz szybkiego jednowierszowego, możesz go pominąć. :-)
Nick Presta
28
Obiekt zwrócony przez urlopen zostanie usunięty (i sfinalizowany, co go zamknie), gdy spadnie poza zakres. Ponieważ Cpython jest liczony jako referencja, możesz polegać na tym, co dzieje się natychmiast po read. Ale withblok byłby jaśniejszy i bezpieczniejszy dla Jython itp.
sah
8
Nie działa z witrynami wyłącznie HTTPS. requestsdziała dobrze
OverCoder
6
Jeśli używasz Amazon Lambda i potrzebujesz adresu URL, rozwiązanie 2.x jest dostępne i wbudowane. Wydaje się, że działa również z https. To nic więcej niż r = urllib2.urlopen("http://blah.com/blah")wtedy text = r.read(). Jest zsynchronizowany, po prostu czeka na wynik w „tekście”.
Fattie,
412

Możesz użyć biblioteki o nazwie żądania .

import requests
r = requests.get("http://example.com/foo/bar")

To całkiem proste. Następnie możesz zrobić tak:

>>> print(r.status_code)
>>> print(r.headers)
>>> print(r.content)
Alex K.
źródło
1
@JoeBlow pamiętaj, że musisz zaimportować biblioteki zewnętrzne, aby z nich skorzystać
MikeVelazco
1
Niemal każda biblioteka Pythona może być używana w AWS Lambda. W przypadku czystego Pythona wystarczy „sprzedać” tę bibliotekę (zamiast kopiować do folderów modułu pip install). W przypadku bibliotek nieczystych istnieje dodatkowy krok - musisz pip installprzenieść bibliotekę lib na instancję systemu AWS Linux (pod tą samą wersją systemu operacyjnego lambda), a następnie skopiować te pliki, aby uzyskać zgodność binarną z systemem AWS Linux. Jedynymi bibliotekami, których nie zawsze będziesz mógł używać w Lambda, są tylko biblioteki z dystrybucjami binarnymi, które na szczęście są dość rzadkie.
Chris Johnson
6
@lawphotog to DZIAŁA z python3, ale musisz pip install requests.
akarilimano
Nawet standardowa biblioteka urllib2 poleca żądania
Asfand Qazi
W odniesieniu do Lambda: jeśli chcesz używać żądań w funkcjach AWS Lambda. Jest też preinstalowana biblioteka żądań boto3. from botocore.vendored import requests Sposób użycia response = requests.get('...')
kmjb,
29

Jeśli chcesz, aby rozwiązanie z httplib2 było jednym narzędziem, zastanów się nad utworzeniem anonimowego obiektu HTTP

import httplib2
resp, content = httplib2.Http().request("http://example.com/foo/bar")
to-chomik
źródło
19

Spójrz na httplib2 , który - obok wielu bardzo przydatnych funkcji - zapewnia dokładnie to, czego chcesz.

import httplib2

resp, content = httplib2.Http().request("http://example.com/foo/bar")

Gdzie treść byłaby treścią odpowiedzi (jako ciąg), a resp zawierałaby nagłówki statusu i odpowiedzi.

Nie jest on dołączony do standardowej instalacji Pythona (ale wymaga tylko standardowego Pythona), ale zdecydowanie warto to sprawdzić.

hennr
źródło
6

Jest to dość proste dzięki potężnej urllib3bibliotece.

Zaimportuj to w ten sposób:

import urllib3

http = urllib3.PoolManager()

I zrób taką prośbę:

response = http.request('GET', 'https://example.com')

print(response.data) # Raw data.
print(response.data.decode('utf-8')) # Text.
print(response.status) # Status code.
print(response.headers['Content-Type']) # Content type.

Możesz także dodać nagłówki:

response = http.request('GET', 'https://example.com', headers={
    'key1': 'value1',
    'key2': 'value2'
})

Więcej informacji można znaleźć w dokumentacji urllib3 .

urllib3jest o wiele bezpieczniejsze i łatwiejsze w użyciu niż polecenie wbudowane urllib.requestlub httpmoduły i jest stabilny.

Juniorized
źródło
1
świetnie, ponieważ możesz łatwo podać czasownik HTTP
Tom
5

rozwiązanie theller dla wget jest naprawdę przydatne, ale stwierdziłem, że nie drukuje postępu w trakcie pobierania. Jest to idealne, jeśli dodasz jeden wiersz po wyciągu drukowanym w raporcie zaczepu.

import sys, urllib

def reporthook(a, b, c):
    print "% 3.1f%% of %d bytes\r" % (min(100, float(a * b) / c * 100), c),
    sys.stdout.flush()
for url in sys.argv[1:]:
    i = url.rfind("/")
    file = url[i+1:]
    print url, "->", file
    urllib.urlretrieve(url, file, reporthook)
print
Xuan
źródło
4

Oto skrypt wget w Pythonie:

# From python cookbook, 2nd edition, page 487
import sys, urllib

def reporthook(a, b, c):
    print "% 3.1f%% of %d bytes\r" % (min(100, float(a * b) / c * 100), c),
for url in sys.argv[1:]:
    i = url.rfind("/")
    file = url[i+1:]
    print url, "->", file
    urllib.urlretrieve(url, file, reporthook)
print
tym bardziej
źródło
4

Bez dalszych importów to rozwiązanie działa (dla mnie) - także z https:

try:
    import urllib2 as urlreq # Python 2.x
except:
    import urllib.request as urlreq # Python 3.x
req = urlreq.Request("http://example.com/foo/bar")
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36')
urlreq.urlopen(req).read()

Często mam problemy z pobieraniem treści, gdy nie podaje się „User-Agent” w informacjach nagłówka. Następnie zwykle żądania są anulowane za pomocą: urllib2.HTTPError: HTTP Error 403: Forbiddenlub urllib.error.HTTPError: HTTP Error 403: Forbidden.

michael_s
źródło
4

Jak również wysyłać nagłówki

Python 3:

import urllib.request
contents = urllib.request.urlopen(urllib.request.Request(
    "https://api.github.com/repos/cirosantilli/linux-kernel-module-cheat/releases/latest",
    headers={"Accept" : 'application/vnd.github.full+json"text/html'}
)).read()
print(contents)

Python 2:

import urllib2
contents = urllib2.urlopen(urllib2.Request(
    "https://api.github.com",
    headers={"Accept" : 'application/vnd.github.full+json"text/html'}
)).read()
print(contents)
Ciro Santilli
źródło
2

Jeśli pracujesz w szczególności z interfejsami API HTTP, istnieją również wygodniejsze opcje, takie jak Nap .

Oto na przykład, jak zdobyć informacje z Github od 1 maja 2014 r . :

from nap.url import Url
api = Url('https://api.github.com')

gists = api.join('gists')
response = gists.get(params={'since': '2014-05-01T00:00:00Z'})
print(response.json())

Więcej przykładów: https://github.com/kimmobrunfeldt/nap#examples

Kimmo
źródło
2

Doskonałe rozwiązania Xuan, Theller.

Aby działał z Pythonem 3, wprowadź następujące zmiany

import sys, urllib.request

def reporthook(a, b, c):
    print ("% 3.1f%% of %d bytes\r" % (min(100, float(a * b) / c * 100), c))
    sys.stdout.flush()
for url in sys.argv[1:]:
    i = url.rfind("/")
    file = url[i+1:]
    print (url, "->", file)
    urllib.request.urlretrieve(url, file, reporthook)
print

Ponadto podany adres URL powinien być poprzedzony „http: //”, w przeciwnym razie zwraca błąd nieznanego typu adresu URL.

Akshar
źródło
1

Dla python >= 3.6, można użyć DLOAD :

import dload
t = dload.text(url)

Dla json:

j = dload.json(url)

Zainstalować:
pip install dload

CONvid19
źródło
0

Właściwie w pythonie możemy czytać z adresów URL jak z plików, oto przykład odczytu jsona z API.

import json

from urllib.request import urlopen

with urlopen(url) as f:

resp = json.load(f)

return resp['some_key']
Katrych Taras
źródło
Chociaż dziękujemy za odpowiedź, byłoby lepiej, gdyby stanowiła dodatkową wartość oprócz innych odpowiedzi. W takim przypadku Twoja odpowiedź nie zapewnia dodatkowej wartości, ponieważ inny użytkownik już opublikował to rozwiązanie. Jeśli poprzednia odpowiedź była dla Ciebie pomocna, powinieneś głosować zamiast powtarzać te same informacje.
Toby Speight,
0

Jeśli chcesz interfejsu API niższego poziomu:

import http.client

conn = http.client.HTTPSConnection('example.com')
conn.request('GET', '/')

resp = conn.getresponse()
content = resp.read()

conn.close()

text = content.decode('utf-8')

print(text)
Juniorized
źródło