Завантажте та збережіть PDF-файл за допомогою модуля запитів Python


87

Я намагаюся завантажити файл PDF з веб-сайту та зберегти його на диск. Мої спроби або не вдаються з помилками кодування, або призводять до порожніх PDF-файлів.

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)
   ...: 

Я знаю, що це якась проблема кодека, але, здається, я не можу змусити її працювати.

Відповіді:


173

У response.contentцьому випадку слід використовувати :

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

З документа :

Ви також можете отримати доступ до тіла відповіді як байти для нетекстових запитів:

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

Отже, це означає: response.textповерніть результат як рядовий об’єкт, використовуйте його під час завантаження текстового файлу . Такі як HTML-файл тощо.

І response.contentповерніть результат як байт-об'єкт, використовуйте його під час завантаження двійкового файлу . Такі як PDF-файл, аудіо-файл, зображення тощо.


Ви також можете використовувати response.rawзамість цього . Однак використовуйте його, коли файл, який ви збираєтеся завантажити, великий. Нижче наведено базовий приклад, який ви також можете знайти в документі:

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_size- це розмір фрагмента, який ви хочете використовувати. Якщо ви встановите його як 2000, тоді запити завантажать цей файл першими 2000байтами, запишуть їх у файл і роблять це знову, знову і знову, поки це не закінчиться.

Отже, це може заощадити вашу оперативну пам’ять. Але я б віддав перевагу використанню response.contentв цьому випадку, оскільки ваш файл невеликий. Як бачите, використання response.rawє складним.


Відносини:


Класно, дякую за додаткову інформацію про response.raw.
Джим,

22

У Python 3 я вважаю, що pathlib - це найпростіший спосіб зробити це. Запит в response.content одружується красиво з write_bytes pathlib в.

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
Дякуємо, що розмістили це. Початкове питання було Python 2.7, але я продовжив і зараз використовую Python 3. Я не знав про бібліотеку pathlib [нова версія 3.4] і включу її у свої поточні проекти.
Джим,

Це дає 544і файл зламаний, є якісь ідеї?
ахбон

@ahbon, що ти маєш на увазі?
user6481870

13

Ви можете використовувати urllib:

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

Це найкращий, tbh.
Dhaval Savalia

Цей найкращий
roktim

urlretrieveпокладається на глобальні налаштування для визначення заголовків запитів, що робить його непридатним для деяких випадків використання.
Майкл Креншоу

5

Як правило, це повинно працювати в Python3:

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

Пам'ятайте, що urllib та urllib2 не працюють належним чином після Python2.

Якщо в деяких загадкових випадках запити не працюють (це сталося зі мною), ви також можете спробувати використовувати

wget.download(url)

Пов’язані:

Ось гідне пояснення / рішення для пошуку та завантаження всіх файлів PDF на веб-сторінці:

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


2

Зверніть увагу, я новачок. Якщо Моє рішення неправильне, будь ласка, виправте та / або дайте мені знати. Можливо, я теж дізнаюся щось нове.

Моє рішення:

Змініть шлях завантаження відповідно до місця, де потрібно зберегти файл. Не соромтеся використовувати і абсолютний шлях для свого використання.

Збережіть нижче як downloadFile.py.

Використання: python downloadFile.py url-of-the-file-to-download new-file-name.extension

Не забудьте додати розширення!

Приклад використання: 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...')

Павел, дякую за вашу відповідь. Я був початківцем Python, коли вперше розмістив це запитання. Зараз я дуже добре знаю мову. Ваш випадок використання сценарію Python для завантаження файлу з командного рядка може охоплюватися утилітами, такими як wget або curl. Крім того, ваша функція downloadFile, як опублікована, здається, називається сама. Ви мали намір зробити відступ для другого блоку коду? У stackoverflow ви можете це виправити, видаливши це. Я також хотів би запропонувати вам поглянути на бібліотеку argparse Python. Ви можете використовувати його для створення приємних утиліт командного рядка. Він подбає про параметри для вас.
Джим,

Мені подобається ваше використання контекстного менеджера (з відкритим ... як файл :, тощо) для обробки записів файлів. Ваш код акуратно написаний. Ви на хорошому шляху до вивчення Python. Удачі!
Джим,

1
Дякую за відповідь, @Jim! Я відредагував допис, і справді не "мав наміру робити відступи": D основну частину програми. Дякуємо за ваші поради! :)
Duck Ling

-5

щодо відповіді Кевіна писати в папці tmp, вона повинна бути такою:

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

він забув .до адреси і, звичайно, вашу папку вже tmpслід було створити


5
1- Кевін не придумав писати tmp, це було як у запитанні О.П. 2- /tmpкаталог - це tmp в системах Unix, розташований за адресою /tmp, немає.
realUser404
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.