一、爬虫环境准备与核心库安装

1.1 Python 环境搭建

本文基于Python 3.8 及以上版本开发,若尚未安装 Python,可从Python 官方网站下载对应系统的安装包,安装时务必勾选Add Python to PATH,完成后可在终端执行以下命令验证安装:

python --version # 或 macOS/Linux 执行 python3 --version

规范建议:为每个爬虫项目创建独立虚拟环境,避免全局依赖冲突,执行命令如下:

# 创建虚拟环境

python -m venv crawler_env

# 激活虚拟环境 #

#Windows: crawler_env\Scripts\activate    # macOS/Linux: source crawler_env/bin/activate

1.2 核心爬虫库安装

Python 爬虫的高效开发依赖成熟的第三方库,分为基础必备库进阶工具库,所有库均可通过pip包管理器安装

以下是爬虫常用的四个库(win+r打开命令提示符运行下列代码):requests、beautifulsoup、scrapy、selenium

pip install requests beautifulsoup4 scrapy selenium

二、爬虫核心原理与基础流程

2.1 爬虫的核心工作闭环

无论简单还是复杂的爬虫,本质都是完成「模拟请求→获取响应→解析数据→存储数据」的闭环流程,四个步骤的核心目标如下:

  1. 模拟请求:伪装成浏览器,向目标服务器发送符合规范的 HTTP 请求,携带必要的身份信息;
  2. 获取响应:接收服务器返回的响应内容,包括网页 HTML 源码、JSON 接口数据、二进制文件等;
  3. 解析数据:从响应内容中过滤、提取我们需要的结构化数据,剔除无关的冗余内容;
  4. 存储数据:将提取的有效数据按照需求保存到本地文件或数据库中,方便后续使用。

2.2 HTTP 协议基础

爬虫的核心是 HTTP 请求,必须掌握以下基础概念,才能应对后续的反爬与复杂场景:

  1. 核心请求方法

    • GET:最常用的请求方法,用于从服务器获取资源,参数直接拼接在 URL 中,无请求体,适合普通网页、接口数据获取;
    • POST:用于向服务器提交数据,参数放在请求体中,安全性更高,适合登录、表单提交、加密接口请求。
  2. 关键请求头字段请求头是服务器识别客户端身份的核心依据,也是反爬校验的重点,新手必须掌握以下关键字段:

    User-Agent客户端标识,记录浏览器版本、操作系统等信息,是最基础的反爬校验项,必须携带

         Referer记录当前请求的来源页面,用于校验请求是否来自网站自身,应对防盗链、来源校             验反爬

         Cookie存储用户会话信息、登录状态,用于需要登录才能访问的页面,维持会话连续性                   Accept声明客户端可接收的内容类型,如text/htmlapplication/json

常见响应状态码服务器通过状态码告知请求结果,可通过状态码快速定位问题:

  • 200 OK:请求成功,服务器正常返回内容;
  • 403 Forbidden:服务器拒绝访问,大概率触发了反爬机制;
  • 404 Not Found:请求的资源不存在,URL 错误或页面已下架;
  • 429 Too Many Requests:请求频率过高,触发了服务器限流规则;
  • 500 Internal Server Error:服务器内部出错,与爬虫无关。

2.3 HTML 网页结构基础

网页的核心是 HTML(超文本标记语言),由嵌套的标签组成,形成 DOM 树结构,爬虫解析数据的本质就是从 DOM 树中定位目标标签,提取标签内的文本或属性。

基础 HTML 结构示例:

html

预览

<!DOCTYPE html>
<html>
<head>
    <title>测试页面</title>
</head>
<body>
    <div class="news-list">
        <div class="news-item">
            <a href="https://example.com/news/1" class="news-title">第一条新闻标题</a>
            <span class="news-date">2026-03-05</span>
        </div>
        <div class="news-item">
            <a href="https://example.com/news/2" class="news-title">第二条新闻标题</a>
            <span class="news-date">2026-03-04</span>
        </div>
    </div>
</body>
</html>

在这个示例中,我们需要提取的新闻标题和链接,就存放在<a>标签的文本和href属性中,通过 BeautifulSoup 或 XPath 即可快速定位。

三、基础网页爬取实战

本节从 0 到 1 实现 3 个渐进式的爬虫案例,所有案例均基于公开合规的测试场景,新手可直接复制代码运行,理解每一步的核心逻辑。

3.1 案例 1:第一个极简爬虫(获取网页源码)

核心目标:使用 requests 库发送 GET 请求,获取目标网页的 HTML 源码,理解请求与响应的核心流程。

import requests

# 配置请求参数

url = "http://example.com"

# 配置请求头,携带User-Agent,模拟浏览器访问

headers = {

    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"

}

# 3. 发送GET请求,捕获异常

try:

    # 发送请求,设置超时时间10秒

    response = requests.get(url, headers=headers, timeout=10)

    # 校验请求是否成功,状态码非200则抛出异常

    response.raise_for_status()

    # 设置响应编码,避免中文乱码

    response.encoding = response.apparent_encoding

    # 4. 处理响应结果

    print("请求成功,状态码:", response.status_code)

    print("="*50)

    # 打印网页HTML源码

    print(response.text)

    # 可选:将源码保存到本地文件

    with open("example.html", "w", encoding="utf-8") as f:

        f.write(response.text)

    print("="*50)

    print("网页源码已保存到example.html")

except Exception as e:

    print("请求失败,错误信息:", e)

4.1 需求与网站分析

  1. 爬取目标:豆瓣电影 Top250 所有电影的结构化数据,包括排名、电影名称、导演、主演、上映年份、国家、类型、评分、评价人数、简介;
  2. URL 规律:豆瓣 Top250 分页 URL 为https://movie.douban.com/top250?start={offset}&filter=,每页 25 条数据,offset 从 0 开始,每次 + 25,共 10 页;
  3. 反爬应对:携带完整请求头、添加随机延迟、使用会话维持 Cookie。

4.2 完整代码实现

import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
from fake_useragent import UserAgent

# 初始化配置
ua = UserAgent()
session = requests.Session()
# 基础URL
base_url = "https://movie.douban.com/top250"
# 存储所有电影数据
all_movies = []

# 请求头配置
def get_headers():
    return {
        "User-Agent": ua.random,
        "Referer": "https://movie.douban.com/",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
        "Connection": "keep-alive",
        "Host": "movie.douban.com"
    }

# 发送请求获取页面源码
def get_page_html(url):
    try:
        # 随机延迟2-4秒,严格控制频率
        time.sleep(random.uniform(2, 4))
        response = session.get(url, headers=get_headers(), timeout=15)
        response.raise_for_status()
        response.encoding = "utf-8"
        return response.text
    except Exception as e:
        print(f"页面请求失败{url}:", e)
        return None

# 解析单页数据
def parse_movie_list(html):
    if not html:
        return []
    soup = BeautifulSoup(html, "lxml")
    # 定位电影列表
    movie_items = soup.find_all("div", class_="item")
    page_movies = []
    
    for item in movie_items:
        try:
            # 提取排名
            rank = item.find("em").get_text(strip=True)
            # 提取电影名称
            title_tag = item.find("span", class_="title")
            title = title_tag.get_text(strip=True) if title_tag else ""
            # 提取其他名称
            other_title = item.find("span", class_="other").get_text(strip=True).replace(" / ", "") if item.find("span", class_="other") else ""
            # 提取评分
            rating = item.find("span", class_="rating_num").get_text(strip=True) if item.find("span", class_="rating_num") else ""
            # 提取评价人数
            comment_num = item.find("div", class_="star").find_all("span")[-1].get_text(strip=True).replace("人评价", "") if item.find("div", class_="star") else ""
            # 提取简介
            quote = item.find("span", class_="inq").get_text(strip=True) if item.find("span", class_="inq") else "无简介"
            
            # 提取导演、年份、国家、类型信息
            info_tag = item.find("div", class_="bd").find("p", class_="")
            info_text = info_tag.get_text(strip=True, separator="\n") if info_tag else ""
            # 分割信息行
            info_lines = info_text.split("\n")
            # 第一行:导演/主演
            director_line = info_lines[0] if len(info_lines) > 0 else ""
            director = director_line.split("导演:")[-1].split("主演:")[0].strip() if "导演:" in director_line else ""
            # 第二行:年份/国家/类型
            year_line = info_lines[1] if len(info_lines) > 1 else ""
            year_info = year_line.split("/")
            year = year_info[0].strip() if len(year_info) > 0 else ""
            country = year_info[1].strip() if len(year_info) > 1 else ""
            movie_type = year_info[2].strip() if len(year_info) > 2 else ""
            
            # 存入字典
            movie_info = {
                "排名": rank,
                "电影名称": title,
                "别名": other_title,
                "导演": director,
                "上映年份": year,
                "国家": country,
                "类型": movie_type,
                "评分": rating,
                "评价人数": comment_num,
                "简介": quote
            }
            page_movies.append(movie_info)
            print(f"已提取:排名{rank} - {title}")
            
        except Exception as e:
            print(f"单条电影数据解析失败:", e)
            continue
    return page_movies

# 主函数:循环爬取所有页面
def main():
    print("开始爬取豆瓣电影Top250")
    print("="*80)
    
    # 循环10页,offset从0到225,步长25
    for offset in range(0, 250, 25):
        page_url = f"{base_url}?start={offset}&filter="
        print(f"\n正在爬取第{int(offset/25 + 1)}页,URL:{page_url}")
        
        # 获取页面源码
        html = get_page_html(page_url)
        if not html:
            print(f"第{int(offset/25 + 1)}页获取失败,跳过")
            continue
        
        # 解析页面数据
        page_movies = parse_movie_list(html)
        if page_movies:
            all_movies.extend(page_movies)
            print(f"第{int(offset/25 + 1)}页爬取完成,成功提取{len(page_movies)}条数据")
        else:
            print(f"第{int(offset/25 + 1)}页未提取到有效数据")
    
    print("\n" + "="*80)
    print(f"所有页面爬取完成,共提取{len(all_movies)}条电影数据")
    
    # 保存数据到CSV文件
    if all_movies:
        df = pd.DataFrame(all_movies)
        df.to_csv("豆瓣电影Top250.csv", index=False, encoding="utf-8-sig")
        print("数据已保存到 豆瓣电影Top250.csv")

# 执行主函数
if __name__ == "__main__":
    main()

5.3 运行说明

  1. 提前安装所需依赖:pip install requests beautifulsoup4 lxml pandas fake_useragent
  2. 直接运行代码,程序会自动爬取 10 页数据,控制台实时打印爬取进度;
  3. 爬取完成后,会在代码同级目录生成豆瓣电影Top250.csv文件,可用 Excel 打开查看完整数据。

六、爬虫数据存储方案

爬取到的结构化数据,需要根据数据量和使用场景选择合适的存储方式,以下是 3 种最常用的存储方案,覆盖绝大多数入门场景。

6.1 TXT 文本存储

适合少量、简单的文本数据,优点是操作简单、无需额外依赖,缺点是不支持结构化查询。

python

运行

# 写入TXT文件
with open("data.txt", "w", encoding="utf-8") as f:
    for item in data_list:
        # 每条数据一行,用分隔符分割字段
        f.write(f"{item['标题']}|{item['链接']}|{item['发布时间']}\n")

# 读取TXT文件
with open("data.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
    for line in lines:
        title, link, date = line.strip().split("|")
        print(title, link, date)

五、爬虫避坑指南与进阶学习路线

5.1 新手必看避坑指南

  1. 法律红线绝对不能碰:严禁爬取个人隐私、涉密数据、付费内容,严禁破解网站防护、DDoS 攻击服务器,否则将承担民事甚至刑事责任;
  2. 优先使用官方 API:如果目标平台提供了官方 API 接口(如天气、电商开放平台),优先使用 API 获取数据,比爬虫更稳定、合规;
  3. 异常处理必须完善:爬虫运行中会遇到网络超时、页面结构变化、反爬拦截等各种问题,必须添加 try-except 异常捕获,避免单条数据错误导致整个程序崩溃;
  4. 先小范围测试,再大规模爬取:先爬取 1-2 页测试解析规则和反爬应对,确认无误后再全量爬取,避免大规模请求后发现规则错误,浪费时间和 IP 资源;
  5. 尊重网站服务器:严格控制请求频率,避免高频并发请求,不要因为爬虫导致网站服务器瘫痪,这既是合规要求,也是程序员的基本素养。
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐