查看网页结构
找到了一个公网的网盘,他有存我原来关注过的微博博主的相片。我想把这些图片全部下载下来。
首先来看一下图片的路径放在哪里了。右键检查,看到了这是个有序列表元素。里面<a>标签就是图片的链接了,点一下列表就会跳转到图片。这个列表显示的<img>是图片的缩略图。
实际查看了网页的Html结构,发现实际列表元素并不是ul无序列表或者li有序列表。而是td表格。
图片链接在a标签里,而a标签是td标签里。我们先找出全部的td标签,然后再从中找出a标签。然后打印出a标签的href属性,获得图片链接。
脚本
图片链接是相对目录,加上网站域名前缀就可以拼接成完整路径了。我们现在开始写脚本,
首先写一个脚本将获取的图片链接写入文本文件。然后再写一个通用的下载脚本,读取文本的文件链接,批量下载到本地。
先安装一下所需的模块,我们要requests库发送HTTP请求并获取响应。用Beautiful Soup 库处理网页的 HTML 内容。
pip install requests beautifulsoup4
爬取数据
import requests
from bs4 import BeautifulSoup
url = 'https://down.kele.im/weibo/%E4%B8%80%E5%B0%BE%E9%98%BF%E6%A2%93Azusa/img/%E5%8E%9F%E5%88%9B%E5%BE%AE%E5%8D%9A%E5%9B%BE%E7%89%87/'
response = requests.get(url)
# 使用 BeautifulSoup 解析网页内容
soup = BeautifulSoup(response.text, 'html.parser')
# 查找所有 class 为 'fb-n' 的 标签
td_tags = soup.find_all('td', class_='fb-n')
# 拼接的前缀
prefix = "https://down.kele.im"
# 遍历 <td> 标签,提取其中的 <a> 链接
links = []
for td in td_tags:
# 查找 <td> 标签下的 <a> 标签
a_tags = td.find_all('a')
for a in a_tags:
href = a.get('href')
if href: # 确保 href 不为空
full_link = f"{prefix}{href}" # 拼接前缀
links.append(full_link)
for link in links:
print(link)
# 将链接写入文件
output_file = "img.txt"
with open(output_file, 'w', newline='', encoding='utf-8') as file:
for link in links:
file.write(link + '\n')
print(f"已提取并保存链接到文件:{output_file}")
下载文件
import os
import requests
# 定义存放图片的文件夹
save_folder = "C:/Users/haowa/Desktop/阿圆"
# 确保文件夹存在
if not os.path.exists(save_folder):
os.makedirs(save_folder)
# 输入文件名
input_file = "C:/Users/haowa/Desktop/img.txt"
# 读取文件中的链接并下载图片
with open(input_file, 'r', encoding='utf-8') as f:
links = f.readlines()
for link in links:
link = link.strip() # 去除换行符和多余空格
if not link:
continue # 跳过空行
try:
# 获取图片内容
response = requests.get(link, stream=True)
response.raise_for_status() # 检查请求是否成功
# 提取图片文件名
file_name = os.path.basename(link)
save_path = os.path.join(save_folder, file_name)
# 保存图片到本地
with open(save_path, 'wb') as img_file:
for chunk in response.iter_content(chunk_size=8192):
img_file.write(chunk)
print(f"已下载图片: {save_path}")
except Exception as e:
print(f"下载失败: {link}, 错误: {e}")
print(f"图片下载完成,保存在文件夹: {save_folder}")
多线程下载
上面的是一个单线程的脚本。我们需要下载1719张图片。一个一个发请求,一个图片1.5秒。要下40分钟。我们是等不及的。
我们需要多线程并发,同时下载多个文件。使用 ThreadPool
库,适合轻量级并发任务。这个模块是python3自带的,不用安装。
功能有多线程下载,控制台实时反馈,下载失败重试和日志输出。
下载失败会重试三次,成功和失败的日志分别写入两个文件中,不用担心哪个文件下漏了。
from multiprocessing.pool import ThreadPool
import os
import requests
import time
# 设置保存路径
save_folder = r"C:/Users/haowa/Desktop/阿圆"
if not os.path.exists(save_folder):
os.makedirs(save_folder)
# 输入文件路径
input_file = r"C:/Users/haowa/Desktop/img.txt"
# 日志文件路径
success_log_file = os.path.join(save_folder, "success_log.txt")
failure_log_file = os.path.join(save_folder, "failure_log.txt")
# 下载函数,带重试机制
def download_image_with_retry(link, retries=3):
link = link.strip()
if not link:
return f"无效链接: {link}"
for attempt in range(retries):
try:
response = requests.get(link, stream=True, timeout=10)
response.raise_for_status()
# 获取文件名并保存
file_name = os.path.basename(link)
save_path = os.path.join(save_folder, file_name)
with open(save_path, 'wb') as img_file:
for chunk in response.iter_content(chunk_size=8192):
img_file.write(chunk)
result = f"成功下载: {link} -> {save_path}"
print(result) # 实时输出成功消息到控制台
return result
except Exception as e:
print(f"尝试 {attempt + 1}/{retries} 失败: {link}, 错误: {e}")
time.sleep(1) # 每次重试间隔 1 秒
result = f"下载失败: {link}"
print(result) # 实时输出失败消息到控制台
return result
# 多线程下载函数
def download_images_concurrently(links, max_workers=10):
with ThreadPool(max_workers) as pool:
results = pool.map(download_image_with_retry, links) # 并行执行任务
# 写入日志文件
with open(success_log_file, 'w', encoding='utf-8') as success_log, open(failure_log_file, 'w', encoding='utf-8') as failure_log:
for result in results:
if "成功下载" in result:
success_log.write(result + '\n')
else:
failure_log.write(result + '\n')
# 读取文件中的链接
with open(input_file, 'r', encoding='utf-8') as f:
links = f.readlines()
# 设置并发线程数
max_threads = 20
print("开始下载图片...")
download_images_concurrently(links, max_workers=max_threads)
print(f"图片下载完成,保存在文件夹: {save_folder}")
print(f"成功日志: {success_log_file}")
print(f"失败日志: {failure_log_file}")
成果展示
非常方便,不到五分钟就下完了,文件下载无误。确实是1719张图,我删掉了几张。感谢老哥的网盘存档,我以前存的图跟硬盘一起走了。跑了老哥一点流量,感谢。
文章评论