Python爬虫保存图片和视频到本地主要涉及网络请求、内容解析和文件操作等步骤。下面将分别介绍这两种媒体资源的保存方法。

图片保存方法
保存图片通常需要先获取网页内容,然后提取图片链接,最后下载并保存到本地文件夹。

使用requests库获取图片内容是最常见的方式,通过二进制写入模式将图片数据保存到本地。首先需要创建保存目录,然后循环下载所有匹配到的图片链接。对于使用懒加载技术的网站,需要注意图片可能存储在data-src属性而非src属性中。

另一种方法是使用urllib库的urlretrieve()函数,它可以直接从网络下载资源到本地,代码更加简洁。

视频保存方法
视频保存与图片类似,但由于视频文件通常较大,需要使用流式下载来避免内存溢出。

通过设置stream=True参数


import os
import requests
from bs4 import BeautifulSoup
import re

class MediaDownloader:
    def __init__(self, save_dir="./downloads"):
        self.save_dir = save_dir
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
        }
        # 创建保存目录
        os.makedirs(save_dir, exist_ok=True)
    
    def download_image(self, img_url, filename=None):
        """下载单张图片并保存到本地"""
        try:
            if not filename:
                filename = img_url.split("/")[-1]
            
            response = requests.get(img_url, headers=self.headers)
            if response.status_code == 200:
                filepath = os.path.join(self.save_dir, "images", filename)
                os.makedirs(os.path.dirname(filepath), exist_ok=True)
                
                with open(filepath, 'wb') as f:
                    f.write(response.content)
                print(f"图片下载成功: {filename}")
                return True
            else:
                print(f"图片下载失败: {img_url}")
                return False
        except Exception as e:
            print(f"下载图片时出错: {str(e)}")
            return False
    
    def download_video(self, video_url, filename=None):
        """下载视频文件(支持大文件和断点续传)"""
        try:
            if not filename:
                filename = video_url.split("/")[-1] or "video.mp4"
            
            filepath = os.path.join(self.save_dir, "videos", filename)
            os.makedirs(os.path.dirname(filepath), exist_ok=True)
            
            # 断点续传处理
            if os.path.exists(filepath):
                file_size = os.path.getsize(filepath)
                self.headers['Range'] = f'bytes={file_size}-'
            
            response = requests.get(video_url, headers=self.headers, stream=True)
            
            if response.status_code in [200, 206]:  # 200正常,206部分内容
                mode = 'ab' if os.path.exists(filepath) else 'wb'
                
                with open(filepath, mode) as f:
                    for chunk in response.iter_content(chunk_size=1024):
                        if chunk:
                            f.write(chunk)
                print(f"视频下载成功: {filename}")
                return True
            else:
                print(f"视频下载失败,状态码: {response.status_code}")
                return False
        except Exception as e:
            print(f"下载视频时出错: {str(e)}")
            return False
    
    def extract_media_urls(self, url):
        """从网页中提取图片和视频URL"""
        try:
            response = requests.get(url, headers=self.headers)
            response.encoding = 'utf-8'
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # 提取图片URL
            image_urls = []
            img_tags = soup.find_all('img')
            for img in img_tags:
                # 优先使用data-src(懒加载),其次使用src
                img_url = img.get('data-src') or img.get('src')
                if img_url and img_url.startswith(('http', '//')):
                    if img_url.startswith('//'):
                        img_url = 'https:' + img_url
                    image_urls.append(img_url)
            
            # 提取视频URL
            video_urls = []
            video_tags = soup.find_all('video')
            for video in video_tags:
                video_url = video.get('src')
                if video_url and video_url.startswith(('http', '//')):
                    if video_url.startswith('//'):
                        video_url = 'https:' + video_url
                    video_urls.append(video_url)
            
            # 查找其他可能的视频标签
            source_tags = soup.find_all('source')
            for source in source_tags:
                video_url = source.get('src')
                if video_url and video_url.startswith(('http', '//')):
                    if video_url.startswith('//'):
                        video_url = 'https:' + video_url
                    video_urls.append(video_url)
            
            return image_urls, video_urls
            
        except Exception as e:
            print(f"提取媒体URL时出错: {str(e)}")
            return [], []
    
    def scrape_and_download(self, url):
        """主函数:爬取网页并下载所有媒体资源"""
        print(f"开始爬取: {url}")
        
        image_urls, video_urls = self.extract_media_urls(url)
        
        print(f"找到 {len(image_urls)} 张图片")
        print(f"找到 {len(video_urls)} 个视频")
        
        # 下载所有图片
        for i, img_url in enumerate(image_urls):
            print(f"下载图片 {i+1}/{len(image_urls)}")
            self.download_image(img_url, f"image_{i+1}.jpg")
        
        # 下载所有视频
        for i, video_url in enumerate(video_urls):
            print(f"下载视频 {i+1}/{len(video_urls)}")
            self.download_video(video_url, f"video_{i+1}.mp4")
        
        print("所有媒体资源下载完成!")

def main():
    # 使用示例
    downloader = MediaDownloader("./my_downloads")
    
    # 替换为你要爬取的实际URL
    target_url = "https://example.com"  # 请替换为实际URL
    
    # 开始爬取和下载
    downloader.scrape_and_download(target_url)

if __name__ == "__main__":
    main()

代码功能说明
1.‌媒体URL提取‌:使用BeautifulSoup解析网页HTML,从img和video标签中提取图片和视频链接,特别处理了懒加载图片的data-src属性。
2.‌图片下载‌:通过requests库获取图片二进制数据,并以wb模式写入本地文件。
3.‌视频下载‌:采用流式下载方式,通过iter_content方法分块处理大文件,避免内存不足。
4.‌断点续传‌:通过检查已下载文件大小和设置Range请求头,实现下载中断后的继续下载功能。
5.‌文件组织‌:自动创建分类文件夹(images和videos)来保存不同类型的媒体文件。

使用注意事项
在实际使用时,请将示例URL替换为实际要爬取的网站地址。
遵守网站的robots.txt规则,避免对服务器造成过大压力。
对于需要JavaScript渲染的网页,可能需要使用Selenium等工具。
注意版权问题,仅下载允许下载的公开资源。
该实现结合了多个搜索结果中的最佳实践,提供了完整的媒体资源下载解决方案。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐