在大数据分析的工作中,数据采集是一切的基础,而实际的网页数据分为服务器端渲染的静态数据和接口动态加载的动态数据,二者的采集思路和方法差异显著。本次以新浪新闻为采集对象,用 Python 实现了单篇新闻静态正文 + 动态评论的全流程采集、解析、清洗与存储,全程整合Requests、BeautifulSoup、re、Pandas等核心库,下文分享完整的实现思路和代码细节。
一、技术栈与采集对象说明
1. 核心技术模块
本次采集从请求、解析、存储到预处理,各环节选用轻量且高效的 Python 库,各司其职又相互配合:
- 请求模块:Requests库,模拟浏览器请求头,支持会话保持,适配静态页面和动态 API 请求;
- 解析模块:BeautifulSoup4+re正则,前者解析结构化 HTML 提取静态内容,后者匹配 JS 代码中的隐藏参数;
- 存储模块:Pandas库,将数据规整为 DataFrame,一键导出 CSV/TXT 格式,方便后续分析;
- 预处理模块:Python 字符串方法 +BeautifulSoup文本提取,实现空白符、HTML 标签的快速清洗。
2. 采集对象
以新浪新闻(news.sina.com.cn)单篇新闻为目标,拆分两类采集内容:
- 静态数据:新闻标题、发布信息、正文内容(服务器端渲染,直接嵌入 HTML 源码);
- 动态数据:新闻下方的用户评论(通过独立 API 接口动态加载,需解析请求参数和返回的 JSON 数据)。
二、静态新闻数据采集:解析 HTML 源码
静态数据的核心是获取 HTML 并精准提取结构化内容,同时一个关键任务是从页面 JS 代码中提取动态评论 API 的调用参数,为后续采集评论做准备。
2.1 核心思路
2.2 静态采集核心代码
import requests
import json
import time
import random
import pandas as pd
import re
from bs4 import BeautifulSoup
class SinaNewsRealScraper:
"""新浪新闻静态正文+动态评论采集器"""
def __init__(self, news_url, cookie):
self.news_url = news_url
self.session = requests.Session()
# 构造请求头,模拟浏览器行为
self.session.headers.update({
"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,
"Referer": "https://news.sina.com.cn/"
})
def scrape_static_info(self):
"""采集新闻静态信息,提取标题、正文及评论API参数"""
print(f"—开始采集新闻静态信息:{self.news_url}—")
try:
# 获取页面HTML
response = self.session.get(self.news_url, timeout=20)
response.raise_for_status() # 抛出请求异常
# 自动识别编码,解决中文乱码
response.encoding = response.apparent_encoding
soup = BeautifulSoup(response.text, "lxml")
# 提取新闻标题
title = soup.find("h1", class_='main-title').text.strip()
# 提取新闻正文
article_body = soup.find("div", id='article')
content = "\\n".join([p.text.strip() for p in article_body.find_all('p')])
# 从JS代码中提取评论API的channel和newsid参数
script_text = response.text
channel_match = re.search(r"channel: '(\\w+)'", script_text)
newsid_match = re.search(r"newsid: '(\\w+-[\\w]+)'", script_text)
# 校验参数是否提取成功
if not (channel_match and newsid_match):
print("错误:未能在页面源码中找到API所需的channel和newsid参数。")
return None
# 整理API参数和静态信息
api_params = {
'channel': channel_match.group(1),
'newsid': newsid_match.group(1)
}
static_info = {
'title': title,
'content': content,
'api_params': api_params
}
print("静态信息及API参数采集成功!")
return static_info
except requests.RequestException as e:
print(f"采集静态信息失败:{e}")
return None
except Exception as e:
print(f"解析静态信息或提取参数时失败:{e}")
return None
三、动态评论数据采集:请求 API 接口
新闻评论并非直接嵌入 HTML,而是通过前端 JS 调用 API 接口动态加载,因此核心是构造合法的 API 请求 URL,分页获取 JSON 数据并解析。
3.1 核心思路
3.2 动态采集核心代码
在上述SinaNewsRealScraper类中继续添加动态采集方法:
def scrape_dynamic_comments(self, api_params):
"""采集动态评论数据,分页请求API接口"""
all_comments = []
page = 1
# 分页请求,直到无新评论返回
while True:
try:
# 构造评论API请求URL(新浪新闻评论API通用格式)
comment_api = f"https://comment.sina.com.cn/page/info?version=1&format=json&channel={api_params['channel']}&newsid={api_params['newsid']}&page={page}"
response = self.session.get(comment_api, timeout=20)
response.raise_for_status()
comment_data = json.loads(response.text)
# 解析评论列表
cmnt_list = comment_data.get('result', {}).get('data', {}).get('cmntlist', [])
if not cmnt_list:
print(f"第{page}页无评论,评论采集完成")
break
# 遍历评论,清洗并整理数据
for cmnt in cmnt_list:
comment = {
'user_name': cmnt.get('nick', '匿名用户'),
'location': cmnt.get('area', '未知地区'),
'time': cmnt.get('time', ''),
'content': cmnt.get('content', '').strip() # 去除空白符
}
all_comments.append(comment)
print(f"第{page}页评论采集完成,共{len(cmnt_list)}条")
page += 1
# 随机休眠,避免请求过快被限制
time.sleep(random.uniform(0.5, 1.5))
except Exception as e:
print(f"第{page}页评论采集失败:{e}")
break
return all_comments
四、数据清洗与存储:规整并导出文件
采集到的静态新闻信息和动态评论数据,需要统一清洗并存储为易读、易分析的格式,本次实现CSV(结构化数据)+TXT(纯文本) 双格式导出,兼顾后续数据分析和人工查看。
4.1 核心思路
4.2 数据存储核心代码
继续在类中添加保存方法,并实现主调用逻辑:
def save_data(self, static_info, comments):
"""将采集数据保存为CSV(评论)和TXT(新闻+评论)"""
if not static_info or not comments:
print("无有效数据可保存")
return
print("\\n—开始保存文件—")
# 保存评论为CSV文件
try:
df = pd.DataFrame(comments)
csv_filename = 'sina_news_real.csv'
df.to_csv(csv_filename, index=False, encoding='utf-8-sig')
print(f"评论数据已成功保存到'{csv_filename}'")
except Exception as e:
print(f"保存CSV文件时出错:{e}")
# 保存新闻+评论为TXT文件
try:
txt_filename = 'sina_news_real.txt'
with open(txt_filename, 'w', encoding='utf-8') as f:
f.write(f"新闻标题:{static_info['title']}\\n")
f.write("="*40 + "\\n")
f.write(f"新闻正文:\\n{static_info['content']}\\n\\n")
f.write("="*40 + "\\n")
f.write(f"用户评论(共{len(comments)}条):\\n")
for comment in comments:
f.write(f"—\\n用户:{comment['user_name']}({comment['location']})\\n")
f.write(f"时间:{comment['time']}\\n内容:{comment['content']}\\n")
print(f"新闻及评论数据已成功保存到'{txt_filename}'")
except Exception as e:
print(f"保存TXT文件时出错:{e}")
# 主调用函数
if __name__ == "__main__":
# 替换为目标新闻URL和自己的新浪Cookie
NEWS_URL = "https://news.sina.com.cn/s/2025-06-15/doc-imyfkzsy8999912.shtml"
COOKIE = "你的新浪Cookie值"
# 初始化采集器并执行采集
scraper = SinaNewsRealScraper(NEWS_URL, COOKIE)
static_info = scraper.scrape_static_info()
if static_info:
comments = scraper.scrape_dynamic_comments(static_info['api_params'])
scraper.save_data(static_info, comments)
print("—整个采集流程执行完毕—")
五、采集结果与分析
本次以新浪新闻《多地出现蜱虫伤人事件,严重可致死!医生提醒》为采集目标,最终实现了完整的数据采集:
从采集结果也能发现一个行业现象:传统门户网站的用户互动数据量大幅减少,这与社交媒体、垂直 APP 的兴起相关,用户更倾向于在专属平台发表观点,门户网站的流量和粘性呈下降趋势。
六、关键问题解决与实战技巧
本次采集的核心难点是从页面 JS 代码中提取评论 API 的隐藏参数,这也是现代网页采集的常见痛点,分享解决方法和实战技巧:
七、应用前景与技术展望
1. 实际应用前景
本次采集的新闻正文和用户评论,是舆情分析、热点事件追踪、公众观点挖掘的优质数据源:
- 对评论做情感分析,可判断公众对热点事件的正面 / 负面 / 中立态度;
- 结合地理位置信息,分析不同地区用户的关注重点;
- 对新闻正文和评论做关键词提取,挖掘事件的核心讨论点。这些分析结果可应用于新闻传播学研究、市场营销、公共政策制定等领域。
2. 技术优化与展望
本次实现的是单篇新闻的采集,后续可从以下方面优化,实现规模化采集:
八、实战总结
本次实战完成了从静态 HTML 解析到动态 API 请求的全流程网页采集,核心收获有两点:





