Hướng dẫn get filename from requests python - lấy tên tệp từ python yêu cầu

Theo tài liệu, cả Content-Disposition và thuộc tính filename của nó đều không cần thiết. Ngoài ra, tôi đã kiểm tra hàng chục liên kết trên internet và không tìm thấy phản hồi với tiêu đề Content-Disposition. Vì vậy, trong hầu hết các trường hợp, tôi sẽ không dựa vào nó nhiều và chỉ lấy thông tin này từ URL yêu cầu [lưu ý: Tôi đang lấy nó từ

import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
1 vì có thể chuyển hướng và chúng tôi muốn lấy tên tệp thực]. Tôi đã sử dụng
import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
2 bởi vì nó trông mạnh mẽ hơn và xử lý các tên tệp được trích dẫn và chưa được trích dẫn. Cuối cùng, tôi đã đưa ra giải pháp này [hoạt động từ Python 3.8]:

from urllib.parse import urlparse

import requests
import werkzeug


def get_filename[url: str]:
    try:
        with requests.get[url] as req:
            if content_disposition := req.headers.get["Content-Disposition"]:
                param, options = werkzeug.http.parse_options_header[content_disposition]
                if param == 'attachment' and [filename := options.get['filename']]:
                    return filename

            path = urlparse[req.url].path
            name = path[path.rfind['/'] + 1:]
            return name
    except requests.exceptions.RequestException as e:
        raise e

Tôi đã viết một số bài kiểm tra bằng cách sử dụng

import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
3 và
import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
4:

import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]

Bài đăng này là về cách tải xuống các tệp hiệu quả/chính xác từ các URL bằng Python. Tôi sẽ sử dụng các yêu cầu thư viện của Chúa cho nó. Tôi sẽ viết về các phương thức để tải xuống chính xác các nhị phân từ các URL và đặt tên tệp của chúng.
I will be using the god-send library requests for it. I will write about methods to correctly download binaries from URLs and set their filenames.

Hãy bắt đầu với các bước của em bé về cách tải xuống tệp bằng các yêu cầu -

import requests

url = '//google.com/favicon.ico'
r = requests.get[url, allow_redirects=True]
open['google.ico', 'wb'].write[r.content]

Mã trên sẽ tải xuống phương tiện truyền thông tại //google.com/favicon.ico và lưu nó dưới dạng google.ico.

Bây giờ chúng ta hãy lấy một ví dụ khác trong đó URL là //www.youtube.com/watch?v=9BZKP7Q19F0. Bạn nghĩ điều gì sẽ xảy ra nếu mã trên được sử dụng để tải xuống? Nếu bạn nói rằng một trang HTML sẽ được tải xuống, bạn sẽ xuất hiện. Đây là một trong những vấn đề tôi gặp phải trong mô -đun nhập của sự kiện mở trong đó tôi phải tải xuống phương tiện từ các liên kết nhất định. Khi URL được liên kết với trang web thay vì nhị phân, tôi phải không tải xuống tệp đó và chỉ giữ liên kết như vậy. Để giải quyết điều này, những gì tôi đã làm là kiểm tra các tiêu đề của URL. Các tiêu đề thường chứa tham số

import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
5 cho chúng ta biết về loại dữ liệu mà URL đang liên kết. Một cách ngây thơ để làm điều đó sẽ là -
What do you think will happen if the above code is used to download it ?
If you said that a HTML page will be downloaded, you are spot on. This was one of the problems I faced in the Import module of Open Event where I had to download media from certain links. When the URL linked to a webpage rather than a binary, I had to not download that file and just keep the link as is.
To solve this, what I did was inspecting the headers of the URL. Headers usually contain a
import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
5 parameter which tells us about the type of data the url is linking to.
A naive way to do it will be -

r = requests.get[url, allow_redirects=True]
print r.headers.get['content-type']

Nó hoạt động nhưng không phải là cách tối ưu để làm như vậy vì nó liên quan đến việc tải xuống tệp để kiểm tra tiêu đề. Vì vậy, nếu tập tin lớn, điều này sẽ không làm gì khác ngoài băng thông thải. Tôi đã xem xét tài liệu yêu cầu và tìm ra một cách tốt hơn để làm điều đó. Theo cách đó, chỉ cần tìm nạp các tiêu đề của một URL trước khi thực sự tải xuống nó. Điều này cho phép chúng tôi bỏ qua việc tải xuống các tệp không có nghĩa là được tải xuống.
So if the file is large, this will do nothing but waste bandwidth.
I looked into the requests documentation and found a better way to do it. That way involved just fetching the headers of a url before actually downloading it.
This allows us to skip downloading files which weren't meant to be downloaded.

import requests

def is_downloadable[url]:
    """
    Does the url contain a downloadable resource
    """
    h = requests.head[url, allow_redirects=True]
    header = h.headers
    content_type = header.get['content-type']
    if 'text' in content_type.lower[]:
        return False
    if 'html' in content_type.lower[]:
        return False
    return True

print is_downloadable['//www.youtube.com/watch?v=9bZkp7q19f0']
# >> False
print is_downloadable['//google.com/favicon.ico']
# >> True

Để hạn chế tải xuống theo kích thước tệp, chúng tôi có thể lấy tệp từ tiêu đề

import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
6 và sau đó so sánh phù hợp.

content_length = header.get['content-length', None]
if content_length and content_length > 2e8:  # 200 mb approx
  return False

Vì vậy, sử dụng chức năng trên, chúng tôi có thể bỏ qua các URL tải xuống không liên kết với phương tiện.

Nhận tên tệp từ URL

Chúng ta có thể phân tích URL để lấy tên tệp. Ví dụ - //aviaryan.in/images/profile.png.
Example - //aviaryan.in/images/profile.png.

Để trích xuất tên tệp từ URL trên, chúng tôi có thể viết một thói quen tìm nạp chuỗi cuối cùng sau khi chao đảo [/].

url = '//aviaryan.in/images/profile.png'
if url.find['/']:
  print url.rsplit['/', 1][1]

Điều này sẽ được cung cấp cho tên tệp trong một số trường hợp một cách chính xác. Tuy nhiên, có những lúc thông tin tên tệp không có trong URL. Ví dụ, một cái gì đó như

import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
7. Trong trường hợp đó, tiêu đề Content-Disposition sẽ chứa thông tin tên tệp. Đây là làm thế nào để lấy nó.
Example, something like
import pytest
import requests
import requests_mock

from main import get_filename

TEST_URL = '//pwrk.us/report.pdf'


@pytest.mark.parametrize[
    'headers,expected_filename',
    [
        [
                {'Content-Disposition': 'attachment; filename="filename.pdf"'},
                "filename.pdf"
        ],
        [
                # The string following filename should always be put into quotes;
                # but, for compatibility reasons, many browsers try to parse unquoted names that contain spaces.
                # //developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
                {'Content-Disposition': 'attachment; filename=filename with spaces.pdf'},
                "filename with spaces.pdf"
        ],
        [
                {'Content-Disposition': 'attachment;'},
                "report.pdf"
        ],
        [
                {'Content-Disposition': 'inline;'},
                "report.pdf"
        ],
        [
                {},
                "report.pdf"
        ]
    ]
]
def test_get_filename[headers, expected_filename]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, text='resp', headers=headers]
        assert get_filename[TEST_URL] == expected_filename


def test_get_filename_exception[]:
    with requests_mock.Mocker[] as m:
        m.get[TEST_URL, exc=requests.exceptions.RequestException]
        with pytest.raises[requests.exceptions.RequestException]:
            get_filename[TEST_URL]
7. In that case, the Content-Disposition header will contain the filename information.
Here is how to fetch it.

import requests
import re

def get_filename_from_cd[cd]:
    """
    Get filename from content-disposition
    """
    if not cd:
        return None
    fname = re.findall['filename=[.+]', cd]
    if len[fname] == 0:
        return None
    return fname[0]


url = '//google.com/favicon.ico'
r = requests.get[url, allow_redirects=True]
filename = get_filename_from_cd[r.headers.get['content-disposition']]
open[filename, 'wb'].write[r.content]

Mã phân tích URL kết hợp với phương thức trên để lấy tên tệp từ tiêu đề Content-Disposition sẽ hoạt động cho hầu hết các trường hợp. Sử dụng chúng và kiểm tra kết quả.
Use them and test the results.

Đây là 2 xu của tôi khi tải xuống các tệp bằng cách sử dụng các yêu cầu trong Python. Hãy cho tôi biết về các thủ thuật khác mà tôi có thể đã bỏ qua.

Bài viết này lần đầu tiên được đăng trên blog cá nhân của tôi.

Thưởng thức bài viết này? Cung cấp cho Avi Aryan như nếu nó hữu ích.Avi Aryan a like if it's helpful.

Nhà phát triển web Stack Full Stack tại Toptal, GSOC 17 & Udacity Mentor

Tôi là một nhà phát triển tự do hiện đang làm việc tại Toptal và Udacity. Tôi chuyên môn trong phát triển web Stack đầy đủ. Tôi đã lập trình được 6 năm và tôi tin vào sự tỉnh táo của mã cũng như bất cứ điều gì. Tôi cũng làm P ...

Khám phá và đọc thêm bài viết từ Avi AryanAvi Aryan

Thưởng thức bài viết này?

Để lại một cái thích và bình luận cho AVIAvi

Làm cách nào để tải xuống một tệp với các yêu cầu?

Để tải xuống một tệp từ URL bằng Python, hãy làm theo ba bước sau:..
Cài đặt mô -đun yêu cầu và nhập nó vào dự án của bạn ..
Sử dụng yêu cầu. Nhận [] để tải xuống dữ liệu đằng sau url đó ..
Viết tệp vào tệp trong hệ thống của bạn bằng cách gọi Open [] ..

Yêu cầu có nhận được tệp tải xuống không?

Yêu cầu là một thư viện HTTP đa năng trong Python với các ứng dụng khác nhau.Một trong những ứng dụng của nó là tải xuống một tệp từ web bằng URL tệp.download a file from web using the file URL.

Làm cách nào để tải xuống nhiều tệp từ một trang web bằng Python?

Nhập mô -đun.Nhập yêu cầu ..
Nhận liên kết hoặc URL.url = '//www.facebook.com/favicon.ico' r = requests.get [url, allow_redirects = true].
Lưu nội dung với tên.Mở ['Facebook.ICO', 'WB']. Viết [R.Content] lưu tệp dưới dạng Facebook.....
Nhận tên tệp từ một url.Để có được tên tệp, chúng ta có thể phân tích URL ..

Làm thế nào để bạn tải xuống một tệp văn bản trong Python?

Một trong những cách đơn giản nhất để tải xuống các tệp trong Python là thông qua mô -đun WGET, điều này không yêu cầu bạn mở tệp đích.Phương thức tải xuống của mô -đun WGET tải xuống các tệp chỉ trong một dòng.Phương thức chấp nhận hai tham số: đường dẫn URL của tệp để tải xuống và đường dẫn cục bộ nơi lưu trữ tệp.via wget module, which doesn't require you to open the destination file. The download method of the wget module downloads files in just one line. The method accepts two parameters: the URL path of the file to download and local path where the file is to be stored.

Bài Viết Liên Quan

Chủ Đề