← 返回列表
简易网页内容获取
使用 Requests 库获取网页 HTML 内容,并配合 BeautifulSoup 解析库提取特定的新闻标题和链接。该脚本展示了如何自动化收集网络信息。
快速预览:
import requests
from bs4 import BeautifulSoup
res = requests.get('https://news.example.com')
soup = BeautifulSoup(res.text, 'html.parser')
for news in soup.find_all('h2', class_='title'):
print(news.get_text().strip())
应用场景与价值
网络内容获取是自动化信息收集的强大工具,在实际工作中有广泛应用:
- 新闻聚合: 自动获取多个新闻网站的头条,创建个性化新闻摘要
- 价格监控: 追踪电商网站商品价格变化,发现最佳购买时机
- 数据分析: 收集行业资讯、竞品信息,支持市场研究
- 内容监测: 监控特定网站更新,及时获取最新信息
- 学术研究: 批量收集研究数据,用于文本分析和数据挖掘
本案例将带你掌握网页内容获取的核心技能,为构建更复杂的数据采集系统打下基础。
基础知识
Requests 库
requests 是 Python 最流行的 HTTP 库,提供了简洁优雅的 API:
import requests
# GET 请求
response = requests.get(url)
# 常用属性
response.status_code # HTTP 状态码(200 表示成功)
response.text # 响应内容(字符串)
response.content # 响应内容(字节)
response.json() # 解析 JSON 响应
BeautifulSoup 库
BeautifulSoup 是强大的 HTML/XML 解析库,能够轻松提取网页数据:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
# 查找元素
soup.find('div', class_='content') # 查找第一个匹配元素
soup.find_all('a', class_='link') # 查找所有匹配元素
soup.select('div.content > p') # CSS 选择器
# 提取数据
element.get_text() # 获取文本内容
element['href'] # 获取属性值
element.attrs # 获取所有属性
HTML 结构基础
理解 HTML 的基本结构对内容获开发至关重要:
<div class="news-item">
<h2 class="title">
<a href="/article/123">新闻标题</a>
</h2>
<p class="summary">新闻摘要...</p>
</div>
代码详解
让我们深入分析内容获取代码的工作原理:
import requests
from bs4 import BeautifulSoup
导入必需的库。如果没有安装,使用 uv add requests beautifulsoup4 安装。
res = requests.get('https://news.example.com')
向目标网站发送 HTTP GET 请求,获取网页内容。res 对象包含了服务器的响应信息。
soup = BeautifulSoup(res.text, 'html.parser')
创建 BeautifulSoup 对象,将 HTML 文本解析为可操作的文档树。'html.parser' 是 Python 内置的解析器。
for news in soup.find_all('h2', class_='title'):
查找所有 class 为 'title' 的 h2 标签。这通常是新闻标题所在的位置。
print(news.get_text().strip())
提取标签内的文本内容,strip() 方法去除首尾空白字符,输出整洁的标题。
完整代码
基础版本:获取新闻标题
import requests
from bs4 import BeautifulSoup
def fetch_news_titles(url):
"""
获取新闻网站的标题
参数:
url: 目标新闻网站的 URL
返回:
标题列表
"""
try:
# 发送请求
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status() # 检查请求是否成功
# 解析 HTML
soup = BeautifulSoup(response.text, 'html.parser')
# 提取标题
titles = []
for news in soup.find_all('h2', class_='title'):
title = news.get_text().strip()
if title: # 确保标题不为空
titles.append(title)
return titles
except requests.RequestException as e:
print(f"请求失败: {e}")
return []
# 使用示例
if __name__ == "__main__":
url = 'https://news.example.com'
titles = fetch_news_titles(url)
print(f"共获取到 {len(titles)} 条新闻标题:\n")
for i, title in enumerate(titles, 1):
print(f"{i}. {title}")
进阶版本:获取标题和链接
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
def fetch_news_with_links(url):
"""
获取新闻标题和链接
返回:
包含标题和链接的字典列表
"""
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
news_list = []
for news_item in soup.find_all('div', class_='news-item'):
title_tag = news_item.find('h2', class_='title')
link_tag = news_item.find('a')
if title_tag and link_tag:
title = title_tag.get_text().strip()
# 使用 urljoin 处理相对链接
link = urljoin(url, link_tag.get('href', ''))
news_list.append({
'title': title,
'link': link
})
return news_list
except Exception as e:
print(f"获取失败: {e}")
return []
# 使用示例
news_data = fetch_news_with_links('https://news.example.com')
for news in news_data:
print(f"标题: {news['title']}")
print(f"链接: {news['link']}\n")
高级版本:保存到文件
import requests
from bs4 import BeautifulSoup
import json
from datetime import datetime
def crawl_and_save(url, output_file='news.json'):
"""
获取新闻并保存到 JSON 文件
"""
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
news_data = {
'crawl_time': datetime.now().isoformat(),
'source_url': url,
'news_list': []
}
for news_item in soup.find_all('article', class_='news'):
title = news_item.find('h2').get_text().strip() if news_item.find('h2') else ''
summary = news_item.find('p', class_='summary').get_text().strip() if news_item.find('p', class_='summary') else ''
link = news_item.find('a')['href'] if news_item.find('a') else ''
news_data['news_list'].append({
'title': title,
'summary': summary,
'link': link
})
# 保存到 JSON 文件
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(news_data, f, ensure_ascii=False, indent=2)
print(f"成功获取 {len(news_data['news_list'])} 条新闻,已保存到 {output_file}")
return news_data
except Exception as e:
print(f"错误: {e}")
return None
# 使用示例
crawl_and_save('https://news.example.com', 'news_20260109.json')
运行示例
安装依赖
uv add requests beautifulsoup4
执行内容获取
uv run main.py
预期输出
共获取到 15 条新闻标题:
1. 科技公司发布最新产品引发市场关注
2. 经济数据显示市场回暖趋势明显
3. 国际会议聚焦气候变化议题
4. 体育赛事精彩瞬间回顾
5. 文化活动丰富市民生活
...
成功获取 15 条新闻,已保存到 news_20260109.json
扩展思路
1. 多页面获取
实现翻页功能,获取多页内容:
def crawl_multiple_pages(base_url, max_pages=5):
"""获取多页新闻"""
all_news = []
for page in range(1, max_pages + 1):
url = f"{base_url}?page={page}"
news = fetch_news_with_links(url)
all_news.extend(news)
time.sleep(1) # 礼貌性延迟
return all_news
2. 添加错误重试机制
from time import sleep
def fetch_with_retry(url, max_retries=3):
"""带重试机制的请求"""
for attempt in range(max_retries):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response
except requests.RequestException as e:
if attempt == max_retries - 1:
raise
print(f"第 {attempt + 1} 次尝试失败,重试中...")
sleep(2 ** attempt) # 指数退避
3. 使用 CSS 选择器
# 更灵活的元素定位
titles = soup.select('div.content > h2.title > a')
for title in titles:
print(title.get_text())
4. 处理动态内容
对于 JavaScript 渲染的页面,使用 Selenium:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
5. 数据清洗与验证
import re
def clean_text(text):
"""清洗文本数据"""
# 去除多余空白
text = re.sub(r'\s+', ' ', text)
# 去除特殊字符
text = re.sub(r'[^\w\s\u4e00-\u9fff]', '', text)
return text.strip()
6. 定时任务
使用 schedule 库实现定时获取:
import schedule
import time
def job():
crawl_and_save('https://news.example.com')
schedule.every().hour.do(job)
while True:
schedule.run_pending()
time.sleep(60)
7. 数据存储到数据库
import sqlite3
def save_to_database(news_list):
"""保存到 SQLite 数据库"""
conn = sqlite3.connect('news.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS news (
id INTEGER PRIMARY KEY,
title TEXT,
link TEXT UNIQUE,
crawl_time TIMESTAMP
)
''')
for news in news_list:
cursor.execute(
'INSERT OR IGNORE INTO news (title, link, crawl_time) VALUES (?, ?, ?)',
(news['title'], news['link'], datetime.now())
)
conn.commit()
conn.close()
注意事项与最佳实践
法律与道德规范
- 遵守 robots.txt: 检查网站的 robots.txt 文件,遵守获取规则
- 服务条款: 阅读并遵守网站的服务条款
- 数据使用: 仅用于个人学习或合法用途,不可商业化使用他人数据
技术最佳实践
- 设置 User-Agent: 模拟浏览器请求,避免被识别为内容获取
- 控制频率: 添加延迟(time.sleep),避免对服务器造成压力
- 异常处理: 妥善处理网络错误、超时、解析失败等异常
- 日志记录: 记录获取过程,便于调试和监控
- 增量更新: 只获取新增内容,避免重复获取
反内容获取应对
- 使用代理 IP 池
- 随机化请求头
- 模拟人类行为(随机延迟、点击轨迹)
- 使用验证码识别服务
通过掌握网页内容获取技术,你可以自动化收集海量网络数据,为数据分析、市场研究、内容聚合等应用提供数据支持。