Завантажте та збережіть 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.