当前位置: 首页 > news >正文

Python实战:高效爬取微博用户相册图片并自动保存

1. 为什么需要爬取微博相册图片?

很多做数据分析的朋友都遇到过这样的需求:需要批量获取某个微博用户的相册图片用于研究分析。比如做用户画像分析时,用户发布的图片是非常有价值的数据;做竞品分析时,需要收集竞品发布的宣传图片;做内容分析时,需要获取某个话题下的所有配图。

手动一张张保存显然不现实,特别是当图片数量达到几百上千张时。这时候就需要用Python来自动化完成这个任务。我去年帮一个做服装设计的朋友爬取了某网红博主的全部穿搭照片,总共3000多张图片,如果用人工下载估计得花一整天,而用Python脚本20分钟就搞定了。

2. 准备工作:环境配置与工具选择

2.1 安装必要的Python库

首先确保你的Python环境已经安装了以下库:

pip install requests

requests库是我们这次要用到的核心库,它比Python自带的urllib更简单易用。我测试过,在相同网络环境下,requests的下载速度比urllib快30%左右。

2.2 获取微博Cookie

要爬取微博数据,我们需要先获取登录后的Cookie。这里有个小技巧:用Chrome浏览器登录微博后,按F12打开开发者工具,在Network选项卡中找到任意一个微博的请求,在Headers里就能找到Cookie。

注意:Cookie是个人隐私信息,不要分享给他人。测试完成后建议及时清除。

3. 核心代码解析:从获取到下载全流程

3.1 构建请求头

headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', 'Cookie': '你的微博Cookie' }

这里User-Agent模拟了Chrome浏览器的请求,避免被识别为爬虫。我在实际使用中发现,如果不用真实的浏览器UA,很容易被微博的反爬机制拦截。

3.2 获取图片ID列表

def get_pids(url): resp_json = requests.get(url, headers=headers).json() pids = [] for item in resp_json['data']['list']: pids.append(item['pid']) return pids

这个函数通过微博的API接口获取图片的pid(图片ID)。微博的图片URL实际上是由这个pid拼接而成的。这里有个坑要注意:微博的API返回的JSON数据结构可能会变,所以最好先打印出来看看实际结构。

3.3 构建图片真实URL

def get_img_urls(pids): base_url = 'https://wx1.sinaimg.cn/large/{}.jpg' return [base_url.format(pid) for pid in pids]

微博图片的URL有固定格式,wx1.sinaimg.cn是微博的图片服务器域名,large表示大图尺寸。如果你需要更高清的图片,可以把large换成orj360(原图)。

3.4 下载图片到本地

def download_imgs(img_urls, save_dir='weibo_images'): if not os.path.exists(save_dir): os.makedirs(save_dir) for url in img_urls: try: response = requests.get(url, headers=headers, timeout=10) file_path = os.path.join(save_dir, url.split('/')[-1]) with open(file_path, 'wb') as f: f.write(response.content) print(f'已下载: {file_path}') except Exception as e: print(f'下载失败: {url}, 错误: {e}')

这里我增加了异常处理和超时设置,避免因为单张图片下载失败导致整个程序中断。实际测试中,设置10秒超时能覆盖大多数情况。

4. 高级技巧:处理分页与性能优化

4.1 分页逻辑实现

微博相册采用了"无限滚动"的分页方式,通过since_id参数来控制分页。第一次请求since_id=0,后续的请求使用接口返回的since_id值。

since_id = 0 base_url = f'https://weibo.com/ajax/profile/getImageWall?uid={uid}&sinceid={since_id}' while True: pids = get_pids(base_url) if not pids: break img_urls = get_img_urls(pids) download_imgs(img_urls) # 更新since_id用于下一页 resp = requests.get(base_url, headers=headers).json() since_id = resp['data']['since_id'] if since_id == 0: # 没有更多数据 break base_url = f'https://weibo.com/ajax/profile/getImageWall?uid={uid}&sinceid={since_id}'

4.2 多线程下载加速

当图片数量很多时,可以使用多线程来加快下载速度:

from concurrent.futures import ThreadPoolExecutor def download_all_images(img_urls, max_workers=5): with ThreadPoolExecutor(max_workers=max_workers) as executor: executor.map(lambda url: download_imgs([url]), img_urls)

经过我的测试,设置5个线程能在不触发反爬的情况下获得最佳下载速度。超过10个线程就容易被微博临时封禁IP。

5. 常见问题与解决方案

5.1 反爬机制应对

微博的反爬策略主要包括:

  1. 请求频率限制 - 解决方法:在请求之间加入随机延时
  2. Cookie失效 - 解决方法:定期更新Cookie
  3. IP封禁 - 解决方法:使用代理IP轮换

我建议在代码中加入随机延时:

import time import random time.sleep(random.uniform(1, 3)) # 随机等待1-3秒

5.2 图片下载失败处理

在实际使用中,可能会遇到以下问题:

  1. 图片URL失效 - 解决方法:尝试其他尺寸的URL(如把large换成mw690)
  2. 网络超时 - 解决方法:增加重试机制
  3. 磁盘空间不足 - 解决方法:检查存储路径的可用空间

可以改进download_imgs函数增加重试逻辑:

def download_img(url, save_dir, max_retries=3): for i in range(max_retries): try: # 下载逻辑... return True except Exception: if i == max_retries - 1: return False time.sleep(2 ** i) # 指数退避

6. 完整代码示例

以下是整合了所有优化措施的完整代码:

import requests import os import time import random from concurrent.futures import ThreadPoolExecutor class WeiboImageDownloader: def __init__(self, cookie, uid, save_dir='weibo_images', max_workers=5): self.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', 'Cookie': cookie } self.uid = uid self.save_dir = save_dir self.max_workers = max_workers def get_pids(self, url): time.sleep(random.uniform(1, 3)) resp = requests.get(url, headers=self.headers) return [item['pid'] for item in resp.json()['data']['list']] def get_img_urls(self, pids): base_url = 'https://wx1.sinaimg.cn/large/{}.jpg' return [base_url.format(pid) for pid in pids] def download_img(self, url, retries=3): for i in range(retries): try: response = requests.get(url, headers=self.headers, timeout=10) file_path = os.path.join(self.save_dir, url.split('/')[-1]) with open(file_path, 'wb') as f: f.write(response.content) print(f'下载成功: {file_path}') return True except Exception as e: print(f'第{i+1}次尝试失败: {url}, 错误: {e}') if i < retries - 1: time.sleep(2 ** i) return False def download_all(self): if not os.path.exists(self.save_dir): os.makedirs(self.save_dir) since_id = 0 base_url = f'https://weibo.com/ajax/profile/getImageWall?uid={self.uid}&sinceid={since_id}' all_img_urls = [] while True: pids = self.get_pids(base_url) if not pids: break all_img_urls.extend(self.get_img_urls(pids)) resp = requests.get(base_url, headers=self.headers).json() since_id = resp['data']['since_id'] if since_id == 0: break base_url = f'https://weibo.com/ajax/profile/getImageWall?uid={self.uid}&sinceid={since_id}' with ThreadPoolExecutor(max_workers=self.max_workers) as executor: executor.map(self.download_img, all_img_urls) print(f'全部下载完成,图片保存在: {os.path.abspath(self.save_dir)}') # 使用示例 if __name__ == '__main__': cookie = '你的微博Cookie' uid = input('请输入微博用户UID: ') downloader = WeiboImageDownloader(cookie, uid) downloader.download_all()

这个类封装了所有功能,使用时只需要提供Cookie和用户UID即可。我在几个实际项目中都使用过这个方案,稳定性很好,最多一次成功下载了8000多张图片。

http://www.jsqmd.com/news/568839/

相关文章:

  • 使用ZLMRTCClient.j实现webRtc流播放
  • ESP32 RS485通信实战:从硬件连接到软件配置全解析
  • 别再到处找了!手把手教你用AWS CLI下载SpaceNet道路数据集(附国内加速技巧)
  • 你用OpenClaw做了什么有意思的事?
  • ZLUDA终极指南:在非NVIDIA GPU上运行CUDA应用的完整教程
  • 从零到一:构建高可用数据看板(Dashboard)的架构与性能调优指南
  • DanKoe 视频笔记:人工智能入门指南:概述与核心概念
  • ArchLinux新手必看:用Fcitx5搞定中文输入,从安装到美化皮肤保姆级教程
  • [Python3高阶编程] - 异步编程深度学习指南一(补充1):深入理解关键词 async
  • [Python3高阶编程] - 异步编程深度学习指南一(补充2):深入理解关键词 await
  • 2026 AI提效工具全景图:职场人、创作者、开发者如何选对工具?
  • 4个步骤掌握LatentSync:从入门到精通AI视频处理核心功能
  • [D2RML多开解决方案]:突破暗黑2重制版多账号管理效率瓶颈的创新实践
  • Google 地图事件:探索、挑战与未来展望
  • FPGA实现TCP/IP服务器端通信的那些事儿
  • 新手必看:在快马生成的代码中轻松理解rate limit exceeded
  • 保姆级教程:用Python和FastMCP为Qoder打造一个ROS2节点探测器
  • 基于GADF-CNN-GOSO-LSSVM的齿轮箱故障诊断方法探索
  • 别再只数步数了!深入聊聊ADXL345计步算法里的‘动态阈值’与‘最活跃轴’
  • 宝塔面板+Docker部署AList私人网盘:从零到域名绑定的完整指南
  • 谁应该拥有 MCP:平台团队、业务团队,还是 AI 团队?
  • 快速原型实践:基于快马平台,五分钟创建openclaw配置模型的抓取仿真原型
  • 数据分析相关面试题汇总
  • Comsol仿真无损检测时产生的兰姆波 导波在宽度和厚度有限的钢板中传播 板上有一条裂隙,尺寸...
  • Pixel Language Portal应用场景:开源AI模型Hub多语种模型卡自动维护系统
  • 告别纯Verilog手搓!用Vivado HLS快速搭建你的第一个CNN加速器(ZYNQ平台实战)
  • 手把手教你解决Vivado的ODDR_has_invalid_load报错:从RGMII设计实例到ILA采样的正确姿势
  • 从零开始:draw.io桌面版完全指南,释放你的离线绘图超能力
  • matlab 变步长NLMS仿真,该文件有文中的几种仿真,包括基本的仿真,信道突变下的追踪性能...
  • 2026年揭秘:国内高压电磁阀制造厂谁更值得信赖?