@[toc]

说明:

这次是接着上一次的爬虫:python爬虫之scrapy 框架学习复习整理二
进行补充,上一次是自己对响应的页面,进行分析,查找出下一页的地址,使用requests发送请求,解析方法还是parse函数。

这次使用自动从响应页面提取出需要爬取的地址,然后接着再次爬取,直至,提取的地址都爬取完毕。

自动提取下一页:Scrapy中CrawlSpider

1、再建立一个爬虫程序:

1
scrapy genspide -t crawl scrapyd2 lab.scrapyd.cn

解释下:scrapy genspide -t crawl 是固定格式,后面跟的scrapyd2是程序名字name,后面是允许爬取的域名,后续可以自己增加需要爬取的域名。

执行之后会生成一个scrapyd2.py文件。

在这里插入图片描述
在这里插入图片描述

scrapyd2.py文件模板自动生成格式为:

在这里插入图片描述
在这里插入图片描述

2、Scrapy中CrawlSpider的几个点:

①、CrawlSpider注意点:

在这里插入图片描述

②、LinkExtractor参数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

③、Rule参数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、简单修改下爬虫程序scrapyd2.py

1、正则匹配需要提取的地址:

初步修改的完整代码:

1
# -*- coding: utf-8 -*-
2
import scrapy
3
from scrapy.linkextractors import LinkExtractor
4
from scrapy.spiders import CrawlSpider, Rule
5
6
7
class Scrapyd2Spider(CrawlSpider):
8
    name = 'scrapyd2'
9
    allowed_domains = ['lab.scrapyd.cn']
10
    start_urls = ['http://lab.scrapyd.cn/']
11
12
    rules = (
13
        Rule(LinkExtractor(allow=r'http://lab.scrapyd.cn/page/\d+/',), callback='parse_item', follow=True),
14
    )
15
16
    def parse_item(self, response):
17
        print("进来了",response.url)
18
        item = {}
19
        #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
20
        #item['name'] = response.xpath('//div[@id="name"]').get()
21
        #item['description'] = response.xpath('//div[@id="description"]').get()
22
        return item

可以看到我只是修改可,rule和parse_item方法中的打印输出测试:
allow修改的是一个正则匹配,可以使用正则方法。
然后可以,执行:

1
scrapy crawl scrayd2

然后打印出来:

在这里插入图片描述
在这里插入图片描述

从结果我们可以看出,已经可以提取出翻页的url,并且爬取了翻页的地址。从打印出的翻页地址,可以充分体验出scrapy的爬取是一个异步的,因为我们就这几页的情况下,顺序还是乱序,如果翻页更多的情况下,那么顺序估计更乱。

测试如果正则匹配为空会怎样:

在这里插入图片描述
在这里插入图片描述

结果把所有的都给我匹配到了,只要是允许域名下的地址:

在这里插入图片描述
在这里插入图片描述

2、xpath匹配需求提取的地址:

只是修改了Rule:
经过我测试之后,发现使用xpath提取发现,’//[@id=”main”]//li[@class=”next”]/a’和’//[@id=”main”]//li[@class=”next”]’提取的结果是一样的,也就证实了,rule的规则,会把匹配到的HTML页面里面的所有地址,只要是allowed_domains 域名下的所有地址都会提取出来,作为下一个爬取url,放到url队列进行继续爬取。

1
rules = (
2
       Rule(LinkExtractor(restrict_xpaths=('//*[@id="main"]//li[@class="next"]/a',), ), callback='parse_item', follow=True),
3
       # Rule(LinkExtractor(restrict_xpaths=('//*[@id="main"]//li[@class="next"]',), ), callback='parse_item', follow=True),
4
       # Rule(LinkExtractor(restrict_xpaths=('//*[@id="main"]',), ), callback='parse_item', follow=True),
5
   )

定位到li和a标签,的结果和正则匹配是一样的。

在这里插入图片描述
在这里插入图片描述

处于好奇,我就测试了下,如果定位到href,会怎样,结果报错了。
‘//*[@id=”main”]//li[@class=”next”]/a/@href’

在这里插入图片描述
在这里插入图片描述

报错内容:看了使用xpath最多定位的url的a标签,着上一级的li

在这里插入图片描述
在这里插入图片描述

然后我又尝试了,如果定位到所有li的div会怎样,结果:
‘//*[@id=”main”]’
结果:

在这里插入图片描述
在这里插入图片描述

把div下所有是allowed_domains域名下的url都匹配过来了,所以,这个不精确的提取不建议使用,这些还是只有自己测试之后才会记得牢(当然时间长了也会忘,没事抽时间复习一下还是很有必要的)。

在这里插入图片描述
在这里插入图片描述

3、结论:

通过使用正则和xpath匹配尝试,得到:

  1. 如果使用正则,尽量匹配地址精确点,这样才不会出现页面混乱,不然解析页面是会出问题。
  2. 如果使用xpath匹配,进行精确到a标签,或者a标签的父级(如果父级有很多a标签,其他的a标签有些不符合,还是精确到a标签吧)
  3. 如果使用xpath匹配,不要匹配到href属性,不然还会报错

4、修改parse_item

直接把之前的代码复制过来了,只不过翻页步骤不要了:

1
def parse_item(self, response):
2
       print("进来了",response.url)
3
       # item = {}
4
       # #item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
5
       # #item['name'] = response.xpath('//div[@id="name"]').get()
6
       # #item['description'] = response.xpath('//div[@id="description"]').get()
7
       # return item
8
9
       # 1、提取每一页的数据
10
       div_list = response.xpath('//*[@id="main"]/div[@class="quote post"]')
11
       for div in div_list:
12
           # extract_first() 和 get() 返回的结果是一样的。
13
           text = div.xpath('./span[@class="text"]/text()').get()
14
           # author = div.xpath('.//*[@class="author"]/text()').extract_first()
15
           author = div.xpath('.//*[@class="author"]/text()').get()
16
           url = div.xpath('.//a[contains(text(),"详情")]/@href').get()
17
           # print("div", text, author, url)
18
           item = ScrapydCnItem()
19
           # item = {}
20
           item['text'] = text
21
           item['author'] = author
22
           item['url'] = url
23
           yield item

5、修改下管道储存的数据名称(防止和之前的混淆):

和之前相比:多加了一个2

在这里插入图片描述
在这里插入图片描述

6、运行:scrapy crawl scrayd2:

1
scrapy crawl scrayd2

打印出来的数据:

在这里插入图片描述
在这里插入图片描述

MongoDB保存的数据:

在这里插入图片描述
在这里插入图片描述