3. 数据采集基础:新闻API介绍与实战抓取
做新闻情绪分析,第一步就是搞到数据。说白了,你得先有新闻,才能分析它的情绪。
我个人习惯用API来抓取新闻数据。为什么?因为省事。你想想看,手动去各大新闻网站爬页面,又要处理反爬,又要解析HTML,太折腾了。API直接给你结构化的数据,多香。
这一章,我们就来聊聊两个主流的新闻API——NewsAPI和GDELT,以及怎么用Python把它们的数据拿到手。
3.1 两大新闻API:NewsAPI vs GDELT
我在项目中用过不少新闻数据源,但最常用的就这两个。它们各有千秋,我分别说说。
3.1.1 NewsAPI
NewsAPI是一个聚合新闻API,覆盖了全球上千家新闻源。它的特点是:
- 数据新鲜:主要提供最近30天内的新闻
- 结构清晰:返回的JSON格式非常规整
- 有免费额度:开发者账号每天100次请求,够你练手了
- 支持关键词搜索:可以按主题、来源、语言等过滤
重要提醒:NewsAPI的免费版不支持历史新闻搜索,只能查最近30天的。如果你需要历史数据,得考虑GDELT或者付费方案。
3.1.2 GDELT
GDELT(Global Database of Events, Language, and Tone)是个庞然大物。它监控全球100多种语言的新闻媒体,数据量巨大。
它的特点:
- 历史数据丰富:从1979年至今的新闻都有
- 自带情绪分析:每条新闻都有情绪评分(Tone)
- 更新频繁:每15分钟更新一次
- 免费开放:完全免费,没有请求次数限制
我的经验:如果你做的是短期事件分析(比如某公司最近一周的舆情),用NewsAPI就够了。但如果你要研究长期趋势(比如某行业过去十年的情绪变化),GDELT是更好的选择。
3.2 用requests库抓取新闻数据
好,理论说完了,咱们直接上代码。Python的requests库是抓取API数据的标配工具。
3.2.1 安装与导入
pip install requests
import requests
import json
from datetime import datetime, timedelta
3.2.2 抓取NewsAPI数据
首先,你需要去 newsapi.org 注册一个账号,拿到API Key。免费的。
# 配置你的API Key
API_KEY = "你的API_KEY"
# 构建请求参数
url = "https://newsapi.org/v2/everything"
params = {
"q": "人工智能", # 搜索关键词
"language": "zh", # 中文新闻
"sortBy": "publishedAt", # 按发布时间排序
"pageSize": 20, # 每页20条
"from": (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
}
# 发送请求
headers = {"X-Api-Key": API_KEY}
response = requests.get(url, params=params, headers=headers)
# 检查状态码
if response.status_code == 200:
data = response.json()
print(f"成功获取 {data['totalResults']} 条新闻")
else:
print(f"请求失败,状态码:{response.status_code}")
避坑指南:我曾经犯过一个低级错误——把API Key直接写在代码里,然后上传到了GitHub。结果第二天就收到邮件说我的Key被滥用,被冻结了。嗯,从那以后我都是用环境变量来管理API Key。
3.2.3 抓取GDELT数据
GDELT的API稍微有点不一样。它用的是GKG(Global Knowledge Graph)接口,返回的是CSV格式的数据。
# GDELT GKG API
url = "https://api.gdeltproject.org/api/v2/doc/doc"
params = {
"query": "人工智能", # 搜索关键词
"mode": "artlist", # 返回文章列表
"format": "json", # 返回JSON格式
"maxrecords": 20, # 最多20条
"timespan": "7d" # 最近7天
}
response = requests.get(url, params=params)
if response.status_code == 200:
data = response.json()
articles = data.get("articles", [])
print(f"成功获取 {len(articles)} 条新闻")
else:
print(f"请求失败,状态码:{response.status_code}")
小技巧:GDELT的查询语法很灵活。你可以用sourcecountry:CN来限定中国来源,用tone>5来筛选正面情绪较高的新闻。具体语法可以参考GDELT官方文档。
3.3 数据格式解析:JSON
抓回来的数据,大部分是JSON格式。你得学会怎么解析它。
3.3.1 JSON结构长什么样?
NewsAPI返回的JSON结构大概是这样的:
{
"status": "ok",
"totalResults": 100,
"articles": [
{
"source": {
"id": "techcrunch",
"name": "TechCrunch"
},
"author": "John Doe",
"title": "人工智能的最新突破",
"description": "这是一篇关于AI突破的文章...",
"url": "https://...",
"publishedAt": "2024-01-15T08:00:00Z",
"content": "全文内容..."
},
// ...更多文章
]
}
3.3.2 解析JSON数据
拿到JSON后,怎么提取我们需要的信息?看代码:
def parse_newsapi_response(data):
"""解析NewsAPI返回的JSON数据"""
articles = []
for item in data.get("articles", []):
article = {
"title": item.get("title", ""),
"description": item.get("description", ""),
"content": item.get("content", ""),
"source": item.get("source", {}).get("name", ""),
"author": item.get("author", ""),
"published_at": item.get("publishedAt", ""),
"url": item.get("url", "")
}
articles.append(article)
return articles
# 使用示例
parsed_data = parse_newsapi_response(data)
for article in parsed_data[:3]: # 打印前3条
print(f"标题:{article['title']}")
print(f"来源:{article['source']}")
print(f"时间:{article['published_at']}")
print("-" * 50)
注意:GDELT返回的JSON结构略有不同。它的articles里每个字段名是title、url、seendate等。而且GDELT多了一个tone字段,直接给出了情绪评分。这个我们后面做情绪分析时会重点用到。
3.4 本章知识体系
为了让你更直观地理解这一章的内容,我画了一张流程图:
3.5 完整示例:抓取并保存新闻
最后,我给你一个完整的示例。把抓取和解析整合到一起,并保存到本地文件:
import requests
import json
from datetime import datetime, timedelta
def fetch_news(api_key, query="人工智能", days=7, max_results=20):
"""抓取新闻并返回结构化数据"""
url = "https://newsapi.org/v2/everything"
params = {
"q": query,
"language": "zh",
"sortBy": "publishedAt",
"pageSize": max_results,
"from": (datetime.now() - timedelta(days=days)).strftime("%Y-%m-%d")
}
headers = {"X-Api-Key": api_key}
response = requests.get(url, params=params, headers=headers)
if response.status_code != 200:
print(f"请求失败:{response.status_code}")
return []
data = response.json()
articles = []
for item in data.get("articles", []):
article = {
"title": item.get("title", ""),
"description": item.get("description", ""),
"content": item.get("content", ""),
"source": item.get("source", {}).get("name", ""),
"published_at": item.get("publishedAt", ""),
"url": item.get("url", "")
}
articles.append(article)
return articles
# 使用示例
API_KEY = "你的API_KEY"
news_data = fetch_news(API_KEY, query="人工智能", days=7, max_results=10)
# 保存到文件
with open("news_data.json", "w", encoding="utf-8") as f:
json.dump(news_data, f, ensure_ascii=False, indent=2)
print(f"成功保存 {len(news_data)} 条新闻到 news_data.json")
我的建议:刚开始做的时候,别贪多。先抓个10条20条数据,把整个流程跑通。确认数据格式没问题了,再慢慢扩大规模。我曾经一上来就抓了5000条,结果发现数据里有大量重复和无关内容,处理起来特别痛苦。
好了,这一章的内容就到这里。数据采集是基础中的基础,但也是最重要的一步。数据质量决定了你后续分析的上限。下一章,我们会聊聊怎么清洗和预处理这些新闻数据——嗯,那才是真正考验耐心的时候。
公众号:蓝海资料掘金营,微信deep3321