清科谷体的博客

  • 文章
  • 关于
  • 联系
  • 隐私政策

  1. 首页
  2. 教程
  3. 正文

用 Python 爬虫批量下载图片(一)解析网页并获取数据

2025年1月18日 152点热度 0人点赞 0条评论

查看网页结构

找到了一个公网的网盘,他有存我原来关注过的微博博主的相片。我想把这些图片全部下载下来。

首先来看一下图片的路径放在哪里了。右键检查,看到了这是个有序列表元素。里面<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张图,我删掉了几张。感谢老哥的网盘存档,我以前存的图跟硬盘一起走了。跑了老哥一点流量,感谢。

 

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: Python 多线程 爬虫 脚本 自动化
最后更新:2025年4月28日

ingker

自娱自乐

点赞
< 上一篇
下一篇 >

文章评论

取消回复

COPYRIGHT © 2025 清科谷体's blog. ALL RIGHTS RESERVED.
THEME KRATOS MADE BY VTROIS | MODIFIED BY INGKER

正在加载今日诗词....

本站已运行