睿诚科技协会

Python 3网络爬虫如何快速入门?

网络爬虫(Web Crawler / Spider)是一个按照一定规则,自动地抓取万维网信息的程序或脚本,Python 凭借其简洁的语法和强大的库生态系统,成为了编写网络爬虫的首选语言。

Python 3网络爬虫如何快速入门?-图1
(图片来源网络,侵删)

本指南将分为以下几个部分:

  1. 爬虫基本原理
  2. 核心库介绍
  3. 实战案例:从简单到复杂
  4. 爬虫进阶
  5. 爬虫的“道德”与法律
  6. 总结与学习路径

爬虫基本原理

一个典型的爬虫工作流程如下:

  1. 发起请求:爬虫模拟浏览器向目标网站的某个 URL(网址)发送一个 HTTP 请求。
  2. 获取响应:服务器收到请求后,会返回一个 HTTP 响应,这个响应中包含了网页的源代码(HTML)、状态码、响应头等信息。
  3. :爬虫从响应内容(通常是 HTML)中提取出需要的数据,这就像用一把“剪刀”从一本杂志上剪下你需要的文章和图片。
  4. 存储数据:将提取出的数据保存到本地文件(如 CSV, TXT)或数据库中,以便后续分析使用。
  5. 发现新链接:从当前解析的页面中提取出新的 URL,将这些 URL 放入一个待抓取的队列中,然后循环执行步骤 1,直到满足停止条件(如抓取足够多的页面或队列已空)。

模拟 vs 真实浏览器

  • 无头浏览器:爬虫直接向服务器请求 HTML 文件,速度快,但无法执行 JavaScript。
  • 真实浏览器:爬虫通过 Selenium 等工具控制一个真实的浏览器(如 Chrome),可以执行 JavaScript,速度慢,但能获取到动态加载的内容。

核心库介绍

Python 爬虫生态非常成熟,下面是几个最核心的库:

Python 3网络爬虫如何快速入门?-图2
(图片来源网络,侵删)
库名称 主要功能 适用场景 优点 缺点
requests 发送 HTTP 请求 基础中的基础,几乎所有爬虫都会用到 API 极其简洁,易用 无法执行 JavaScript
BeautifulSoup 解析 HTML/XML requests 获取的页面源码中提取数据 语法简单,容错性强,支持多种解析器 依赖 requests 或其他请求库
lxml 解析 HTML/XML 性能要求高的场景 速度快,功能强大 API 相对复杂,容错性不如 BS
Selenium 自动化浏览器 抓取由 JavaScript 动态渲染的页面 能模拟真实用户操作,JS 渲染无压力 速度慢,依赖浏览器驱动
Scrapy 框架 构建大型、复杂、高性能的爬虫项目 功能全面(异步下载、管道、调度器等) 学习曲线较陡,不适合小型项目
aiohttp 异步 HTTP 客户端 高并发、高性能爬虫 基于异步 asyncio,效率极高 需要异步编程思维

实战案例:从简单到复杂

我们将通过三个逐步深入的案例来掌握爬虫的编写。

静态网页数据抓取(requests + BeautifulSoup

目标:抓取豆瓣电影 Top 250 的电影名称、评分和一句话评价。

目标网址https://movie.douban.com/top250

步骤

Python 3网络爬虫如何快速入门?-图3
(图片来源网络,侵删)
  1. 安装库

    pip install requests beautifulsoup4 lxml
  2. 编写代码

    import requests
    from bs4 import BeautifulSoup
    import csv
    # 1. 发起请求
    url = 'https://movie.douban.com/top250'
    # 设置请求头,模拟浏览器访问
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
    }
    try:
        response = requests.get(url, headers=headers, timeout=10)
        # 确保请求成功
        response.raise_for_status() 
        # 2. 获取响应内容 (HTML)
        html = response.text
    except requests.RequestException as e:
        print(f"请求失败: {e}")
        exit()
    # 3. 解析内容
    soup = BeautifulSoup(html, 'lxml') # 使用 lxml 解析器,需要安装 lxml
    # 找到所有包含电影信息的 <ol class="grid_view"> 下的 <li>
    movie_list = soup.find_all('li', class_='item')
    # 创建一个列表来存储所有电影数据
    all_movies_data = []
    for movie in movie_list:
        # 提取电影名称
        title = movie.find('span', class_='title').text
        # 提取评分
        score = movie.find('span', class_='rating_num').text
        # 提取一句话评价
        quote = movie.find('span', class_='inq')
        quote_text = quote.text if quote else '无' # 处理可能为空的情况
        all_movies_data.append([title, score, quote_text])
        print(f"正在抓取: {title}, 评分: {score}")
    # 4. 存储数据 (保存到 CSV 文件)
    with open('douban_top250.csv', 'w', newline='', encoding='utf-8-sig') as f:
        writer = csv.writer(f)
        writer.writerow(['电影名称', '评分', '一句话评价']) # 写入表头
        writer.writerows(all_movies_data) # 写入所有数据
    print("\n数据已成功保存到 douban_top250.csv")

代码解析

  • headers:用于伪装成浏览器,防止被网站识别为爬虫。
  • requests.get():发送 GET 请求。
  • response.raise_for_status():如果请求返回的状态码不是 200(成功),则会抛出异常。
  • BeautifulSoup(html, 'lxml'):创建一个 BeautifulSoup 对象,将 HTML 文档解析成树形结构。
  • soup.find_all():查找所有符合条件的标签,返回一个列表。
  • find()text:查找单个标签并获取其内部的文本内容。
  • csv.writer:将数据写入 CSV 文件,utf-8-sig 编码可以避免 Excel 打开中文乱码。

处理分页与动态内容(Selenium

目标:抓取知乎某个话题下所有回答的作者和赞同数,知乎的内容是动态加载的,requests 无法直接获取。

目标网址:知乎话题页(https://www.zhihu.com/topic/19552769/hot

步骤

  1. 安装库

    pip install selenium
  2. 下载浏览器驱动

    • 访问 ChromeDriver for Testing 下载与你 Chrome 浏览器版本匹配的 chromedriver
    • 将下载的 chromedriver.exe (Windows) 或 chromedriver (Mac/Linux) 放到你的 Python 脚本同目录下,或者将其路径添加到系统环境变量中。
  3. 编写代码

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    import time
    # 1. 配置 Selenium WebDriver
    # 如果你把 chromedriver 放在了脚本同目录下,可以这样写
    service = Service(executable_path='chromedriver.exe') 
    driver = webdriver.Chrome(service=service)
    url = 'https://www.zhihu.com/topic/19552769/hot'
    driver.get(url)
    # 2. 处理动态加载
    # 模拟点击“加载更多”按钮,直到没有新内容
    while True:
        try:
            # 等待“加载更多”按钮出现并点击
            load_more_button = WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable((By.XPATH, '//button[@class="Button.Button--primary.Button--plain"]'))
            )
            load_more_button.click()
            print("点击了“加载更多”...")
            time.sleep(2) # 等待新内容加载
        except Exception as e:
            print("没有更多内容了或出现其他错误:", e)
            break
    # 3. 解析内容
    # 等待所有回答加载完成
    WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '.ContentItem.AnswerItem'))
    )
    answers = driver.find_elements(By.CSS_SELECTOR, '.ContentItem.AnswerItem')
    for answer in answers:
        try:
            # 作者
            author = answer.find_element(By.CSS_SELECTOR, '.AuthorInfo-name').text
            # 赞同数
            votes = answer.find_element(By.CSS_SELECTOR, '.VoteButton--up').text
            print(f"作者: {author}, 赞同: {votes}")
        except Exception as e:
            print(f"解析单个回答时出错: {e}")
            continue
    # 4. 关闭浏览器
    driver.quit()

代码解析

  • webdriver.Chrome():启动一个 Chrome 浏览器实例。
  • WebDriverWait:显式等待,比 time.sleep() 更智能,它会等待某个条件(如元素可点击、元素出现)满足后再执行下一步。
  • EC.element_to_be_clickable:等待元素可被点击。
  • driver.find_elements():查找所有匹配的元素,返回一个列表。
  • driver.quit():关闭浏览器并释放资源。

使用框架(Scrapy

目标:使用 Scrapy 框架重构案例一,实现更高效、更结构化的爬虫。

步骤

  1. 安装 Scrapy

    pip install scrapy
  2. 创建项目

    scrapy startproject douban_movie
    cd douban_movie
    scrapy genspider top250 movie.douban.com

    这会创建一个项目结构,并自动生成一个名为 top250 的爬虫文件。

  3. 项目结构

    douban_movie/
    ├── scrapy.cfg          # 部署配置文件
    └── douban_movie/       # 项目 Python 模块
        ├── __init__.py
        ├── items.py        # 定义要抓取的数据结构
        ├── middlewares.py  # 中间件
        ├── pipelines.py    # 数据处理管道
        ├── settings.py     # 爬虫设置
        └── spiders/        # 爬虫目录
            ├── __init__.py
            └── top250.py    # 我们将在这里编写爬虫逻辑
  4. 修改 items.py:定义我们要抓取的数据字段。

    # douban_movie/items.py
    import scrapy
    class DoubanMovieItem(scrapy.Item):
        title = scrapy.Field()
        score = scrapy.Field()
        quote = scrapy.Field()
  5. 修改 spiders/top250.py:编写爬虫核心逻辑。

    # douban_movie/spiders/top250.py
    import scrapy
    from ..items import DoubanMovieItem
    class Top250Spider(scrapy.Spider):
        name = 'top250'
        allowed_domains = ['movie.douban.com']
        start_urls = ['https://movie.douban.com/top250']
        def parse(self, response):
            # 找到所有电影条目
            movie_list = response.css('ol.grid_view li.item')
            for movie in movie_list:
                # 创建一个 Item 对象
                item = DoubanMovieItem()
                # 使用 CSS 选择器提取数据
                item['title'] = movie.css('span.title::text').get()
                item['score'] = movie.css('span.rating_num::text').get()
                item['quote'] = movie.css('span.inq::text').get()
                # 将 item 交给引擎,进入处理管道
                yield item
            # 处理分页
            next_page = response.css('a.next::attr(href)').get()
            if next_page is not None:
                # 构造下一页的完整 URL 并继续爬取
                yield response.follow(next_page, self.parse)
  6. 修改 pipelines.py:配置数据存储。

    # douban_movie/pipelines.py
    import csv
    class DoubanMoviePipeline:
        def open_spider(self, spider):
            # 爬虫启动时打开文件
            self.f = open('douban_top250_scrapy.csv', 'w', newline='', encoding='utf-8-sig')
            self.writer = csv.DictWriter(self.f, fieldnames=['title', 'score', 'quote'])
            self.writer.writeheader()
        def close_spider(self, spider):
            # 爬虫结束时关闭文件
            self.f.close()
        def process_item(self, item, spider):
            # 处理每个 item,写入文件
            self.writer.writerow(item)
            return item
  7. 修改 settings.py:开启管道。

    # douban_movie/settings.py
    # ... (其他设置)
    ITEM_PIPELINES = {
       'douban_movie.pipelines.DoubanMoviePipeline': 300,
    }
  8. 运行爬虫

    scrapy crawl top250

Scrapy 优势

  • 异步下载:Scrapy 使用 Twisted 库实现异步 I/O,可以同时发起多个请求,速度极快。
  • 管道:数据流经多个处理管道,可以方便地进行清洗、去重、存储等操作。
  • 调度器:自动管理请求队列和去重。
  • 可扩展性:支持中间件、扩展等,功能强大。

爬虫进阶

  • 反爬虫对策

    • User-Agent 池:随机更换 User-Agent
    • IP 代理:使用代理 IP 池来避免因请求频率过高而被封禁 IP。
    • 验证码:使用 OCR 库(如 pytesseract)或第三方打码平台。
    • 动态渲染:使用 SeleniumPyppeteer(无头 Chrome)。
    • 登录:模拟登录,维持 Session
  • 数据存储

    • 关系型数据库:MySQL, PostgreSQL,适合结构化数据。
    • 非关系型数据库:MongoDB, Redis,适合半结构化和海量数据。
    • 云存储:AWS S3, Google Cloud Storage。
  • 部署与调度

    • Scrapy-Redis:基于 Scrapy 和 Redis 的分布式爬虫框架。
    • Celery:一个强大的分布式任务队列,可以用来定时调度爬虫任务。

爬虫的“道德”与法律

爬虫技术是中性的,但使用它必须遵守法律法规和网站的 robots.txt 协议。

  1. robots.txt:这是一个放在网站根目录下的文本文件,规定了哪些页面可以爬取,哪些不可以,在爬取一个网站前,务必先查看其 robots.txthttps://www.douban.com/robots.txt)。
  2. 尊重网站资源
    • 设置合理的请求间隔:使用 time.sleep()scrapyDOWNLOAD_DELAY 设置,避免对服务器造成过大压力。
    • 不要频繁请求:避免短时间内大量请求同一页面。
  3. 数据使用:抓取的数据仅用于个人学习或研究,不得用于商业用途或侵犯他人隐私。
  4. 版权:尊重网站的版权声明。

总结与学习路径

  1. 入门阶段

    • 核心库requests + BeautifulSoup
    • 目标:能够抓取静态网页,提取数据并保存到本地文件。
    • 实践:从豆瓣、知乎等简单网站开始。
  2. 进阶阶段

    • 核心库/框架Selenium + Scrapy
    • 目标:能够处理动态加载的页面,并使用框架构建稳定、高效的爬虫。
    • 实践:尝试爬取更复杂的电商、社交媒体网站,学习使用数据库存储数据。
  3. 高级阶段

    • 技术点:分布式爬虫、反反爬策略、数据清洗与分析、部署。
    • 目标:构建企业级、高可用的数据采集系统。
    • 实践:学习 Scrapy-Redis,研究 IP 代理池,学习使用 Docker 进行部署。

网络爬虫是一个实践性极强的领域,最好的学习方式就是动手去做,从简单的项目开始,逐步挑战更复杂的网站,你很快就能成为一名合格的爬虫工程师,祝你学习愉快!

分享:
扫描分享到社交APP
上一篇
下一篇