Scrapy设置之HTTP缓存与离线工作

本文介绍了Scrapy的HTTP缓存功能,包括如何启用缓存策略和选择存储位置。通过设置缓存策略为RFC2616Policy模拟浏览器行为,并在本地文件系统存储响应。在离线环境中,缓存可以加速爬虫运行。同时,展示了如何调整设置以控制缓存大小,以及清理缓存的方法。

Scrapy的HttpCacheMiddleware组件(默认情况下没有启用)提供了一个底层(low-level)的对HTTP请求和响应的缓存。如果启用的话(把HTTPCACHE_ENABLED设置为True),它会缓存每个请求和对应的响应。

这个组件有两个可选项:缓存策略和存储位置。

缓存策略:

  • Dummy policy(默认):这种策略不考虑服务器返回的HTTP Cache-Control指示,它会缓存所有的请求和响应。当遇到相同的请求时,它会直接从缓存中获得响应。要使用这种缓存策略,可以把HTTPCACHE_POLICY设置成scrapy.extensions.httpcache.DummyPolicy
  • RFC2616Policy:这种缓存策略会考虑服务器返回的缓存指令,大概类似于浏览器的行为。可以参考Scrapy文档

存储位置:

  • 用本地文件系统存储(默认):可以设置HTTPCACHE_DIR指定存储的位置。要使用这种方式,需要把HTTPCACHE_STORAGE设置成scrapy.extensions.httpcache.FilesystemCacheStorage。每对请求/响应都会被存储在不同的目录里,里面有一些与此相关的文件(参考Scrapy文档)。目录的名字是由请求对应的fingerprint确定的(scrapy.util
<think>我们正在处理一个关于使用Scrapy爬取笔趣阁小说的问题。用户给出的指令是"scrapy crawl biquge novel content",这看起来像是一个命令行指令,但实际上用户可能是在询问如何使用Scrapy框架来爬取笔趣阁网站的小说内容。 根据提供的引用,我们有三个Scrapy爬取笔趣阁相关的代码示例(引用1、2、3)和一个关于Scrapy框架的简要介绍(引用4)。我们的任务是根据这些引用,构建一个完整的爬虫项目,并解释如何运行它。 步骤: 1. 创建Scrapy项目 2. 定义Item(用于存储小说数据) 3. 编写Spider(解析网页,提取小说内容) 4. 设置Item Pipeline(处理存储) 5. 运行爬虫 但是,用户给出的指令中提到了“biquge”和“novel content”,因此我们需要创建一个名为biquge的spider,并且爬取小说内容。 根据引用3,我们有一个相对完整的示例,它爬取单章小说内容,并通过下一章链接递归爬取整本小说。我们将以此为基础。 具体步骤: 1. 创建Scrapy项目: 在命令行中执行: ``` scrapy startproject biquge cd biquge ``` 2. 定义Item(在items.py中): 根据引用2,我们可以定义三个字段:name(小说名)、author(作者)、content(小说内容)。但是,引用3中使用了title(章节名)和content(章节内容)。考虑到整本小说,我们可能需要存储多个章节,因此我们可以这样设计: - 小说名(name)和作者(author)可以在第一个页面中获取(如小说目录页),然后传递给每一章。 - 每一章我们存储章节标题(title)和内容(content),最后将所有章节合并成整本小说。 但是,由于Scrapy是异步的,我们可能需要将不同章节的内容收集起来,然后在某个点(如最后)合并。另一种做法是每章单独存储,然后离线合并。 为了简单,我们可以先按章节存储,然后通过后续处理合并。这里我们按照引用3的方式,每章生成一个Item,包含章节标题和内容。而整本书的书名和作者可以在Spider的初始化中获取,并传递给每个章节Item。 修改items.py: ```python import scrapy class BiqugeItem(scrapy.Item): # 小说名 novel_name = scrapy.Field() # 作者 author = scrapy.Field() # 章节标题 chapter_title = scrapy.Field() # 章节内容 chapter_content = scrapy.Field() # 章节顺序(可选,用于后续排序) chapter_order = scrapy.Field() ``` 3. 编写Spider: 在spiders目录下创建biquge_spider.py(或类似名称)。 根据引用3,我们使用一个起始URL(小说第一章),然后解析出章节标题、内容,并找到下一章的链接,递归爬取。 但是,我们需要先获取小说名和作者。根据引用1和引用3,我们可以从目录页获取小说名和作者。引用1的起始URL是目录页(`http://www.biquge.info/10_10582/`),引用3的起始URL是第一章(`https://www.bigee.cc/book/6909/1.html`)。我们可以从目录页开始,因为目录页包含小说名、作者和所有章节的链接。 两种策略: - 策略一:从目录页开始,解析小说名、作者,然后提取所有章节链接,然后逐个请求章节页面(使用scrapy.Request)并解析内容。 - 策略二:从第一章开始,然后通过“下一章”链接递归爬取,同时从第一章页面获取小说名和作者(如果第一章页面有的话)。 引用3使用的是策略二(通过下一章链接递归)。但是,如果第一章页面没有小说名和作者,我们就需要调整。 查看引用3的起始URL:`https://www.bigee.cc/book/6909/1.html`,我们可以假设这个页面有小说名和作者吗?在引用3的代码中,它只提取了章节标题和内容,以及下一章链接。所以我们需要修改。 实际上,笔趣阁的不同网站结构可能不同。因此,我们需要根据具体的笔趣阁网站调整。 这里我们采用策略一,因为目录页通常包含完整信息。以引用1的目录页为例。 步骤: - 请求目录页,解析小说名、作者。 - 解析所有章节链接。 - 依次请求每个章节,解析章节标题和内容。 - 在解析章节时,将小说名、作者、章节标题、内容等信息存入Item。 注意:由于章节数量可能很多,我们可能需要限制(比如只爬取前10章作为测试)。 我们以引用1的网站为例(`http://www.biquge.info/10_10582/`)来编写Spider。 创建spider(biquge_spider.py): ```python import scrapy from biquge.items import BiqugeItem class BiqugeSpider(scrapy.Spider): name = 'biquge' allowed_domains = ['www.biquge.info'] start_urls = ['http://www.biquge.info/10_10582/'] # 替换为你要爬的小说的目录页 def parse(self, response): # 解析小说名和作者 novel_name = response.xpath('//div[@id="info"]/h1/text()').get() author = response.xpath('//div[@id="info"]/p[1]/text()').get().replace('作者:', '') # 解析所有章节链接 chapter_links = response.xpath('//div[@id="list"]/dl/dd/a/@href').getall() # 注意:笔趣阁的章节链接可能是相对路径,需要转换为绝对路径 for index, link in enumerate(chapter_links): # 假设链接是相对路径,拼接为绝对URL chapter_url = response.urljoin(link) # 请求章节页面,并传递小说名、作者和章节顺序(index) yield scrapy.Request(chapter_url, callback=self.parse_chapter, meta={'novel_name': novel_name, 'author': author, 'chapter_order': index}) def parse_chapter(self, response): # 从meta中获取小说名、作者和章节顺序 novel_name = response.meta['novel_name'] author = response.meta['author'] chapter_order = response.meta['chapter_order'] # 解析章节标题 chapter_title = response.xpath('//div[@class="bookname"]/h1/text()').get() # 解析章节内容 # 注意:笔趣阁的内容通常在一个id为content的div中,并且可能包含一些干扰字符(如广告) content_list = response.xpath('//div[@id="content"]//text()').getall() # 过滤掉不需要的字符(如空格、广告等) content = ''.join(content_list).strip() # 清理内容:去除广告、换行符等(根据实际情况调整) content = content.replace('\xa0', ' ').replace('<br>', '\n').replace('  ', '\n ') # 创建Item item = BiqugeItem() item['novel_name'] = novel_name item['author'] = author item['chapter_title'] = chapter_title item['chapter_content'] = content item['chapter_order'] = chapter_order yield item ``` 注意:以上代码中的XPath路径需要根据实际网页结构调整。由于笔趣阁网站可能改版或存在多个镜像站点,用户需要根据目标网站的实际HTML调整XPath。 4. 设置Item Pipeline(可选): 如果我们想将数据存储到文件或数据库,可以编写Pipeline。这里我们可以将每章内容存储为文本文件,或者将所有章节存储到一个文件中(注意按章节顺序)。 在pipelines.py中: ```python class BiqugePipeline: # 在开始爬虫时打开一个文件 def open_spider(self, spider): if spider.name == 'biquge': self.file = open('novel.txt', 'w', encoding='utf-8') # 处理每个Item def process_item(self, item, spider): if spider.name == 'biquge': # 将章节标题和内容写入文件 self.file.write(f"{item['chapter_title']}\n\n") self.file.write(item['chapter_content'] + "\n\n") return item # 关闭文件 def close_spider(self, spider): if spider.name == 'biquge': self.file.close() ``` 然后在settings.py中启用Pipeline: ```python ITEM_PIPELINES = { 'biquge.pipelines.BiqugePipeline': 300, } ``` 5. 运行爬虫: 在项目根目录下执行: ``` scrapy crawl biquge ``` 注意:由于我们使用了Pipeline将内容写入文件,运行后会在当前目录生成一个novel.txt文件,包含所有章节。 但是,用户提供的指令是“scrapy crawl biquge novel content”,这可能是用户想运行一个名为“biquge”的爬虫,并且可能希望将内容存储为“novel content”。我们可以解释运行命令后,爬虫会开始工作,并将小说内容存储下来。 另外,考虑到用户可能希望将整本小说存储为一个文件(按章节顺序),我们在Pipeline中按chapter_order排序?但是注意,Scrapy是异步的,章节顺序可能乱序到达。因此,我们需要在Pipeline中缓存所有章节,然后按顺序写入。 修改Pipeline: ```python from collections import defaultdict class BiqugePipeline: def __init__(self): self.chapters = defaultdict(str) # 用字典存储章节内容,键为顺序,值为内容字符串 self.novel_name = None self.author = None def process_item(self, item, spider): if spider.name == 'biquge': # 记录小说名和作者(假设每章都一样,我们只取一次) if self.novel_name is None: self.novel_name = item['novel_name'] self.author = item['author'] # 将章节内容按顺序存入字典 self.chapters[item['chapter_order']] = f"{item['chapter_title']}\n\n{item['chapter_content']}\n\n" return item def close_spider(self, spider): if spider.name == 'biquge': # 按顺序写入文件 with open(f'{self.novel_name}.txt', 'w', encoding='utf-8') as f: # 写入小说名和作者 f.write(f"小说名:{self.novel_name}\n作者:{self.author}\n\n") # 按章节顺序写入 for order in sorted(self.chapters.keys()): f.write(self.chapters[order]) ``` 这样,在爬虫结束时,会按章节顺序将整本小说写入以小说名命名的文件中。 注意:如果章节非常多,可能会占用大量内存。另一种方法是使用临时文件,然后合并。 最后,用户需要根据实际网站调整XPath,因为不同的笔趣阁镜像站点结构可能不同。 总结回答: 1. 创建Scrapy项目并定义Item。 2. 编写Spider,从目录页开始,解析小说名、作者和章节链接,然后请求每个章节页面解析内容。 3. 使用Pipeline将章节按顺序存储到文件中。 4. 运行爬虫命令:`scrapy crawl biquge` 相关问题: 1. 如何调整XPath以适应不同的笔趣阁网站? 2. 如何避免被笔趣阁网站反爬虫? 3. 如何提高爬取速度? 4. 如何将爬取的小说内容存储到数据库(如MongoDB)?</think>### 使用Scrapy爬取笔趣阁小说内容 以下是完整的Scrapy爬虫实现方案,用于爬取笔趣阁网站的小说内容: #### 1. 创建Scrapy项目 ```bash scrapy startproject biquge_crawler cd biquge_crawler ``` #### 2. 定义数据模型(items.py) ```python import scrapy class NovelItem(scrapy.Item): novel_name = scrapy.Field() # 小说名称 author = scrapy.Field() # 作者 chapter_title = scrapy.Field() # 章节标题 chapter_content = scrapy.Field() # 章节内容 chapter_url = scrapy.Field() # 章节链接 ``` #### 3. 编写爬虫(spiders/biquge_spider.py) ```python import scrapy from biquge_crawler.items import NovelItem class BiqugeSpider(scrapy.Spider): name = 'biquge' allowed_domains = ['www.biquge.info'] # 替换为实际小说目录页URL start_urls = ['http://www.biquge.info/10_10582/'] def parse(self, response): # 提取小说基本信息 novel_name = response.xpath('//div[@id="info"]/h1/text()').get() author = response.xpath('//div[@id="info"]/p[1]/text()').get().replace('作者:', '') # 提取所有章节链接 chapter_links = response.xpath('//div[@id="list"]/dl/dd/a/@href').getall() for link in chapter_links[:10]: # 测试前10章 full_url = response.urljoin(link) yield scrapy.Request( full_url, callback=self.parse_chapter, meta={'novel_name': novel_name, 'author': author} ) def parse_chapter(self, response): item = NovelItem() item['novel_name'] = response.meta['novel_name'] item['author'] = response.meta['author'] item['chapter_title'] = response.xpath('//div[@class="bookname"]/h1/text()').get() # 处理章节内容 content_lines = response.xpath('//div[@id="content"]//text()').getall() cleaned_content = '\n'.join( line.strip() for line in content_lines if line.strip() and '笔趣阁' not in line ) item['chapter_content'] = cleaned_content item['chapter_url'] = response.url yield item ``` #### 4. 配置数据存储(pipelines.py) ```python import json class JsonWriterPipeline: def open_spider(self, spider): self.file = open('novel.json', 'w', encoding='utf-8') self.file.write('[\n') self.first_item = True def close_spider(self, spider): self.file.write('\n]') self.file.close() def process_item(self, item, spider): if not self.first_item: self.file.write(',\n') else: self.first_item = False line = json.dumps(dict(item), ensure_ascii=False) self.file.write(' ' + line) return item ``` #### 5. 启用Pipeline(settings.py) ```python ITEM_PIPELINES = { 'biquge_crawler.pipelines.JsonWriterPipeline': 300, } ``` #### 6. 运行爬虫 ```bash scrapy crawl biquge ``` ### 关键点说明 1. **XPath选择器**:使用`response.xpath()`提取小说标题、作者、章节内容和链接 2. **URL拼接**:`response.urljoin()`处理相对URL 3. **内容清洗**:过滤广告文本和空白字符 4. **递归爬取**:通过章节链接实现整本小说爬取 5. **JSON存储**:使用Pipeline将数据保存为结构化JSON文件 ### 注意事项 1. 替换`start_urls`为实际小说目录页URL 2. 遵守网站`robots.txt`规则,添加下载延迟 3. 完整爬取时移除章节限制`[:10]` 4. 可添加代理中间件防止IP被封 > 提示:实际使用时需根据目标网站结构调整XPath选择器[^1][^3]。Scrapy框架的异步处理机制能有效提升爬取效率[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值