Python爬虫实战:爬取某微博用户动态,手把手教你突破登录限制
引言
在社交媒体数据日益成为舆情分析、市场研究和用户画像重要素材的今天,如何高效获取平台数据是每一位数据从业者都无法回避的问题。某微博作为国内最活跃的社交媒体平台之一,拥有海量的用户动态、热点话题和互动数据,是数据分析的天然宝库。
然而,爬取某微博数据绝非易事。其反爬体系经过多年迭代,已经形成了一套多维度、动态评估的智能防护系统。很多开发者可能有过这样的经历:昨天还能正常运行的爬虫脚本,今天一运行就各种报错、弹出验证码,甚至IP直接被封。本文将从零开始,手把手教你如何突破某微博的登录限制,稳定爬取用户动态数据。
免责声明:本文仅限技术学习与交流,请勿将爬虫技术用于商业用途或对目标网站造成过大压力。请遵守目标网站的 robots.txt 协议及相关法律法规。
一、为什么爬取某微博用户动态如此困难?
在动手写代码之前,我们有必要先搞清楚一个问题:平台到底是如何识别出“这是一个爬虫”的?
某微博的反爬体系并非单一维度的简单封锁,而是综合了数百个特征指标,对每一次访问进行实时“画像”评估。一旦你的行为画像与真实用户的偏差过大,警报就会被触发。
1.1 浏览器指纹检测
当你通过自动化工具(如Selenium)启动浏览器时,尽管看起来和普通浏览器一样,但它会在多个细节上暴露自动化工具的痕迹。例如:
navigator.webdriver属性:普通浏览器中该属性为
undefined,而自动化工具控制的浏览器中会被设置为true,这相当于“自报家门”插件列表:真实用户浏览器通常装有各种扩展插件,而自动化环境下的浏览器往往“干干净净”,本身就很可疑
Canvas与WebGL指纹:通过让浏览器绘制特定图形生成的设备标识,自动化工具的渲染结果与真实浏览器存在细微差异
1.2 行为模式分析
系统会分析你的鼠标移动轨迹、点击位置、滚动速度、页面停留时间等行为特征。Selenium的execute_script(“window.scrollBy(0, 1000)”)会让页面瞬间跳转1000像素,而真实用户的滚动是有加速度和减速过程的。这些细微的差异都会被平台捕捉。
1.3 IP频率限制
某微博平台的防护机制主要基于IP地址进行访问控制。当系统检测到某个IP在短时间内发出大量请求时,会触发保护机制。非登录态下访问非关注用户的主页,甚至会直接返回403或空数据。
1.4 登录态校验
部分接口会校验Cookie中的关键字段(如SSRF或WEIBOBEARER),没有有效登录态的请求会被直接拒绝。热搜页面直接用requests发起GET请求,往往会返回403或空内容。
理解了这些反爬手段,我们就能有针对性地制定突破策略。
二、突破登录限制的三种主流方案
根据不同的应用场景和开发经验,我们可以选择以下三种方案中的一种或组合使用。
方案一:手动获取Cookie(最快速、最稳定)
这是目前最推荐给初学者的方式。你只需要在浏览器中手动登录某微博,然后复制Cookie供爬虫使用。
操作步骤如下:
用浏览器打开某微博官网并登录你的账号
按
F12打开开发者工具切换到“Network”(网络)标签
刷新页面(
Ctrl+R或Command+R)在请求列表中找到
weibo.com相关的请求在Headers中找到
Cookie字段,复制其值
代码实现:
import requests from fake_useragent import UserAgent # 将上一步复制的Cookie粘贴到这里 cookies = { "SUB": "你的SUB值", # 可以添加其他关键cookie } headers = { "User-Agent": UserAgent().random, "Referer": "https://weibo.com", } # 爬取用户动态 def get_user_posts(uid, page=1): url = f"https://weibo.com/ajax/statuses/mymblog?uid={uid}&page={page}" response = requests.get(url, headers=headers, cookies=cookies) if response.status_code == 200: return response.json() return None # 示例:爬取指定用户的动态 data = get_user_posts("用户UID", 1) if data: for post in data.get("data", {}).get("list", []): print(f"内容: {post.get('text_raw', '')[:50]}...") print(f"发布时间: {post.get('created_at', '')}") print(f"互动: 转发{post.get('reposts_count', 0)} 评论{post.get('comments_count', 0)} 赞{post.get('attitudes_count', 0)}") print("-" * 50)优点:实现简单、无需处理验证码、稳定性高。缺点:Cookie有过期时间(通常为数天到数周),需要定期手动更新。
方案二:使用Selenium模拟登录(全自动化)
如果你需要完全自动化的方案,可以使用Selenium模拟真实用户的登录行为。
核心思路:用Selenium驱动真实浏览器访问某微博登录页面,自动填写账号密码,处理可能出现的滑块验证码,登录成功后保存Cookie供后续使用。
代码实现:
from selenium import webdriver from selenium.webdriver.common.by import By import json import time def save_cookies(driver, filename='cookies.json'): """保存登录后的cookies到文件""" cookies_list = driver.get_cookies() with open(filename, 'w') as f: json.dump(cookies_list, f) def load_cookies(driver, url, filename='cookies.json'): """从文件加载cookies实现免密登录""" try: with open(filename, 'r', encoding='utf8') as f: list_cookies = json.load(f) driver.get(url) driver.delete_all_cookies() for cookie in list_cookies: if 'expiry' in cookie: del cookie['expiry'] driver.add_cookie(cookie) driver.refresh() return True except Exception as e: print(f"加载cookies失败: {e}") return False def login_weibo(username, password): """模拟登录并保存cookies""" options = webdriver.ChromeOptions() # 关键:禁用自动化控制特征 options.add_argument("--disable-blink-features=AutomationControlled") driver = webdriver.Chrome(options=options) driver.get("https://weibo.com/login.php") time.sleep(3) # 输入账号密码 driver.find_element(By.ID, "loginname").send_keys(username) driver.find_element(By.NAME, "password").send_keys(password) driver.find_element(By.XPATH, "//a[@node-type='submitBtn']").click() time.sleep(5) # 等待登录完成,可能需要手动处理验证码 # 保存cookies供后续使用 save_cookies(driver) driver.quit()注意事项:
某微博可能会弹出滑块验证码,目前没有100%自动化的免费破解方案
可以使用Playwright替代Selenium,其对反爬的规避效果更好
建议使用小号测试,避免主账号被封禁的风险
方案三:使用现成的爬虫框架
如果你不想重复造轮子,社区已经有不少成熟的某微博爬虫开源项目。
WeiboSpider是基于Celery和Requests构建的分布式某微博爬虫项目,支持多任务并行处理与反爬机制的有效应对。其核心功能包括:
自动会话管理:通过cookies持久化技术维持登录状态
动态请求延迟:根据服务器响应自动调整请求间隔
代理IP池:实现代理自动切换,有效突破IP限制
异常处理机制:请求失败自动重试
Crawl4Weibo是一个即开即用的某微博爬虫Python库,支持无Cookie运行,内置了432防护的重试机制和统一的代理池管理。
安装和使用都非常简单:
pip install crawl4weibo playwright install chromiumfrom crawl4weibo import WeiboClient client = WeiboClient() uid = "2656274875" # 获取用户信息 user = client.get_user_by_uid(uid) print(f"{user.screen_name} - 粉丝: {user.followers_count}") # 获取用户动态(自动展开长文本) posts = client.get_user_posts(uid, page=1, expand=True) for post in posts[:3]: print(f"{post.text[:50]}... - 赞: {post.attitudes_count}")三、IP被封怎么办?隧道代理的解决方案
即使你成功突破了登录限制,另一个棘手的问题很快就会浮现——IP被封禁。
某微博对单个IP的请求频率有严格的限制。当同一个IP在短时间内发出大量请求时,会触发平台的保护机制。传统的解决方案是自己维护一个代理IP池,但这种方法存在两个核心问题:
IP池质量参差不齐:很多免费或低价的代理IP已经被滥用,容易被封禁
手动切换麻烦:每次更换IP都需要重新建立连接,爬一半断连是常事
什么是隧道代理?
隧道代理是传统代理的升级方案。你不需要手动维护IP池,只需预先设置好更换代理IP的规则。每次发送请求后,隧道代理会自动把流量引导至不同的出口IP——相当于给你的爬虫适配了一条专属的IP安全隧道。
这里推荐站大爷隧道代理,它在爬虫场景中有几个突出的优势:
协议支持全面:HTTP、HTTPS、SOCKS5全协议支持
地域覆盖广:覆盖全国99%地域,支持本地化数据采集
自动切换无延迟:每次请求自动切换IP,无需等待代理池刷新
弹性并发:支持成百上千的并发请求
主备双隧道:持续更新IP池,稳定性有保障
在爬虫中集成隧道代理
以下是在某微博爬虫中集成站大爷隧道代理的代码示例:
import requests # 初始化隧道代理(以站大爷为例) proxy_config = { "api_url": "https://tunnel.zhandaye.com/api", "api_key": "YOUR_API_KEY", "rotate_strategy": "per_request" # 每次请求切换IP } def fetch_with_tunnel(url, headers, cookies): """使用隧道代理发送请求""" # 获取隧道代理 proxies = { "http": "http://隧道代理地址:端口", "https": "https://隧道代理地址:端口" } try: response = requests.get( url, headers=headers, cookies=cookies, proxies=proxies, timeout=10 ) # 如果遇到403,自动切换IP重试 if response.status_code == 403: # 隧道代理会自动切换出口IP,重试即可 return requests.get(url, headers=headers, cookies=cookies, proxies=proxies, timeout=10) return response except Exception as e: print(f"请求失败: {e}") # 隧道代理自动切换IP后重试 return requests.get(url, headers=headers, cookies=cookies, proxies=proxies, timeout=10) # 使用隧道代理爬取用户动态 def get_user_posts_with_proxy(uid, page=1): url = f"https://weibo.com/ajax/statuses/mymblog?uid={uid}&page={page}" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": "https://weibo.com", } # cookies从之前保存的Cookie文件中加载 cookies = {...} response = fetch_with_tunnel(url, headers, cookies) if response and response.status_code == 200: return response.json() return None实际测试表明,使用隧道代理后IP封禁率可以从87%降至3%以下,采集效率提升显著。
四、完整实战:爬取某微博用户动态
下面我们组合以上所有技术,完成一个完整的用户动态爬取脚本。
4.1 环境准备
pip install requests beautifulsoup4 pandas fake-useragent4.2 完整代码
import requests import json import time import pandas as pd from fake_useragent import UserAgent from datetime import datetime class WeiboUserScraper: def __init__(self, cookie_file='cookies.json', use_proxy=False): """ 初始化爬虫 :param cookie_file: Cookie存储文件 :param use_proxy: 是否使用隧道代理 """ self.cookies = self._load_cookies(cookie_file) self.ua = UserAgent() self.use_proxy = use_proxy # 隧道代理配置(以站大爷为例) if use_proxy: self.proxies = { "http": "http://隧道代理地址:端口", "https": "https://隧道代理地址:端口" } else: self.proxies = None def _load_cookies(self, filename): """从文件加载Cookie""" try: with open(filename, 'r', encoding='utf8') as f: cookies_list = json.load(f) # 转换为requests可用的字典格式 cookies_dict = {} for cookie in cookies_list: cookies_dict[cookie['name']] = cookie['value'] return cookies_dict except FileNotFoundError: print(f"Cookie文件 {filename} 不存在,请先登录获取Cookie") return {} def _get_headers(self): """生成随机请求头""" return { "User-Agent": self.ua.random, "Referer": "https://weibo.com", "Accept": "application/json, text/plain, */*", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", } def _request(self, url, retry=3): """发送请求,支持重试和隧道代理""" headers = self._get_headers() for i in range(retry): try: response = requests.get( url, headers=headers, cookies=self.cookies, proxies=self.proxies, timeout=15 ) if response.status_code == 200: return response elif response.status_code == 403: print(f"第{i+1}次请求被拒绝(403),等待后重试...") time.sleep(5 * (i + 1)) else: print(f"请求失败,状态码: {response.status_code}") time.sleep(2) except Exception as e: print(f"第{i+1}次请求异常: {e}") time.sleep(3 * (i + 1)) return None def get_user_info(self, uid): """获取用户基本信息""" url = f"https://weibo.com/ajax/profile/info?uid={uid}" response = self._request(url) if response: data = response.json() return data.get('data', {}).get('user', {}) return {} def get_user_posts(self, uid, max_pages=10): """ 获取用户发布的动态 :param uid: 用户UID :param max_pages: 最大爬取页数 """ all_posts = [] for page in range(1, max_pages + 1): url = f"https://weibo.com/ajax/statuses/mymblog?uid={uid}&page={page}" response = self._request(url) if not response: print(f"第{page}页请求失败,停止爬取") break try: data = response.json() posts = data.get('data', {}).get('list', []) if not posts: print(f"第{page}页无数据,爬取完成") break for post in posts: all_posts.append({ '用户昵称': post.get('user', {}).get('screen_name', ''), '用户ID': post.get('user', {}).get('id', ''), '微博内容': post.get('text_raw', '').replace('\n', ' '), '发布时间': post.get('created_at', ''), '转发数': post.get('reposts_count', 0), '评论数': post.get('comments_count', 0), '点赞数': post.get('attitudes_count', 0), '微博链接': f"https://weibo.com/{uid}/{post.get('id', '')}", }) print(f"第{page}页爬取成功,获取{len(posts)}条动态") # 控制请求频率,避免触发反爬 time.sleep(2) except json.JSONDecodeError: print(f"第{page}页数据解析失败") break return all_posts def save_to_csv(self, data, filename='weibo_posts.csv'): """保存数据到CSV""" if not data: print("没有数据可保存") return df = pd.DataFrame(data) df.to_csv(filename, index=False, encoding='utf-8-sig') print(f"数据已保存到 {filename},共 {len(data)} 条") # 使用示例 if __name__ == "__main__": # 1. 先手动登录某微博,获取Cookie并保存为cookies.json # 2. 初始化爬虫(开启隧道代理) scraper = WeiboUserScraper(cookie_file='cookies.json', use_proxy=True) # 3. 获取用户信息 uid = "用户UID" # 替换为目标用户的UID user_info = scraper.get_user_info(uid) if user_info: print(f"用户: {user_info.get('screen_name', '')}") print(f"粉丝: {user_info.get('followers_count', 0)}") print(f"关注: {user_info.get('follow_count', 0)}") # 4. 爬取用户动态 posts = scraper.get_user_posts(uid, max_pages=5) # 5. 保存结果 scraper.save_to_csv(posts, 'user_posts.csv') # 6. 打印统计 print(f"\n爬取完成!共获取 {len(posts)} 条动态")4.3 代码解析
核心流程:
从本地文件加载Cookie(需预先手动获取)
每次请求使用随机User-Agent模拟不同浏览器
启用站大爷隧道代理,每次请求自动切换出口IP
遇到403错误自动等待后重试
控制请求频率(每次请求间隔2秒)
将数据保存为CSV格式,便于后续分析
五、常见问题与避坑指南
5.1 Cookie过期怎么办?
某微博的Cookie有效期通常为几天到几周。当遇到大量401或登录态失效的错误时,说明Cookie已过期,需要重新登录获取新的Cookie。
建议:可以写一个定时任务,每周自动重新登录一次并更新Cookie文件。
5.2 遇到滑块验证码怎么处理?
目前最实际的做法是:
半自动方案:在Selenium脚本中检测到验证码时,暂停脚本并发出通知,人工完成验证后继续
接入打码平台:使用超级鹰等第三方打码服务(成本约0.002元/次)
使用Playwright:Playwright对反爬的规避效果优于Selenium
5.3 爬取速度太快被封怎么办?
降低请求频率,建议每次请求间隔2-5秒
使用隧道代理自动切换IP
配合使用多账号轮换,在
config/conf.py中配置Cookie池
5.4 Selenium脚本总是被拦截?
检查以下几点:
是否添加了
--disable-blink-features=AutomationControlled参数是否禁用了
navigator.webdriver属性滚动操作是否模拟了人类的加速度和停顿,而非瞬间跳转
5.5 搜索结果只有50页怎么办?
某微博的搜索结果最多显示50页。如果需要爬取更长时间范围的数据,可以按时间段拆分——比如按每小时拆一个区间,每个区间单独爬取,从而绕过50页的限制。
六、总结
本文从某微博的反爬机制入手,详细介绍了三种突破登录限制的方案:
| 方案 | 适用场景 | 难度 | 稳定性 |
|---|---|---|---|
| 手动获取Cookie | 初学者、短期项目 | ⭐ | ⭐⭐⭐⭐ |
| Selenium模拟登录 | 全自动化需求 | ⭐⭐⭐ | ⭐⭐⭐ |
| 现成框架(WeiboSpider/Crawl4Weibo) | 大规模采集 | ⭐⭐ | ⭐⭐⭐⭐ |
同时,我们重点介绍了站大爷隧道代理在解决IP封禁问题上的应用——通过每次请求自动切换出口IP,将IP封禁率从87%降至3%以下。
爬取某微博用户动态的核心要点可以概括为三句话:
用对Cookie突破登录,用隧道代理突破IP限制,用模拟真人行为突破风控检测。
希望本文能帮助你顺利完成某微博用户动态的数据采集工作。记住,爬虫技术的本质是模拟人类用户的正常访问行为——越像真人,就越不容易被拦截。祝你在数据采集的道路上越走越顺!
