【愚公系列】《Python网络爬虫从入门到精通》058-自定义分布式爬取诗词排行榜数据

🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟

📣开发者圈持续输出高质量干货的"愚公精神"践行者------全网百万开发者都在追更的顶级技术博主!

👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"挖山不止"的毅力为开发者们搬开知识道路上的重重阻碍!

💎【行业认证·权威头衔】

✔ 华为云天团核心成员:特约编辑/云享专家/开发者专家/产品云测专家

✔ 开发者社区全满贯:CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主

✔ 技术生态共建先锋:横跨鸿蒙、云计算、AI等前沿领域的技术布道者

🏆【荣誉殿堂】

🎖 连续三年蝉联"华为云十佳博主"(2022-2024)

🎖 双冠加冕CSDN"年度博客之星TOP2"(2022&2023)

🎖 十余个技术社区年度杰出贡献奖得主

📚【知识宝库】

覆盖全栈技术矩阵:

◾ 编程语言:.NET/Java/Python/Go/Node...

◾ 移动生态:HarmonyOS/iOS/Android/小程序

◾ 前沿领域:物联网/网络安全/大数据/AI/元宇宙

◾ 游戏开发:Unity3D引擎深度解析

每日更新硬核教程+实战案例,助你打通技术任督二脉!

💌【特别邀请】

正在构建技术人脉圈的你:

👍 如果这篇推文让你收获满满,点击"在看"传递技术火炬

💬 在评论区留下你最想学习的技术方向

⭐ 点击"收藏"建立你的私人知识库

🔔 关注公众号获取独家技术内参

✨与其仰望大神,不如成为大神!关注"愚公搬代码",让坚持的力量带你穿越技术迷雾,见证从量变到质变的奇迹!✨ |

文章目录


🚀前言

在前几篇中,我们已经系统学习了如何搭建分布式爬虫系统,并使用 Scrapy 和 Redis 实现数据的高效抓取与存储。今天,我们将带领大家走进一个更具创意的项目------自定义分布式爬取诗词排行榜数据

诗词文化作为中国传统文化的重要组成部分,一直以来都备受人们喜爱。在互联网上,很多平台会定期发布各类诗词排行榜,展示热门的诗词作品、作者以及相关的评论和评分。通过分布式爬虫抓取这些数据,不仅可以帮助我们了解当下热门的诗词,还能进行更深层次的数据分析与挖掘。

在本篇文章中,我们将从实际需求出发,学习如何自定义一个分布式爬虫,用于爬取诗词排行榜的数据,并实现以下功能:

  1. 分析诗词排行榜网站结构:学习如何解析并提取诗词排行榜中的诗词、作者、评分等信息。
  2. 自定义分布式爬虫:通过 Scrapy 和 Redis 实现分布式任务调度和数据存储,提升爬取效率。
  3. 数据存储与清洗:将抓取到的诗词数据进行存储和清洗,去除冗余信息,确保数据的准确性与完整性。
  4. 多线程与分布式管理:如何利用分布式架构,将任务和数据进行高效的分发和管理。
  5. 深入分析诗词数据:如何对爬取到的诗词数据进行初步的分析,揭示诗词的流行趋势和相关属性。

通过本篇文章的学习,你将能够掌握如何自定义一个分布式爬虫,专门爬取诗词排行榜数据。无论是为了深入了解诗词文化,还是进行数据分析,本篇教程都将为你提供实战经验,帮助你在爬虫项目中取得突破。

🚀一、自定义分布式爬虫:诗词排行榜

使用Scrapy结合Redis实现自定义分布式爬虫,爬取"诗词排行榜"(http://www.shicimingju.com/paiming)的诗词数据。

🔎1.核心步骤

🦋1.1 网页分析

  • 分页规律

    首页地址:http://www.shicimingju.com/paiming

    第N页地址:http://www.shicimingju.com/paiming?p={页码}(页码范围1-100)

  • 数据定位

    • 诗词标题:<h3>标签内文本
    • 作者:<div class="list_num_info">的文本内容
    • 内容:<div class="shici_content>的文本(需处理"展开全文"标签)

🦋1.2 数据库设计

  1. 创建数据库

    • 数据库名:poetry_data
    • 字符集:utf8mb4,排序规则:utf8mb4_0900_ai_ci
  2. 数据表结构

    • 表名:poetry
    • 字段:
      • id (主键,自增)
      • title (标题,VARCHAR 20)
      • author (作者,VARCHAR 10)
      • content (内容,VARCHAR 1000)

🦋1.3 Scrapy项目搭建

  1. 创建项目

    bash 复制代码
    scrapy startproject poetry
    cd poetry
    scrapy genspider poetrySpider shicimingju.com/paiming
  2. 项目结构

    • items.py:定义数据字段
    • middlewares.py:随机请求头中间件
    • pipelines.py:MySQL存储管道
    • settings.py:分布式配置

🦋1.4 核心代码实现

  1. 数据项定义 (items.py)

    python 复制代码
    import scrapy
    
    class PoetryItem(scrapy.Item):
        title = scrapy.Field()   # 保存诗词标题
        author = scrapy.Field()  # 保存诗词作者
        content = scrapy.Field() # 保存诗词内容
        pass
  2. 中间件 (middlewares.py)

    python 复制代码
    from fake_useragent import UserAgent  # 导入请求头类
    # 自定义随机请求头的中间件
    class RandomHeaderMiddleware(object):
        def __init__(self, crawler):
            self.ua = UserAgent()  # 随机请求头对象
            # 如果配置文件中不存在就使用默认的Google Chrome请求头
            self.type = crawler.settings.get("RANDOM_UA_TYPE", "chrome")
    
        @classmethod
        def from_crawler(cls, crawler):
            # 返回cls()实例对象
            return cls(crawler)
    
        # 发送网络请求时调用该方法
        def process_request(self, request, spider):
            # 设置随机生成的请求头
            request.headers.setdefault('User-Agent', getattr(self.ua, self.type))
  3. MySQL存储管道 (pipelines.py)

    python 复制代码
    # -*- coding: utf-8 -*-
    
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
    
    import pymysql            # 导入数据库连接pymysql模块
    class PoetryPipeline(object):
        # 初始化数据库参数
        def __init__(self,host,database,user,password,port):
            self.host = host
            self.database = database
            self.user = user
            self.password = password
            self.port = port
    
        @classmethod
        def from_crawler(cls, crawler):
            # 返回cls()实例对象,其中包含通过crawler获取配置文件中的数据库参数
            return cls(
                host=crawler.settings.get('SQL_HOST'),
                user=crawler.settings.get('SQL_USER'),
                password=crawler.settings.get('SQL_PASSWORD'),
                database=crawler.settings.get('SQL_DATABASE'),
                port=crawler.settings.get('SQL_PORT')
            )
    
        # 打开爬虫时调用
        def open_spider(self, spider):
            # 数据库连接
            self.db = pymysql.connect(host=self.host, user=self.user, password=self.password, database=self.database, port=self.port, charset='utf8')
            self.cursor = self.db.cursor()  # 床架游标
    
        # 关闭爬虫时调用
        def close_spider(self, spider):
            self.db.close()
    
        def process_item(self, item, spider):
            data = dict(item)  # 将item转换成字典类型
            # sql语句
            sql = 'insert into poetry (title,author,content) values(%s,%s,%s)'
            # 执行插入多条数据
            self.cursor.executemany(sql, [(data['title'], data['author'], data['content'])])
            self.db.commit()  # 提交
            return item  # 返回item
  4. 爬虫逻辑 (poetrySpider.py)

    python 复制代码
    # -*- coding: utf-8 -*-
    import scrapy
    
    from poetry.items import PoetryItem    # 导入Item对象
    from redis import Redis                # 导入Redis对象
    import re                               # 导入正则表达式
    class PoetryspiderSpider(scrapy.Spider):
        name = 'poetrySpider'
        allowed_domains = ['shicimingju.com/paiming']
        start_urls = ['http://shicimingju.com/paiming/']
        # 实现网络请求
        def start_requests(self):
            # 创建redis链接对象
            conn = Redis(host='192.168.3.67', port=6379)
            for i in range(1,101):  # 由于诗词排行榜网页共计100页,所以循环执行100次
                # 拼接请求地址
                url = self.start_urls[0].strip('/') + '?p={page}'.format(page=i)
                add = conn.sadd('poetry_url', url)  # 添加请求地址
                if add==1:                          # redis中没有当前url,就发送请求
                    print(url)
                    # 执行请求
                    yield scrapy.Request(url=url, callback=self.parse)
                else:
                    print('第',i,'页请求地址已存在无需请求!')
    
        # 处理请求结果
        def parse(self, response):
            item = PoetryItem()  # 创建item对象
            shici_all=response.css('.card.shici_card')     # 获取每页所有诗词内容
            for shici in shici_all:                       # 循环遍历每页中每个诗词
                title= shici.css('h3 a::text').get()       # 获取诗词标题名称
                author = shici.xpath('./div[@class= "list_num_info"]')\
                    .xpath('string()').get()    # 获取作者
                author = author.strip()         # 删除所有空格
                content = shici.css('.shici_content').xpath('string()').getall()[0]
                if '展开全文'in content:        # 判断诗词内容是否为展开全文模式
                    content=re.sub(' |展开全文|收起|\n','',content)
                else:
                    content = re.sub(' |\n','',content)
                item['title'] = title  # 将诗词标题名称添加至item
                item['author'] = author  # 将诗词作者添加至item
                item['content'] = content  # 将诗词内容添加至item
                yield item  # 打印item信息
            pass
    
    # 导入CrawlerProcess类
    from scrapy.crawler import CrawlerProcess
    # 导入获取项目配置信息
    from scrapy.utils.project import get_project_settings
    
    # 程序入口
    if __name__=='__main__':
        # 创建CrawlerProcess类对象并传入项目设置信息参数
        process = CrawlerProcess(get_project_settings())
        # 设置需要启动的爬虫名称
        process.crawl('poetrySpider')
        # 启动爬虫
        process.start()

🦋1.5 分布式配置 (settings.py)

python 复制代码
BOT_NAME = 'poetry'

SPIDER_MODULES = ['poetry.spiders']
NEWSPIDER_MODULE = 'poetry.spiders'

# Obey robots.txt rules
ROBOTSTXT_OBEY = True
DOWNLOADER_MIDDLEWARES = {
   'poetry.middlewares.PoetryDownloaderMiddleware': 543,
}

# 配置请求头类型为随机,此处还可以设置为ie、firefox以及chrome
RANDOM_UA_TYPE = "random"
ITEM_PIPELINES = {
   'poetry.pipelines.PoetryPipeline': 300,
}

# 配置数据库连接信息
SQL_HOST = '127.0.0.1'      # 数据库地址
SQL_USER = 'root'            # 用户名
SQL_PASSWORD='root'          # 密码
SQL_DATABASE = 'poetry_data'    # 数据库名称
SQL_PORT = 3306              # 端口

🦋1.6 启动分布式爬虫

  1. Redis配置

    • 修改 redis.conf 中的 bind 为服务器IP,并重启服务。
    • 测试远程连接:redis-cli -h [IP] -p 6379
  2. MySQL远程访问

    sql 复制代码
    UPDATE mysql.user SET host='%' WHERE user='root';
    FLUSH PRIVILEGES;
  3. 多节点运行

    • 在多台机器部署代码,修改 settings.py 中的 SQL_HOST 和 Redis连接IP。

    • 同时启动爬虫:

      bash 复制代码
      scrapy crawl poetrySpider

🔎2.效果验证

  1. Redis去重验证

    • 使用 Redis Desktop Manager 查看 poetry_url 集合中的URL去重记录。
  2. MySQL数据验证

    • 执行查询语句 SELECT * FROM poetry;,确认数据完整入库。

🔎3.注意事项

  • IP替换:所有 [你的IP] 需替换为实际服务器地址。
  • 请求头中间件:参考18.3节的 RandomHeaderMiddleware 实现随机User-Agent。
  • 错误处理:添加异常捕获逻辑(如数据库连接失败重试)。
相关推荐
愚公搬代码27 分钟前
【愚公系列】《Python网络爬虫从入门到精通》055-Scrapy_Redis分布式爬虫(安装Redis数据库)
数据库·爬虫·python
浅浅2801 小时前
numpy、pandas内存优化操作整理
数据结构·经验分享·python·学习·性能优化·numpy·pandas
拓端研究室TRL1 小时前
Python+AI提示词比特币数据预测:Logistic逻辑回归、SVC及XGB特征工程优化实践
开发语言·人工智能·python·算法·逻辑回归
就叫飞六吧1 小时前
Python自动化selenium-一直卡着不打开浏览器怎么办?
python·selenium·自动化
亚林瓜子1 小时前
AWS Elastic Beanstalk的部署Python Flask后端服务(Hello,World)
python·flask·aws·eb
weixin_307779131 小时前
实现AWS Step Function安全地请求企业内部API返回数据
开发语言·python·云计算·aws
zhangjipinggom2 小时前
怎么安装python3.5-以及怎么在这个环境下安装包
开发语言·python
格子先生Lab2 小时前
Java反射机制深度解析与应用案例
java·开发语言·python·反射
461K.3 小时前
spark与hadoop的区别
大数据·运维·hadoop·分布式·spark·intellij-idea
Samuel-Gyx3 小时前
2025第十六届蓝桥杯python B组满分题解(详细)
python·职场和发展·蓝桥杯