Apakah ada cara mudah untuk meminta URL dengan python dan TIDAK mengikuti pengalihan?

101

Melihat sumber urllib2, sepertinya cara termudah untuk melakukannya adalah dengan subclass HTTPRedirectHandler dan kemudian menggunakan build_opener untuk mengganti HTTPRedirectHandler default, tetapi ini sepertinya banyak pekerjaan (relatif rumit) untuk melakukan apa yang seharusnya dilakukan. cukup mudah.

John
sumber
2
Untuk googler: menggunakan pustaka permintaan akan menghemat banyak sakit kepala: docs.python-requests.org dan lihat jawaban Marian di bawah, ini sangat elegan.
Alojz Janez
Saya setuju bahwa permintaan adalah cara yang harus ditempuh hari ini. Saya telah memberi suara positif pada komentar ini dan jawaban Marian, tetapi saya membiarkan jawaban itu diberikan karena itu yang terbaik saat itu.
Yohanes
1
Penghargaan @John bagus tapi waktu terus berjalan dan ini adalah situs komunitas yang diedit. Fokusnya adalah pada jawaban yang baik dan bukan pada orang-orangnya. Dia akan mempertahankan poin upvote-nya. Anda menyesatkan banyak rekan pembuat kode ke perpustakaan yang tidak digunakan lagi.
mit
1
OK cukup adil. Saya telah menerima jawaban permintaan.
Yohanes

Jawaban:

186

Berikut adalah cara Permintaan :

import requests
r = requests.get('http://github.com', allow_redirects=False)
print(r.status_code, r.headers['Location'])
Marian
sumber
6
Kemudian lihat r.headers['Location']untuk melihat ke mana ia akan mengirim Anda
patricksurry
Perhatikan bahwa tampaknya Permintaan akan dinormalisasi Locationmenjadi location.
Hamish
2
@Hamish requestsmemungkinkan Anda mengakses header baik dalam bentuk kanonik maupun dalam huruf kecil. Lihat docs.python-requests.org/en/master/user/quickstart/…
Marian
1
Mulai 2019 di Python 3, ini sepertinya tidak lagi berfungsi untuk saya. (Saya mendapatkan kesalahan dikt kunci.)
Max von Hippel
36

Dive Into Python memiliki bab bagus tentang menangani pengalihan dengan urllib2. Solusi lain adalah httplib .

>>> import httplib
>>> conn = httplib.HTTPConnection("www.bogosoft.com")
>>> conn.request("GET", "")
>>> r1 = conn.getresponse()
>>> print r1.status, r1.reason
301 Moved Permanently
>>> print r1.getheader('Location')
http://www.bogosoft.com/new/location
olt
sumber
7
Setiap orang yang datang ke sini dari Google, harap perhatikan bahwa cara terkini untuk pergi adalah yang ini: stackoverflow.com/a/14678220/362951 Pustaka permintaan akan menghemat banyak sakit kepala.
mit
Tautan ke "Dive Into Python" sudah mati.
guettli
11

Ini adalah penangan urllib2 yang tidak akan mengikuti pengalihan:

class NoRedirectHandler(urllib2.HTTPRedirectHandler):
    def http_error_302(self, req, fp, code, msg, headers):
        infourl = urllib.addinfourl(fp, headers, req.get_full_url())
        infourl.status = code
        infourl.code = code
        return infourl
    http_error_300 = http_error_302
    http_error_301 = http_error_302
    http_error_303 = http_error_302
    http_error_307 = http_error_302

opener = urllib2.build_opener(NoRedirectHandler())
urllib2.install_opener(opener)
Carles Barrobés
sumber
Saya menguji unit API dan berurusan dengan metode login yang mengalihkan ke halaman yang tidak saya pedulikan, tetapi tidak mengirimkan cookie sesi yang diinginkan dengan respons terhadap pengalihan. Inilah yang saya butuhkan untuk itu.
Tim Wilder
9

Kata redirectionskunci dalam httplib2metode permintaan adalah ikan haring merah. Daripada mengembalikan permintaan pertama, ia akan memunculkan RedirectLimitpengecualian jika menerima kode status pengalihan. Untuk mengembalikan respon inital Anda perlu set follow_redirectsuntuk Falsedi Httpobyek:

import httplib2
h = httplib2.Http()
h.follow_redirects = False
(response, body) = h.request("http://example.com")
Ian Mackinnon
sumber
8

saya kira ini akan membantu

from httplib2 import Http
def get_html(uri,num_redirections=0): # put it as 0 for not to follow redirects
conn = Http()
return conn.request(uri,redirections=num_redirections)
Ashish
sumber
5

Saya penunjuk kedua untuk Menyelam ke Python . Berikut adalah implementasi menggunakan penangan pengalihan urllib2, lebih banyak pekerjaan daripada yang seharusnya? Mungkin, angkat bahu.

import sys
import urllib2

class RedirectHandler(urllib2.HTTPRedirectHandler):
    def http_error_301(self, req, fp, code, msg, headers):  
        result = urllib2.HTTPRedirectHandler.http_error_301( 
            self, req, fp, code, msg, headers)              
        result.status = code                                 
        raise Exception("Permanent Redirect: %s" % 301)

    def http_error_302(self, req, fp, code, msg, headers):
        result = urllib2.HTTPRedirectHandler.http_error_302(
            self, req, fp, code, msg, headers)              
        result.status = code                                
        raise Exception("Temporary Redirect: %s" % 302)

def main(script_name, url):
   opener = urllib2.build_opener(RedirectHandler)
   urllib2.install_opener(opener)
   print urllib2.urlopen(url).read()

if __name__ == "__main__":
    main(*sys.argv) 
Aaron Maenpaa
sumber
3
Kelihatannya salah ... Kode ini benar-benar mengikuti pengalihan (dengan memanggil penangan asli, sehingga mengeluarkan permintaan HTTP), dan kemudian meningkatkan pengecualian
Carles Barrobés
5

Namun cara terpendek adalah

class NoRedirect(urllib2.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, hdrs, newurl):
        pass

noredir_opener = urllib2.build_opener(NoRedirect())
Tzury Bar Yochay
sumber
1
Bagaimana ini jalan terpendek? Itu bahkan tidak berisi impor atau permintaan sebenarnya.
Marian
Saya sudah akan memposting solusi ini dan cukup terkejut menemukan jawaban ini di bagian bawah. Ini sangat ringkas dan harus menjadi jawaban teratas menurut saya.
pengguna
Selain itu, ini memberi Anda lebih banyak kebebasan, dengan cara ini dimungkinkan untuk mengontrol URL mana yang harus diikuti .
pengguna
Saya menegaskan, ini adalah cara termudah. Komentar singkat untuk mereka yang ingin melakukan debug. Jangan lupa bahwa Anda dapat mengatur multiples handler saat melibas pembuka seperti: opener = urllib.request.build_opener(debugHandler, NoRedirect())where debugHandler=urllib.request.HTTPHandler()dan debugHandler.set_http_debuglevel (1). Akhirnya:urllib.request.install_opener(opener)
StashOfCode