← 返回列表

简易网页内容获取

使用 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()

注意事项与最佳实践

法律与道德规范

  1. 遵守 robots.txt: 检查网站的 robots.txt 文件,遵守获取规则
  2. 服务条款: 阅读并遵守网站的服务条款
  3. 数据使用: 仅用于个人学习或合法用途,不可商业化使用他人数据

技术最佳实践

  1. 设置 User-Agent: 模拟浏览器请求,避免被识别为内容获取
  2. 控制频率: 添加延迟(time.sleep),避免对服务器造成压力
  3. 异常处理: 妥善处理网络错误、超时、解析失败等异常
  4. 日志记录: 记录获取过程,便于调试和监控
  5. 增量更新: 只获取新增内容,避免重复获取

反内容获取应对

  • 使用代理 IP 池
  • 随机化请求头
  • 模拟人类行为(随机延迟、点击轨迹)
  • 使用验证码识别服务

通过掌握网页内容获取技术,你可以自动化收集海量网络数据,为数据分析、市场研究、内容聚合等应用提供数据支持。