Scrapy框架之CrawlSpider爬虫 实战 详解

CrawlSpiderScrapy 框架中一个非常实用的爬虫基类,它继承自 Spider

类,主要用于实现基于规则的网页爬取。相较于普通的 Spider 类,CrawlSpider

可以根据预定义的规则自动跟进页面中的链接,从而实现更高效、更灵活的爬取。

Scrapy 创建CrawlSpider爬虫

目标网址:http://quotes.toscrape.com/

目标:匹配top10标签里面的所有quote

观察其他的URL链接,这些都是干扰,我们只需要匹配top10里面的链接,所有需要编写正则表达式来匹配

1.创建 Scrapy 项目 :在命令行输入scrapy startproject myproject,这里的myproject是项目名。

2.进入项目目录 :输入cd myproject
3.创建 CrawlSpider :输入scrapy genspider -t crawl myspider example.commyspider是爬虫名,example.com是初始爬取的域名。

python 复制代码
scrapy genspider -t crawl quotes quotes.toscrape.com
python 复制代码
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class QuotesSpider(CrawlSpider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ["http://quotes.toscrape.com/"]

    rules = (
        Rule(LinkExtractor(allow=r'/tag/[a-z]+/$'), callback='parse_tag', follow=False),
    )

    def parse_tag(self, response):
        tag_url = response.url
        print(f"Extracted tag URL: {tag_url}")
  • rules:是一个元组,包含一个或多个 Rule 对象,每个 Rule 对象定义了一个爬取规则。
  • LinkExtractor(allow=r'/tag/[a-z]+/$'):创建一个 LinkExtractor 对象,使用正则表达式 r'/tag/[a-z]+/$' 来提取符合规则的链接。该正则表达式的含义是:匹配含/tag/的链接,后面跟着一个或多个小写字母,最后以 / 结尾的链接。
  • callback='parse_tag':当 LinkExtractor 提取到符合规则的链接并访问该链接对应的页面后,会调用 parse_tag 方法来处理该页面。
  • follow=False:表示不跟进从当前页面提取的符合规则的链接。也就是说,爬虫只会处理当前页面中符合规则的链接,不会继续深入这些链接对应的页面去提取更多链接。(会自动访问符合规则的链接)

    可以看到爬取的就是top10的

相对 URL 和绝对 URL 的差异 : Scrapy 的 LinkExtractor 在处理链接时,处理的是绝对 URL 而非 HTML 中的相对 URL。要是你的正则表达式是基于相对 URL 来写的,就可能会匹配失败。比如,HTML 里的相对 URL 是/tag/inspirational/,但 Scrapy 处理时会把它变成绝对 URL http://quotes.toscrape.com/tag/inspirational/

因此 r'^/tag/[a-z]+/$' 就无法匹配,因为绝对 URL 是以 http:// 开头的,并非 /tag/

或者改为这样也是可以的 r'^http://quotes.toscrape.com/tag/[a-z]+/$'

接下来我们继续跟进,将follow=True。进入这些标签页面进一步爬取详情内容

python 复制代码
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class QuotesSpider(CrawlSpider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ["http://quotes.toscrape.com/"]

    rules = (
        Rule(LinkExtractor(allow=r'/tag/[a-z]+/$'), callback='parse_tag', follow=True),
    )

    def parse_tag(self, response):
        # 打印当前页面的URL
        tag_url = response.url
        print(f"Extracted tag URL: {tag_url}")

        # 提取名言和作者
        quotes = response.css('div.quote')
        for quote in quotes:
            text = quote.css('span.text::text').get()
            author = quote.css('small.author::text').get()
            print(f"Quote: {text}, Author: {author}")

翻页逻辑

有的标签类别不止一页数据,例如

python 复制代码
http://quotes.toscrape.com/tag/love/page/2/

可以看到我们只需要匹配next里面链接,其他的为干扰。我们可以使用更精确的 CSS 选择器来配合 LinkExtractor

python 复制代码
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class QuotesSpider(CrawlSpider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ["http://quotes.toscrape.com/"]

    rules = (
        # 规则1:提取所有标签链接
        Rule(LinkExtractor(allow=r'/tag/[a-z]+/$'), callback='parse_tag', follow=True),

        # 规则2:使用CSS选择器提取<li>标签下的分页链接
        Rule(LinkExtractor(restrict_css='li.next a'), callback='parse_tag', follow=True),

    )


    def parse_tag(self, response):
        # 打印当前页面的URL
        tag_url = response.url
        print(f"Extracted tag URL: {tag_url}")

        # 提取名言和作者
        quotes = response.css('div.quote')
        for quote in quotes:
            text = quote.css('span.text::text').get()
            author = quote.css('small.author::text').get()
            print(f"Quote: {text}, Author: {author}")

如果 Rule(LinkExtractor(restrict_css='li.next a'), callback='parse_tag', follow=False)

那么爬虫只会处理当前页面中提取到的分页链接对应的页面,而不会进一步去跟进这些页面中的其他分页链接,所以只能获取到第二页的数据,无法获取到第二页之后的页面数据。

还可以使用 XPath 提取

python 复制代码
    rules = (
        # 规则1:提取所有标签链接
        Rule(LinkExtractor(allow=r'/tag/[a-z]+/$'), callback='parse_tag', follow=True),

        # 规则2:使用CSS选择器提取<li>标签下的分页链接
        Rule(LinkExtractor(restrict_css='li.next a'), callback='parse_tag', follow=True),

        # 规则3:使用XPath提取<li>标签下的分页链接
        Rule(LinkExtractor(restrict_xpaths='//li[@class="next"]/a'), callback='parse_tag', follow=True),

    )

Scrapy 内部有一个链接去重机制,默认使用 scrapy.dupefilters.RFPDupeFilter 来过滤重复的请求。当 LinkExtractor 提取到链接后,Scrapy 会先检查这个链接是否已经在请求队列中或者已经被处理过,如果是,就不会再次发起请求。

规则 2 和规则 3 提取的是相同的,由于 Scrapy 的去重机制,相同的链接只会被请求和处理一次,所以不会因为规则 2 和规则 3 提取到相同的链接而导致 parse_tag 方法被重复调用并打印两次数据。

虽然 Scrapy 会对链接进行去重,但如果你的 parse_tag 方法内部存在一些逻辑,可能会导致数据重复处理。例如,如果你在 parse_tag 方法中对数据进行了一些存储操作,并且没有进行去重处理,那么可能会出现数据重复存储的情况

LinkExtractor allow参数

  • 字符串列表allow=['/tag/love/', '/tag/humor/']LinkExtractor 会提取包含 /tag/love/ 或者 /tag/humor/ 的链接

  • 编译好的正则表达式对象

    python 复制代码
    tag_pattern = re.compile(r'/tag/[a-z]+/$')
    rules = (
        Rule(LinkExtractor(allow=tag_pattern), callback='parse_item', follow=True),
    )
  • 空列表或空字符串 :如果你传入一个空列表 [] 或者空字符串 ''LinkExtractor 会提取页面中的所有链接。

相关推荐
Python大数据分析@6 小时前
CLI一键采集,使用Python搭建TikTok电商爬虫Agent
开发语言·爬虫·python
编程隐士6 小时前
爬虫管理系统实现方案
爬虫
跨境数据猎手8 小时前
1688 商品铺货到独立站实操(附工具 + 代码)
大数据·爬虫·软件构建
_.Switch1 天前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
码界奇点1 天前
基于Python的新浪微博数据爬虫系统设计与实现
数据库·爬虫·python·毕业设计·新浪微博·源代码管理
tang777891 天前
代理IP质量检测实战:Python实现IP可用性、延迟、匿名度自动测试脚本
大数据·爬虫·python·网络协议·tcp/ip
datascome2 天前
文章自动采集发布到Discuz网站技巧
经验分享·爬虫·数据采集·discuz·网站内容批量发布
亿牛云爬虫专家2 天前
Go爬虫进阶:如何优雅地在Colly框架中实现无缝代理切换?
爬虫·中间件·golang·爬虫代理·colly框架·代理切换·api提取
小白学大数据3 天前
Python 3.7 高并发爬虫:接口请求与页面解析并发处理
开发语言·爬虫·python
深蓝电商API3 天前
淘宝商品主图视频下载:从 API 返回值中提取视频 URL 并转码
爬虫·接口·api·淘宝api