scrapy爬取数据的基本流程及url地址拼接

本文详细介绍Scrapy爬虫框架的基础使用,包括项目创建、爬虫编写、数据提取及URL拼接技巧。涵盖异步与非阻塞概念,以及如何通过yield传递数据,使用response.follow和response.urljoin构造请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:初学者,整理后方便能及时完善,冗余之处请多提建议,感谢!
 
了解内容:
Scrapy :抓取数据的爬虫框架
 
 
异步与非阻塞的区别
 
异步:指的是整个过程,中间如果是非阻塞的,那就是异步过程;
非阻塞:关注拿到结果之前的状态 (如果拿到结果前在等待,是阻塞,反之,是非阻塞)
 
 
理解:
Scrapy 基本工作流程(简单--->复杂)
                            

            
                 每个模块间不通讯,模块之间通过引擎进行数据传输

 

 
   
 基本使用
 
一、创建spider
 
scrapy项目流程
---创建项目
    ---scrapy startproject  xxxx
---创建爬虫
    ---cd 项目目录下
    ---scrapy genspider   aaa    allowed_domains"”
        scrapy genspider  first_spider   jpdd.com
      first_spider   爬虫名字
      jpdd.com     限制爬取数据的范围
--完善spider
    ---提取数据,提取url地址构成request对象
        xpath  extract_first()\extract()   response.meta      yield  scrapy.Requeest       
--完善管道 
--运行爬虫
    --- cd  项目目录   
    ---scrapy  crawl   first_spider
 
注意:避免爬虫名和项目名重复 ;
           不管在终端还是pycharm 都要切换到当前目录下 cd myspider
            allowed_domains : 限定爬取的范围
           
二、完善spider 
 
    ----  对数据的提取
    1、 Scray 中的parse 做什么用途? 
            ---处理start_urls 中的url地址的响应
 
    2 、yiele 生成器的使用
             好处:遍历函数的返回值的时候,挨个把数据读到内存,不会造成内存的瞬间占用过高
             通过yield传递数据给管道,(类似转发)
             yield能够传递的对象只能是:BaseItem, Request, dict, None
    
    3 、使用.extract()把response.xpath()提取的数据转化为字符串列表
            .extract()    返回一个含有字符串的列表,没有返回空列表
            .extract_first()   提取列表中的第一个字符串,如果不存在,返回None
 
----例:
yield的使用:使用多个yield 来传递需要的数据
 

 

  
 
 
 
 
 
 
         
 

上面的代码应该改成:yield item

 
4、 根据Response返回的url地址,对next_url的url地址进行拼接,构造请求,有5种方式
 
        第1种:手动字符串相加
        第2种:urllib.parse.urljoin(baseurl,url)  后面的url会根据baseurl进行url地址的拼接
        第3种:response.follow(url ,callback)   能够根据response的地址把url拼接完整,构造成Request对象,
                                                                      但这个方法在python 1.0后的版本中才有
        第4种( 推荐):response.urljoin(next_url)     更简洁、好用
        第5种:scrapy.Request(url,callback,meta,dont_filter)
 
---例:
# 第一种:手动拼接下一页url
 
#主站链接 用来拼接
    base_site = 'https://www.jpdd.com'

def parse(self,response):
    book_urls = response.xpath('//table[@class="p-list"]//a/@href').extract()

    for book_url in book_urls:
         url = self.base_site + book_url
         yield scrapy.Request(url, callback=self.getInfo)    

    #获取下一页
    next_page_url = self.base_site + response.xpath(
            '//table[@class="p-name"]//a[contains(text(),"下一页")]/@href'
            ).extract()[0]

    yield scrapy.Request(next_page_url, callback=self.parse)
 
使用urllib实现url地址拼接的原理:
        

 

        
 
 
 
 

 

三、完善管道 
       
  管道的设置也是以键值的形式
 
      

 

 
 
 
 
 
 
 
数据保存:可以是具体的item,也可以保存在文件中,如下2种方式
 
 第一种:
        
     
 
 
 
 
 
 
 
 
 
 
 
第二种:

  ------数字越小,表示离引擎越近,数据越先经过处理,反之 。

  -------使用多个管道时,前面的管道中要记得return  xx  不然后面的管道接收不到前面的数据,会返回none
 
四、item的使用
        
         为什么要单独定义item?
            定义item即提前规划好哪些字段需要抓取,scrapy.Field()仅仅是提前占坑,通过item.py能够让别人清楚自己的爬虫是在抓取什么数据;
       同时来提示哪些字段是需要抓取的,没有定义的字段不能使用,防止手误;
    item不能直接存入mongodb中,需要转化为字典后再存储。
 
      Item使用之前需要先导入并且实例化,之后的使用方法和使用字典相同
    from yanguan.items import YanguanItem
    item = YanguanItem() #实例化

  

补充:
构造翻页请求
        meta 自身是个字典
          Scrapy.Request() ===>相当于构造了一个requests对象
 
scrapy.Request(url[,callback,method="GET",headers,body,cookies,meta,dont_filter=False])

参数说明:
括号中的参数为可选参数
callback:表示当前的url的响应交给哪个函数去处理
meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
dont_filter:默认会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动

 
        
 
 

 

转载于:https://www.cnblogs.com/littlehappycode/p/10996203.html

<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、付费专栏及课程。

余额充值