如何使用scrapy+splash+Lua滚动爬取CSDN

发布时间:2021-11-09 18:19:24 作者:柒染
来源:亿速云 阅读:306
# 如何使用Scrapy+Splash+Lua滚动爬取CSDN

## 前言

在当今数据驱动的时代,网络爬虫技术成为获取互联网信息的重要手段。对于CSDN这类技术社区,传统的爬虫可能无法有效抓取动态加载的内容。本文将详细介绍如何通过Scrapy+Splash+Lua的组合方案,实现对CSDN页面的滚动爬取,解决JavaScript渲染难题。

## 技术栈介绍

### 1. Scrapy框架
Scrapy是一个用Python编写的开源网络爬虫框架,具有以下特点:
- 高性能的异步处理
- 内置数据提取工具(XPath/CSS选择器)
- 完善的中间件和管道系统
- 可扩展的架构设计

### 2. Splash服务
Splash是一个JavaScript渲染服务,基于Qt WebKit开发,主要功能包括:
- 执行页面中的JavaScript代码
- 模拟鼠标滚动、点击等交互行为
- 返回渲染后的HTML或截图
- 支持Lua脚本控制浏览器行为

### 3. Lua脚本
Lua是一种轻量级脚本语言,在Splash中用于:
- 控制页面加载流程
- 执行复杂的交互操作
- 处理页面等待逻辑
- 返回自定义格式的数据

## 环境搭建

### 1. 安装Scrapy
```bash
pip install scrapy

2. 安装Splash服务

推荐使用Docker快速部署:

docker pull scrapinghub/splash
docker run -p 8050:8050 scrapinghub/splash

3. 安装scrapy-splash中间件

pip install scrapy-splash

4. 配置Scrapy项目

settings.py中添加以下配置:

SPLASH_URL = 'http://localhost:8050'

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

爬虫实现步骤

1. 创建Scrapy项目

scrapy startproject csdn_crawler
cd csdn_crawler
scrapy genspider csdn "csdn.net"

2. 编写Lua滚动脚本

创建scroll.lua文件:

function main(splash, args)
    -- 设置页面加载超时时间
    splash:set_timeout(60)
    
    -- 访问目标URL
    assert(splash:go(args.url))
    
    -- 等待页面初始加载
    splash:wait(2)
    
    -- 获取页面高度并初始化滚动位置
    local scroll_to = splash:jsfunc("window.scrollTo")
    local get_body_height = splash:jsfunc(
        "function() {return document.body.scrollHeight;}"
    )
    
    local scroll_height = get_body_height()
    local scroll_step = 500
    local current_position = 0
    
    -- 模拟滚动操作
    while current_position < scroll_height do
        scroll_to(0, current_position)
        splash:wait(1)  -- 等待内容加载
        current_position = current_position + scroll_step
        
        -- 动态更新页面高度(应对懒加载)
        scroll_height = get_body_height()
    end
    
    -- 最终滚动到底部确保所有内容加载
    scroll_to(0, scroll_height)
    splash:wait(3)
    
    -- 返回渲染后的HTML和截图
    return {
        html = splash:html(),
        png = splash:png(),
        har = splash:har(),
    }
end

3. 编写Scrapy爬虫

修改csdn.py文件:

import scrapy
from scrapy_splash import SplashRequest

class CsdnSpider(scrapy.Spider):
    name = 'csdn'
    allowed_domains = ['csdn.net']
    
    def start_requests(self):
        urls = [
            'https://blog.csdn.net/nav/python',
            'https://blog.csdn.net/nav/ai',
            'https://blog.csdn.net/nav/bigdata'
        ]
        for url in urls:
            yield SplashRequest(
                url,
                self.parse,
                endpoint='execute',
                args={
                    'lua_source': open('scroll.lua').read(),
                    'timeout': 90,
                    'images': 1
                }
            )
    
    def parse(self, response):
        # 提取文章列表
        for article in response.css('article.blog-list-box'):
            yield {
                'title': article.css('h4 a::text').get().strip(),
                'url': article.css('h4 a::attr(href)').get(),
                'author': article.css('.user-name::text').get(),
                'publish_time': article.css('.time::text').get(),
                'read_count': article.css('.read-num::text').get(),
            }
        
        # 分页处理(示例)
        next_page = response.css('.ui-pager a:contains("下一页")::attr(href)').get()
        if next_page:
            yield SplashRequest(
                response.urljoin(next_page),
                self.parse,
                endpoint='execute',
                args={
                    'lua_source': open('scroll.lua').read(),
                    'timeout': 90
                }
            )

4. 数据处理与存储

配置pipelines.py实现数据清洗和存储:

import pymongo

class CsdnPipeline:
    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db
    
    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE')
        )
    
    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]
    
    def close_spider(self, spider):
        self.client.close()
    
    def process_item(self, item, spider):
        # 数据清洗
        if item.get('read_count'):
            item['read_count'] = int(item['read_count'].replace('阅读数:', ''))
        
        # 存储到MongoDB
        self.db['csdn_articles'].update_one(
            {'url': item['url']},
            {'$set': dict(item)},
            upsert=True
        )
        return item

反爬应对策略

1. 请求头设置

settings.py中添加:

DEFAULT_REQUEST_HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept': 'text/html,application/xhtml+xml',
    'Accept-Language': 'zh-CN,zh;q=0.9',
}

2. 下载延迟设置

DOWNLOAD_DELAY = 3
RANDOMIZE_DOWNLOAD_DELAY = True

3. IP代理中间件

推荐使用scrapy-rotating-proxies

ROTATING_PROXY_LIST = [
    'ip1:port',
    'ip2:port',
    # ...
]

部署与优化

1. 分布式扩展

使用scrapy-redis实现分布式爬取:

SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
REDIS_URL = 'redis://localhost:6379'

2. 性能优化技巧

结语

通过Scrapy+Splash+Lua的组合,我们成功实现了对CSDN动态内容的滚动爬取。这种方案不仅适用于CSDN,还可以扩展到其他JavaScript渲染的网站。在实际应用中,请务必遵守网站的robots.txt协议,合理控制爬取频率,避免给目标网站造成过大负担。

注意:本文仅供技术学习参考,请勿用于非法爬取或商业用途。实际应用中应遵守相关法律法规和网站的使用条款。 “`

推荐阅读:
  1. 使用Python怎么爬取知乎图片
  2. 使用python怎么爬取个性签名

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

splash csdn scrapy

上一篇:SourceTree如何轻松使用Git管理项目

下一篇:Django中的unittest应用是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》