import os import requests from urllib.parse import urljoin from bs4 import BeautifulSoup import logging from pathlib import Path # 配置日志记录 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) def get_page_content(url): """获取网页内容""" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } try: response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() response.encoding = response.apparent_encoding return response.text except requests.exceptions.RequestException as e: logging.error(f"请求失败: {e}") return None def extract_file_links(html, base_url): """提取文件下载链接""" soup = BeautifulSoup(html, 'html.parser') file_links = [] # 查找所有包含文件扩展名的链接 for link in soup.find_all('a', href=True): href = link['href'] if any(href.lower().endswith(ext) for ext in ('.pdf', '.doc', '.docx', '.xls', '.xlsx', '.zip', '.rar')): absolute_url = urljoin(base_url, href) file_links.append((absolute_url, link.text.strip())) return file_links def download_file(url, save_dir): """下载单个文件""" try: response = requests.get(url, stream=True, timeout=15) response.raise_for_status() # 从URL获取文件名 filename = os.path.basename(url.split('?')[0]) # 去除URL参数 if not filename: filename = f"file_{hash(url)}" # 创建保存目录 Path(save_dir).mkdir(parents=True, exist_ok=True) # 保存文件 file_path = os.path.join(save_dir, filename) with open(file_path, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): if chunk: f.write(chunk) logging.info(f"成功下载: {filename}") return True except Exception as e: logging.error(f"下载失败 {url}: {str(e)}") return False def main(): target_url = "http://www.nhc.gov.cn/lljks/zcwj2/new_list.shtml" save_directory = "./downloaded_files" # 获取页面内容 html_content = get_page_content(target_url) if not html_content: return # 提取文件链接 file_links = extract_file_links(html_content, target_url) if not file_links: logging.warning("未找到可下载文件") return # 下载所有文件 success_count = 0 for url, name in file_links: if download_file(url, save_directory): success_count += 1 logging.info(f"下载完成,成功{success_count}/{len(file_links)}个文件") if __name__ == "__main__": main()
时间: 2025-06-11 21:58:10 浏览: 24
<think>嗯,用户给了一段Python代码,是关于用requests和BeautifulSoup来爬取网页上的文件并下载的。他们可能想了解这段代码的功能或者需要解释。首先,我需要仔细看一下代码的结构,然后分步骤解释每个部分的作用。
首先,代码里导入了几个库:os、requests、urllib.parse中的urljoin、BeautifulSoup、logging和pathlib的Path。这些库分别用于处理文件路径、HTTP请求、URL解析、HTML解析、日志记录和路径管理。用户可能对每个导入的库的作用不太清楚,需要逐一解释。
接下来,代码配置了logging,设置了日志的级别和格式。这个部分可能对于调试和记录运行情况很重要,用户可能需要知道为什么需要配置日志,以及各个参数的意义。
然后定义了get_page_content函数,用来获取网页内容。里面设置了User-Agent头,处理了请求异常,还调整了编码。这里可能需要解释User-Agent的作用,以及异常处理的重要性,比如网络问题或页面不存在的情况。
extract_file_links函数用来提取文件链接。这里用到了BeautifulSoup来解析HTML,查找所有a标签,并且筛选出带有特定文件扩展名的链接。可能需要解释urljoin的作用,以及如何确保获取的是绝对URL而不是相对路径。还有,代码中检查了扩展名如.pdf、.doc等,用户可能想知道如何修改这些扩展名或者添加其他类型。
download_file函数负责下载单个文件。这里使用流式下载来避免大文件占用过多内存,处理了文件名提取和保存路径的创建。可能需要说明stream=True的作用,以及如何处理文件名中的参数问题。还有,使用Path创建目录的优势在哪里。
main函数是整个程序的入口,设置了目标URL和保存目录,然后按顺序调用前面的函数:获取内容、提取链接、下载文件。最后统计成功下载的数量。用户可能想知道如何修改目标URL或保存路径,或者如何处理下载失败的情况。
用户可能的疑问点包括:代码的用途,各个函数的作用,如何自定义(比如修改下载的文件类型、保存路径),以及可能遇到的错误(如权限问题、网络问题)。此外,用户可能关心这段代码是否合法,是否符合目标网站的使用条款,是否有反爬措施需要注意。
另外,需要注意代码中是否有潜在的问题,比如没有处理可能的重复文件名,或者没有限制下载速度导致被封IP。还有,异常处理是否全面,比如在下载文件时的异常是否被正确捕获并记录。
最后,用户可能需要了解如何运行这段代码,需要安装哪些依赖库,比如requests和beautifulsoup4,以及可能的运行环境要求,比如Python版本。
总结来说,解释这段代码需要分模块讲解每个函数的作用,导入的库的用途,代码的逻辑流程,以及潜在的问题和改进点。同时,提醒用户注意合法性和网站的规定,避免滥用爬虫。</think>这个Python脚本是一个网页文件下载工具,主要用于从指定网页自动下载常见格式的文件。以下分模块解析其工作原理:
$\textcolor{blue}{一、模块导入部分}$
```python
import os
import requests # HTTP请求库
from urllib.parse import urljoin # URL拼接
from bs4 import BeautifulSoup # HTML解析
import logging # 日志记录
from pathlib import Path # 路径处理
```
- $\text{requests}$:发送HTTP请求的核心库
- $\text{BeautifulSoup}$:解析HTML文档结构
- $\text{urljoin}$:确保获取绝对URL,避免相对路径问题
$\textcolor{blue}{二、核心函数解析}$
1. $\text{get_page_content(url)}$
```python
headers = {'User-Agent': '...'} # 模拟浏览器访问
response = requests.get(url, headers=headers, timeout=10)
```
- 使用$\text{User-Agent}$头绕过基础反爬机制
- $\text{timeout=10}$设置10秒超时防止卡死
- $\text{apparent_encoding}$自动检测页面编码
2. $\text{extract_file_links(html, base_url)}$
```python
if any(href.lower().endswith(ext) for ext in
('.pdf', '.doc', '.docx', '.xls', '.xlsx', '.zip', '.rar')):
```
- 通过后缀名过滤文件链接
- 支持扩展类型:$$ \{ \text{pdf, doc, xls, zip, rar} \} $$
- 使用$\text{urljoin}$保证链接完整性
3. $\text{download_file(url, save_dir)}$
```python
response = requests.get(url, stream=True) # 流式下载
for chunk in response.iter_content(chunk_size=8192):
```
- $\text{stream=True}$实现大文件分块下载
- 文件命名策略:$$ \text{filename} = \text{basename}(\text{split}(url)[0]) $$
- 自动创建保存目录:$\text{Path(save_dir).mkdir()}$
$\textcolor{blue}{三、执行流程}$
$$
\begin{aligned}
1.&\ \text{main()} \rightarrow \text{get_page_content()} \\
2.&\ \downarrow \text{extract_file_links()} \\
3.&\ \downarrow \text{download_file()} \times N \\
4.&\ \text{输出下载统计}
\end{aligned}
$$
$\textcolor{blue}{四、改进建议}$
1. 增加随机延迟:避免高频请求被屏蔽
```python
import time
import random
time.sleep(random.uniform(0.5, 1.5))
```
2. 文件去重机制
```python
if os.path.exists(file_path):
logging.warning(f"文件已存在: {filename}")
return False
```
3. 扩展过滤规则:支持正则表达式匹配
```python
import re
pattern = r'\.(pdf|docx?|xlsx?|zip|rar)$'
if re.search(pattern, href, re.IGNORECASE):
```
$\textcolor{red}{注意事项:}$
- 遵守网站的$\text{robots.txt}$协议
- 确认目标网站允许自动化访问
- 控制请求频率(建议≥2秒/次)
- 商业用途需获得授权
该脚本适合批量下载公开资料,但需注意遵守相关法律法规和网站使用条款。建议在测试时先使用小规模数据验证功能有效性。
阅读全文
相关推荐











