PDF dosyasını Python istek modülü ile indirin ve kaydedin


87

Bir web sitesinden bir PDF dosyası indirmeye ve diske kaydetmeye çalışıyorum. Denemelerim ya kodlama hatalarıyla başarısız oluyor ya da boş PDF'lerle sonuçlanıyor.

In [1]: import requests

In [2]: url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'

In [3]: response = requests.get(url)

In [4]: with open('/tmp/metadata.pdf', 'wb') as f:
   ...:     f.write(response.text)
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-4-4be915a4f032> in <module>()
      1 with open('/tmp/metadata.pdf', 'wb') as f:
----> 2     f.write(response.text)
      3 

UnicodeEncodeError: 'ascii' codec can't encode characters in position 11-14: ordinal not in range(128)

In [5]: import codecs

In [6]: with codecs.open('/tmp/metadata.pdf', 'wb', encoding='utf8') as f:
   ...:     f.write(response.text)
   ...: 

Bunun bir tür codec sorunu olduğunu biliyorum ama işe yarayacak gibi görünmüyorum.

Yanıtlar:


176

response.contentBu durumda kullanmalısınız :

with open('/tmp/metadata.pdf', 'wb') as f:
    f.write(response.content)

Gönderen belgede :

Metin olmayan istekler için yanıt gövdesine bayt olarak da erişebilirsiniz:

>>> r.content
b'[{"repository":{"open_issues":0,"url":"https://github.com/...

Bu şu anlama gelir: response.textçıktıyı bir dizge nesnesi olarak döndür, bir metin dosyası indirirken onu kullan . HTML dosyası vb.

Ve response.contentçıktıyı bayt nesnesi olarak döndürün, bir ikili dosya indirirken kullanın . PDF dosyası, ses dosyası, resim vb.


Bunun response.rawyerine de kullanabilirsiniz . Ancak, indirmek üzere olduğunuz dosya büyük olduğunda kullanın. Aşağıda, belgede de bulabileceğiniz temel bir örnek bulunmaktadır:

import requests

url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'
r = requests.get(url, stream=True)

with open('/tmp/metadata.pdf', 'wb') as fd:
    for chunk in r.iter_content(chunk_size):
        fd.write(chunk)

chunk_sizekullanmak istediğiniz yığın boyutudur. Bunu olarak ayarlarsanız 2000, istekler o dosyayı ilk 2000baytları indirir, bunları dosyaya yazar ve tamamlamadıkça bunu tekrar tekrar yapar.

Bu, RAM'inizi kurtarabilir. Ancak response.content, dosyanız küçük olduğu için bu durumda bunun yerine kullanmayı tercih ederim . Gördüğünüz gibi kullanımı response.rawkarmaşık.


İlişkili:


Harika, response.raw hakkındaki ek bilgiler için teşekkür ederim
Jim

23

Python 3'te, pathlib'in bunu yapmanın en kolay yolu olduğunu düşünüyorum. İsteğin response.content evlenmekteydi kadar güzel pathlib en write_bytes ile.

from pathlib import Path
import requests
filename = Path('metadata.pdf')
url = 'http://www.hrecos.org//images/Data/forweb/HRTVBSH.Metadata.pdf'
response = requests.get(url)
filename.write_bytes(response.content)

1
Bunu gönderdiğiniz için teşekkürler. Asıl soru Python 2.7 idi, ancak devam ettim ve şimdi Python 3 kullanıyorum. Pathlib kitaplığı [3.4 sürümünde yeni] hakkında bilgi sahibi değildim ve mevcut projelerime dahil edeceğim.
Jim

Verdi 544ve dosya bozuldu, herhangi bir fikrin var mı?
ahbon

@ahbon, ne demek istiyorsun?
user6481870

14

Urllib'i kullanabilirsiniz:

import urllib.request
urllib.request.urlretrieve(url, "filename.pdf")

1
Bu en iyisi, tbh.
Dhaval Savalia

Bu en iyisi
roktim

1
urlretrieveistek başlıklarını belirlemek için genel ayarları kullanır ve bu da bazı kullanım durumları için uygunsuz hale getirir.
Michael Crenshaw

5

Genel olarak, bu Python3'te çalışmalıdır:

import urllib.request 
..
urllib.request.get(url)

Urllib ve urllib2'nin Python2'den sonra düzgün çalışmadığını unutmayın.

Bazı gizemli durumlarda istekler işe yaramazsa (benim başıma geldiyse), kullanmayı da deneyebilirsiniz.

wget.download(url)

İlişkili:

İşte bir web sayfasındaki tüm pdf dosyalarını bulup indirmek için iyi bir açıklama / çözüm:

https://medium.com/@dementorwriter/notesdownloader-use-web-scraping-to-download-all-pdfs-with-python-511ea9f55e48


2

Lütfen yeni başlayan olduğumu unutmayın. Çözümüm yanlışsa lütfen düzeltmekten çekinmeyin ve / veya bana bildirin. Ben de yeni bir şeyler öğrenebilirim.

Çözümüm:

DownloadPath'i dosyanızın kaydedilmesini istediğiniz yere göre değiştirin . Kullanımınız için de mutlak yolu kullanmaktan çekinmeyin.

Aşağıdakileri downloadFile.py olarak kaydedin.

Kullanım: python downloadFile.py url-of-the-file-to-download new-file-name.extension

Bir uzantı eklemeyi unutmayın!

Örnek kullanım: python downloadFile.py http://www.google.co.uk google.html

import requests
import sys
import os

def downloadFile(url, fileName):
    with open(fileName, "wb") as file:
        response = requests.get(url)
        file.write(response.content)


scriptPath = sys.path[0]
downloadPath = os.path.join(scriptPath, '../Downloads/')
url = sys.argv[1]
fileName = sys.argv[2]      
print('path of the script: ' + scriptPath)
print('downloading file to: ' + downloadPath)
downloadFile(url, downloadPath + fileName)
print('file downloaded...')
print('exiting program...')

Pawel, cevabın için teşekkürler. Bu soruyu ilk gönderdiğimde Python'da acemiydim. Şimdi dili çok iyi biliyorum. Bir dosyayı komut satırından indirmek için Python komut dosyası yazma durumunuz, wget veya curl gibi yardımcı programlar tarafından ele alınabilir. Ayrıca, yüklenen dosya indirme işleviniz kendisini çağırıyor gibi görünüyor. İkinci kod bloğunun girintisini artırmayı mı düşündünüz? Stackoverflow'da, bunu aşarak bunu düzeltebilirsiniz. Ayrıca Python'un argparse kütüphanesine bir göz atmanızı tavsiye ederim. Güzel komut satırı yardımcı programları yapmak için kullanabilirsiniz. Sizin için parametreleri halleder.
Jim

Dosya yazımını işlemek için bir bağlam yöneticisi (açık ... dosya olarak :, vb) kullanmanızı seviyorum. Kodunuz düzgün bir şekilde yazılmıştır. Python öğrenmek için iyi bir yoldasın. İyi şanslar!
Jim

1
Cevabınız için teşekkürler, @ Jim! Gönderiyi düzenledim ve gerçekten de programın ana parçası olan "girintileme" niyetinde değildim. Tavsiyelerin için teşekkürler! :)
Duck Ling

-4

Kevin'in bir klasöre yazması ile ilgili olarak tmp, şöyle olmalı:

with open('./tmp/metadata.pdf', 'wb') as f:
    f.write(response.content)

.adresten önce unuttu ve elbette klasörünüz tmpzaten oluşturulmuş olmalıydı


5
1- Kevin yazma fikrini ortaya atmadı tmp, OP'nin sorusundaki gibiydi. 2- /tmpdizin, Unix sistemlerindeki tmp'dir /tmp, no.
realUser404
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.