CrawlSpider

创建项目

  1. # 进入文件夹 cd命令
  2. cd C:\Users\41999\Documents\PycharmProjects\Python\TZSpyder\第六节Scrapy(三)
  3. # 查看命令
  4. scrapy genspider
  5. # 罗列所有模板
  6. scrapy genspider -l
  7. # 选择模板并且创建
  8. scrapy genspider -t crawl zh xxx.com

crawl继承关系.png

Rule讲解

image.png

定义规则

1 爬取URL

2 形成请求

3 响应的处理

方法描述

rule处理响应数据response, Extractor
image.png
follow影响链接的去向

案例实践

对网站的分析

四个主要的网页对象
image.png
2 在书本详情页源码中确认信息是否包含

image.png

3 在目录页面使用调试工具获取章节的URL,将URL复制到详情页的源码中,看是否存在

image.png
确认文章内容是否存在于网页源码,注意使用浏览器中的设置——>开发工具——>其他开发工具

书本中的内容是静态保存的。

  1. 首先选中网络,使用刷新重新获取数据;

  2. 选中列表中第一行网页,选择查看源码

  3. 点击源码,使用快捷键查找书本内容,确认数据

    image.png

章节的URL也在主页面的网页源码中

image.png

除主界面以外,一本书的详情页,详情页中的目录页,目录页中的文本页面依次存在嵌套关系,需要分别获取其URL

这里是查看详情页URL是否存在于主界面的源码当中

image.png

爬取流程

image.png

对主程序的修改

首先设定允许域名和起始域名

image.png

rules规则中,允许的域名

以正则表达式的格式书写,匹配小说的URL
image.png

发现网页有重复,每一个小说详情页面的URL会出现两次,但爬取工具会自动过滤,无需多虑

image.png
image.png

数据交换过程

文字描述:从起始页面开始,将URL交给引擎,引擎交给下载器从而拿到响应,响应返回给RULER
RULER对响应过滤,正则提取子页面URL,此URL提交给引擎,引擎将其提交给下载器获得影响
此响应经RULER中的回调参数传递给parse_item
image.png
第三个参数follow的设置,值为False,否则数据会分别交给parse_item和rule两处

image.png

设置从主页面提取小说详情页URL的处理函数,由RULER中的参数process_links进行转交,下一步是定义转交对象的函数

image.png

设定处理响应中解析到子页面URL的函数

image.png

在settings中关闭机器爬虫规范协议

image.png
默认请求头增加User-Agent

image.png

解决函数报错未果

image.png
process_links对象必须加双引号才能识别数据回传对象
image.png

将子页面网页链接回传,才不会有下面的报错

image.png

仅仅获取一本书的小说详情页URL

image.png

降低下载延时,在settings文件的第二十八行,将三改为一

image.png

分析抓取对象(从小说详情页中找需要哪些元素)

image.png

解析网页,获取小说类别

  1. response.xpath('//div[@class="book-label"]/a/text()').extract()[1]

image.png

提取书名

  1. response.xpath('//div[@class="book-name"]/text()').extract()[0].strip()

作者

  1. response.xpath('//div[@class="au-name"]/a/text()').extract()[0]

更新状态

  1. response.xpath('//div[@class="book-label"]/a/text()').extract()[0]

图书字数

  1. response.xpath('//div[@class="nums"]/span/i/text()').extract()[0]

完整解析函数

  1. def parse_book(self, response):
  2. category = response.xpath('//div[@class="book-label"]/a/text()').extract()[1]
  3. book_name = response.xpath('//div[@class="book-name"]/text()').extract()[0].strip()
  4. author = response.xpath('//div[@class="au-name"]/a/text()').extract()[0]
  5. status = response.xpath('//div[@class="book-label"]/a/text()').extract()[0]
  6. book_nums = response.xpath('//div[@class="nums"]/span/i/text()').extract()[0]
  7. description = ''.join(response.xpath('//div[@class="book-dec Jbook-dec hide"]/p/text()').re("\S+"))
  8. c_time = datetime.datetime.now()
  9. book_url = response.url # 可以拿到请求的URL
  10. catalog_url = response.css("a").re('http://book.zongheng.com/showchapter/\d+.html')[0]
  11. print(category, book_name, author, status, book_nums, description, c_time, book_url, catalog_url)

利用rule函数继续获取目录页这个子级页面

注意!!!
引擎返回的报文,一方面要交给回调参数进行解析处理,一方面由follow的值决定,是否再传递给Rule用于再次提取子页面

1, 首先从主页面开始,用引擎下载及返回报文,交给第一个rule负责匹配

2, 第一个rule匹配到的数据交给parse_book解析,它又会再次拿到URL

3,将这个URL交给引擎下载并且获得响应,将响应交给第二个rule进行正则匹配,这次获得的是目录页的URL
image.png
细节处理

第一个Rule中的follow设置为True,那么响应报文中的URL才会提交给rule

第二个Rule则不需要再次将响应报文返回给rule

第二个Rule中的callback回调对象需要重新设置

image.png

创造第三个Rule,继续匹配章节目录源代码中每一个章节的URL

image.png
目录源码中存放的第二章章节的URL
image.png

主流程已经完成,先逐步完善细节

第一 针对主界面每一本小说文框下最新章节进行限制。因此会对其产生干扰

image.png

从响应提取方法中寻找限制方法

image.png
从源码中找到提取对象的范围

image.png

在第三个rule也就是从全部章节源码中找到一个章节的限制区域,以第一章为例

image.png

总结:
后一个限制解析用来限制前一个提取网页进行的区域范围
image.png

第二,针对第二个Rule,展示全部章节源码进行分析,我们爬取的元素是有序的章节排布,包括章节的URL,以及title

image.png

有序数据的对应

利用列表来存储爬取到的章节URL以及title,这样数据就会变得有序

image.png

第三 针对第三个Rule,也就是第四级页面,确定小说内容存在的位置

image.png

细节处理

获取到章节内容后,还有多余的字符,本人尝试处理一下
image.png
1 将其转换为字符串,使用replace()方法替换,结果不行,因为字符在列表中每一个字符串中
image.png
2 extract()方法也是选择器专用的,无法插手
image.png
3 我尝试自己写一个循环,循环读取数据,取出再返回去,未果,下课后再尝试,先解决进度

老师先将列表转换为字符串拼接,我加了replace()方法之后成功将字符替换为空,但是不怎么美观

image.png

存储结构的规划

image.png

暂时收工,还剩下十四分钟的课程没有学习
**
20210216

对主程序分别新增管道存储结构

  1. def parse_book(self, response):
  2. category = response.xpath('//div[@class="book-label"]/a/text()').extract()[1]
  3. book_name = response.xpath('//div[@class="book-name"]/text()').extract()[0].strip()
  4. author = response.xpath('//div[@class="au-name"]/a/text()').extract()[0]
  5. status = response.xpath('//div[@class="book-label"]/a/text()').extract()[0]
  6. book_nums = response.xpath('//div[@class="nums"]/span/i/text()').extract()[0]
  7. description = ''.join(response.xpath('//div[@class="book-dec Jbook-dec hide"]/p/text()').re("\S+"))
  8. c_time = datetime.datetime.now()
  9. book_url = response.url # 可以拿到请求的URL
  10. catalog_url = response.css("a").re('http://book.zongheng.com/showchapter/\d+.html')[0]
  11. item = NovelItem()
  12. item["category"] = category
  13. item["book_url"] = book_url
  14. item["author"] = author
  15. item["statu"] = status
  16. item["book_nums"] = book_nums
  17. item["description"] = description
  18. item["c_time"] = c_time
  19. item["book_url"] = book_url
  20. item["catalog_url"] = catalog_url
  21. yield item
  1. def parse_catalog(self, response):
  2. a_tags = response.xpath('//ul[@class="chapter-list clearfix"]/li/a')
  3. chapter_list = []
  4. catalog_url = response.url
  5. for a in a_tags:
  6. print("解析catalog_url")
  7. title = a.xpath("./text()").extract()[0]
  8. chapter_url = a.xpath("./@href").extract()[0]
  9. chapter_list.append(title, chapter_url, catalog_url)
  10. item = ChapterItem()
  11. item["chapter_list"] = chapter_list
  12. yield item
  1. def get_content(self, response):
  2. chapter_url = response.url
  3. content = ''.join(response.xpath('//div[@class="content"]/p/text()').extract()).replace("\u3000\u3000", "")
  4. c_time = datetime.datetime.now()
  5. # 向管道传递数据
  6. item = ContentItem()
  7. item["chapter_url"] = chapter_url
  8. item["content"] = content
  9. item["c_time"] = c_time
  10. yield item

在settings中配置MySQL连接

image.png

设置文件目录

image.png

时间有限,还剩下八节课时间,全部章节学完之后再重新扣这一个章节的内容

由于Windows下配置MySQL之困难,我前后花了两个小时左右,上一次凌晨配置也是。以后的项目学习搬到Ubuntu下开始。

所以从下一个章节开始,项目就在Ubuntu操作系统上运行。MySQL配置比较简单。等会儿将整个文件复制过去。

另外学习爬虫的时候,会产生一些业务需求,比如文件的存储和转换。比较典型的,小型数据使用JSON存储。稍微大型的文件使用MySQL存储。

上一次在终端产生的报错,由于程序关闭导致无法重新查看,所以还需要去学习OS模块,看能否将报错信息持久固化到文件当中,便于查找问题。

目前发现的就这几个需求,随着学习的深入,需要掌握的东西肯定是越来越多。所以一般需要什么就重新学习什么。

20210216 | 1952再次梳理代码逻辑

spider拿到数据,将数据交给引擎,引擎拿到数据之后交给管道存储,管道建立了对应结构,同时管道中的结构和items中的结构对应

pipelines中存储的数据,会转存到mysql,转存的工具是模块pymsql。

使用pymysql需要在settings中的设置链接数据库。

几个重要的pymysql命令

1 select insert into 读写

2 commit 提交

3 细节 items分为三类, 第一类是小说 第二类是章节 第三类是具体的文章内容

对知识点的补充:

settings程序中,需要自己先行创建一个数据库

image.png
image.png

本项目还未解决的问题:

MySQL数据表中字段的写入,id需要自增减 章节内容需要设定类型为text

数据之间发生的转交

现在已经是20点19分,还剩下一天的内容没有学习,先去追赶进度

CrawlSpider去重