实战教学:使用 Scrapy 爬取 CSDN 文章与用户头像

Python爬虫实战:利用Scrapy抓取CSDN博客文章与用户头像

文章目录

⚠️ 教学声明: 本文内容仅用于 Python Scrapy框架的技术学习与研究,旨在展示异步爬虫的核心逻辑与数据清洗方法。请勿利用本文代码进行大规模、高频率的文章爬取,以免给 CSDN服务器造成负担。爬虫开发应遵循 Robots 协议,尊重原创内容版权,抓取到的数据请勿用于任何商业用途。

一、内容与原理

Scrapy 是一个基于 Python 的开源、高性能网络爬虫框架,采用异步 I/O 模型(Twisted)实现高并发数据抓取。其核心架构由五大组件构成:引擎(Engine)调度器(Scheduler)下载器(Downloader)爬虫(Spider)管道(Item Pipeline),各组件通过**中间件(Middleware)**协同工作,形成高效的数据流处理 Pipeline。

在请求处理方面,Scrapy 支持自动 Cookie 管理,默认启用会话状态维持功能,使得多步骤交互(如用户登录)成为可能。同时,通过自定义请求头、请求方法及回调函数链,爬虫可模拟复杂用户行为。

针对 CSDN 这种内容丰富的站点,我们采取两种策略:

  1. CrawlSpider 规则爬取:针对文章详情,利用规则自动提取链接,结合列表页元数据抓取文章内容。
  2. 混合下载策略 :针对图片资源,在 Scrapy 解析过程中结合 requests 库进行流式下载(虽然 Scrapy 有自带的图片管道,但通过 requests 手动控制可以更灵活地演示下载逻辑)。

二、实施过程与结果分析

实验一:CSDN文章全量爬取

1. 项目初始化

首先创建 Scrapy 项目并进入目录:

bash 复制代码
scrapy startproject csdn_spider
cd csdn_spider
2. 爬虫模板生成

生成一个基于 CrawlSpider 的通用爬虫模板,专注于 csdn.net 域名的抓取:

bash 复制代码
scrapy genspider -t crawl csdn_article csdn.net
3. 核心配置 (settings.py)

为了应对 CSDN 的反爬策略并保证数据正常入库,我们需要修改 settings.py

python 复制代码
# 遵守 Robots 协议设为 False,否则无法爬取
ROBOTSTXT_OBEY = False

# 设置下载延迟,避免对服务器造成过大压力
DOWNLOAD_DELAY = 1

# 开启 Cookies (CSDN部分页面可能需要)
COOKIES_ENABLED = True

# 激活数据管道
ITEM_PIPELINES = {
   'csdn_spider.pipelines.CsdnSpiderPipeline': 300,
}
4. 数据模型定义 (items.py)

我们需要明确抓取的数据字段。编辑 items.py

python 复制代码
import scrapy

class CsdnBlogItem(scrapy.Item):
    author_nickname = scrapy.Field()  # 昵称
    author_avatar = scrapy.Field()    # 头像链接
    blog_title = scrapy.Field()       # 博客标题
    blog_url = scrapy.Field()         # 博客链接
    read_count = scrapy.Field()       # 阅读数
    like_count = scrapy.Field()       # 点赞数
    collect_count = scrapy.Field()    # 收藏数
    content = scrapy.Field()          # 文章正文
5. 目标网址分析与策略

通过 F12 开发者工具分析 CSDN 博客首页(https://blog.csdn.net/),我们需要结合**列表页** 和详情页的数据。

字段 提取方式 选择器/表达式 说明
作者昵称 CSS .user-info span::text 列表页获取
文章标题 CSS .article-title::text 列表页获取
阅读/赞/藏 CSS .num::text 列表页清洗获取
文章链接 CSS .article-title::attr(href) 用于自动跟进
文章正文 XPath //div[@id="content_views"]//text() 详情页获取
6. 核心爬虫编写 (csdn_article_spider.py)

我们使用 CrawlSpider,利用 rules 自动发现文章链接,同时使用一个字典 self.article_meta 来在"列表页"和"详情页"之间传递数据(注意:在生产环境中通常推荐使用 meta 参数传递,但此处演示利用类属性缓存的思路)。

关键代码逻辑:

python 复制代码
class CsdnArticleSpider(CrawlSpider):
    name = 'csdn_article'
    allowed_domains = ['csdn.net']
    start_urls = ['https://blog.csdn.net/?spm=1001.2100.3001.4477']

    # 规则:自动提取 /article/details/ 开头的链接,调用 parse_article 解析
    rules = (
        Rule(
            LinkExtractor(allow=r'/article/details/\d+', restrict_css='.article-title'),
            callback='parse_article',
            follow=False
        ),
    )

    def parse_start_url(self, response):
        """ 解析首页:提取元数据并缓存,不生成Item,等待详情页匹配 """
        article_items = response.css('.article-item')
        self.article_meta = {} 
        
        for item in article_items:
            link = item.css('.article-title::attr(href)').get()
            if not link: continue
            full_url = urljoin(response.url, link)
            
            # 提取并清洗统计数据
            stats_texts = item.css('.num::text').getall()
            # ... (省略具体清洗代码,见源码) ...
            
            # 存入缓存
            self.article_meta[full_url] = {
                'author_nickname': item.css('.user-info span::text').get(),
                'blog_title': item.css('.article-title::text').get().strip(),
                # ... 其他字段
            }
        return []

    def parse_article(self, response):
        """ 解析详情页:合并缓存的元数据与正文内容 """
        url = response.url
        item = CsdnBlogItem()
        
        # 从缓存读取列表页信息
        meta = self.article_meta.get(url, {})
        item.update(meta)
        item['blog_url'] = url
        
        # 提取文章正文
        content_parts = response.xpath('//div[@id="content_views"]//text()').getall()
        item['content'] = '\n'.join(part.strip() for part in content_parts if part.strip())[:5000]
        
        yield item
7. 数据清洗与持久化 (pipelines.py)

在 Pipeline 中,我们将数据清洗(去除"阅读"、"点赞"等中文),并保存为 JSON 数组格式。

python 复制代码
class CsdnSpiderPipeline:
    def process_item(self, item, spider):
        adapter = ItemAdapter(item)
        
        # 数据清洗示例:'阅读 1.2k' -> '1.2k'
        read_count = adapter.get('read_count', '')
        if read_count and '阅读' in read_count:
            adapter['read_count'] = read_count.replace('阅读', '').strip()
            
        # ... 点赞、收藏的清洗类似 ...
        
        # 写入 JSON 文件逻辑 (代码略,见源码)
        return item
结果分析

运行爬虫:

bash 复制代码
scrapy crawl csdn_article


执行结果:

  • 状态:成功访问 20+ 个页面,所有请求返回 HTTP 200。
  • 数据 :成功生成 csdn_blogs_日期.json 文件。
  • 内容:JSON 文件中包含了文章的完整元数据(标题、作者、阅读量)以及清洗后的正文内容。

实验二:CSDN 用户头像图片爬取

1. 独立爬虫设计

为了演示文件下载,我们创建一个独立的爬虫 csdn_avatar_spider.py。不同于 Scrapy 自带的 ImagesPipeline,这里我们演示如何在 Spider 内部混合使用 requests 库进行同步下载(适用于小规模资源抓取)。

2. 爬虫实现逻辑
  1. 目录创建 :爬虫启动时自动建立 avatar_images 文件夹。
  2. 链接提取 :解析首页 CSS .user-info img 获取图片 URL。
  3. URL 补全 :处理以 /// 开头的相对路径。
  4. 下载保存 :遍历链接,使用 requests.get 下载二进制数据并写入文件。

关键代码:

python 复制代码
import scrapy
import os
import requests
from urllib.parse import urljoin

class CsdnAvatarSpider(scrapy.Spider):
    name = 'csdn_avatar'
    start_urls = ['https://blog.csdn.net/']

    def parse(self, response):
        image_dir = 'avatar_images'
        os.makedirs(image_dir, exist_ok=True)
        
        avatar_elements = response.css('.user-info img')
        
        for i, img in enumerate(avatar_elements):
            src = img.css('::attr(src)').get()
            if not src: continue

            # URL 补全
            if src.startswith('//'):
                avatar_url = 'https:' + src
            else:
                avatar_url = urljoin(response.url, src)

            # 简单的文件命名
            filename = f"avatar_{i:03d}.jpg"
            filepath = os.path.join(image_dir, filename)

            try:
                # 使用 requests 下载
                headers = {'User-Agent': 'Mozilla/5.0 ...'}
                res = requests.get(avatar_url, headers=headers, timeout=10)
                if res.status_code == 200:
                    with open(filepath, 'wb') as f:
                        f.write(res.content)
                    self.logger.info(f"✅ 已保存: {filename}")
            except Exception as e:
                self.logger.error(f"下载失败: {e}")
结果分析

运行爬虫:

bash 复制代码
scrapy crawl csdn_avatar

执行结果:

  • 控制台输出大量 ✅ 已保存: avatar_xxx.jpg 日志。
  • 检查本地 avatar_images 文件夹,成功下载了当前列表页所有用户的头像图片。
  • 此方法简单直接,但在大规模爬取时建议使用 Scrapy 的异步 ImagesPipeline 以避免阻塞爬虫主线程。

三、总结

本次实战通过 Scrapy 框架完成了对 CSDN 博客的结构化数据与媒体资源抓取。

  1. CrawlSpider 配合 LinkExtractor 极大地简化了翻页和详情页的链接发现逻辑。
  2. Item Pipeline 实现了数据的自动化清洗和 JSON 格式化存储,保证了数据的可用性。
  3. 通过结合 requests 下载图片,展示了 Scrapy 框架的灵活性,能够与 Python 生态中的其他库无缝结合。

🛡️ 开发者合规指南 (极其重要)

在 CSDN 分享爬虫技术时,请务必守住技术底线:

尊重 Robots 协议:在正式环境中应尽量遵循站点的抓取规则。

设置下载延迟:我们在 settings.py 中将 DOWNLOAD_DELAY 设为

1s,这是保护目标服务器、避免触发封禁策略的"温和"做法。

非商业化原则:本教程所有代码及抓取到的数据(如头像、标题等)仅限个人技术研究演示,请务必尊重原创作者的版权。

相关推荐
笨鸟先飞,勤能补拙16 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
长和信泰光伏储能17 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂18 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study18 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境19 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境19 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd12319 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy123931021620 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb0020 小时前
一个项目带你入门AI应用开发01
python
05664620 小时前
Python康复训练——常用标准库
开发语言·python·学习