如何使用PHP和Python从网站下载文件

4
我有一个Python脚本,可以爬取多个网站并下载它们的文件。我的问题是,一些网站似乎在使用PHP,至少我推测是这样,因为URL看起来像这样:https://www.portablefreeware.com/download.php?dd=1159
问题在于,我无法从这样的链接中获取任何文件名或扩展名,因此无法保存该文件。目前,我只保存URL。
是否有任何方法可以得到链接背后实际的文件名?
以下是我简化的下载代码:
r = requests.get(url, allow_redirects=True)

file = open("name.something", 'wb')
file.write(r.content)
file.close()

免责声明:我从未使用过PHP进行任何工作,因此请原谅我可能有关于它的术语或理解上的错误。不过我很乐意学习更多。


你可以尝试检查头部信息,例如:r.headers - Dmitry Leiko
就像问题中所述,我不想保存HTML,我想要实际的文件。我不理解这句话的意思。"链接后面的实际文件"指的是什么?如果我访问像问题中的URL,为什么它应该对应于"a file"(一个文件)?为什么将页面的HTML内容保存到磁盘上不符合"文件"的条件? - Karl Knechtel
5个回答

3
为从 URL 中获取重定向后的文件名,请在响应中检查 Content Disposition 标头。以下是一段代码,用于从响应标头中提取文件名和扩展名。
import requests from urllib.parse import unquote
    
def get_filename_from_cd(cd):
    """
    Get filename from content disposition header
    """
    if not cd:
        return None
    fname = None
    for param in cd.split(';'):
        if 'filename' in param.lower():
            fname = param.split('=')[1].strip()
            break
    return unquote(fname)
    
url = 'https://www.portablefreeware.com/download.php?dd=1159'
r = requests.get(url,allow_redirects=True)
    
# Get the file name from the headers
filename = get_filename_from_cd(r.headers.get('content-disposition'))
    
if filename:
    with open(filename, 'wb') as file:
    file.write(r.content)
else:
    print("Couldn't find the file name in the response headers.")

如果那样不起作用。
import requests
import mimetypes

response = requests.get('https://www.portablefreeware.com/download.php?dd=1159')
content=response.content
content_type = response.headers['Content-Type']
ext= mimetypes.guess_extension(content_type)


print(content)# [ZipBinary]
print(ext)# .zip
print(content_type)#application/zip, application/octet-stream

with open("newFile."+ext, 'wb') as f:
  f.write(content)
  f.close()

1
使用allow_redirects=True选项时,requests.get会自动跟踪响应中Location头部的URL以进行另一个请求,结果会丢失第一个响应的头部信息,这就是为什么您无法在任何地方找到文件名信息的原因。
相反,您应该使用allow_redirects=False选项,以便您可以获取包含实际下载URL的Location头部信息:
import requests

url = 'https://www.portablefreeware.com/download.php?dd=1159'
r = requests.get(url, allow_redirects=False)
print(r.headers['Location'])

这将输出:
https://www.diskinternals.com/download/Linux_Reader.exe

示例:https://replit.com/@blhsing/TrivialLightheartedLists

然后,您可以向下载URL发送另一个请求,并使用os.path.basename获取将写入内容的文件名:

import os

url = r.headers['Location']
with open(os.path.basename(url), 'w') as file:
    r = requests.get(url)
    file.write(r.content)

0

您可以通过响应头获取文件名并下载文件。

以下是带有进度条和缓冲区块大小的下载代码:

  1. 使用tqdm显示进度条。 pip install tqdm
  2. 在此过程中,使用块写入来节省内存。
import os

import requests
import tqdm
url = "https://www.portablefreeware.com/download.php?dd=1159"
response_header = requests.head(url)
file_path = response_header.headers["Location"]
file_name = os.path.basename(file_path)
with open(file_name, "wb") as file:
    response = requests.get(url, stream=True)
    total_length = int(response.headers.get("content-length"))
    for chunk in tqdm.tqdm(response.iter_content(chunk_size=1024), total=total_length / 1024, unit="KB"):
        if chunk:
            file.write(chunk)
            file.flush()

进度输出:

6%|▌         | 2848/46100.1640625 [00:04<01:11, 606.90KB/s]

0

可通过分布式 DNS 网络在任何地方反弹可重定向。因此,上面的示例答案显示 https://www,但在我的情况下,它们将被解析为欧洲,因此我的最快本地来源是

https://eu.diskinternals.com/download/Linux_Reader.exe

到目前为止,最简单的方法是先使用原始curl,如果它很好,就不需要检查或抓取

不必费心去解决任何问题,
curl -o 1159.tmp https://www.portablefreeware.com/download.php?dd=1159

然而我知道在这种情况下,这不是预期的结果,所以下一步是

curl -I https://www.portablefreeware.com/download.php?dd=1159 |find "Location"

这给出了其他人显示的结果
https://www.diskinternals.com/download/Linux_Reader.exe 但这并不是完整的图片,因为如果我们反馈回去

curl.exe -K location.txt

我们得到

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://eu.diskinternals.com/download/Linux_Reader.exe">here</a>.</p>
</body></html>

因此嵌套的重定向至

https://eu.diskinternals.com/download/Linux_Reader.exe

所有这些都可以通过命令行脚本在一两行中循环运行,但我不使用Python,所以您需要编写大约十几行代码来实现类似的功能。

C:\Users\WDAGUtilityAccount\Desktop>curl -O https://eu.diskinternals.com/download/Linux_Reader.exe
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 44.9M  100 44.9M    0     0  3057k      0  0:00:15  0:00:15 --:--:-- 3640k

C:\Users\WDAGUtilityAccount\Desktop>dir /b lin*.*
Linux_Reader.exe

来自昨天额外更新的帮助文件(2022年9月4日,星期日)链接

curl -O https://eu.diskinternals.com/download/Uneraser_Setup.exe


0
你正在使用 "requests" 进行下载。这在此类下载中不起作用。
尝试使用 "urllib" 替代:
import urllib.request

urllib.request.urlretrieve(url, filepath)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接