18--Scrapy04:CrawlSpider、链接提取器、源码模板文件

Scrapy04--CrawlSpider、链接提取器、源码模板文件

案例:汽车之家,全站抓取二手车的信息 来区分SpiderCrawlSpider

注意:汽车之家的访问频率 要控制一下, 要不然会跳验证

settings.py 中设置 DOWNLOAD_DELAY = 3

一、常规Spider

# spiders/Ershou.py
import scrapy
from scrapy.linkextractors import LinkExtractor

class ErshouSpider(scrapy.Spider):
    name = 'ershou'
    allowed_domains = ['che168.com']
    start_urls = ['https://www.che168.com/china/a0_0msdgscncgpi1ltocsp1exx0/']

    def parse(self, resp, **kwargs):
        # print(resp.text)
        # 链接提取器:详情页
        le = LinkExtractor(restrict_xpaths=("//ul[@class='viewlist_ul']/li/a",), deny_domains=("topicm.che168.com",) )
        links = le.extract_links(resp)
        
        for link in links:
            yield scrapy.Request(
                url=link.url,
                callback=self.parse_detail
            )
            
        # 链接提取器:翻页
        le2 = LinkExtractor(restrict_xpaths=("//div[@id='listpagination']/a",))
        pages = le2.extract_links(resp)
        for page in pages:
            yield scrapy.Request(url=page.url, callback=self.parse)

    def parse_detail(self, resp, **kwargs):
        title = resp.xpath('/html/body/div[5]/div[2]/h3/text()').extract_first()
        print(title)

1.1 链接提取器

LinkExtractor:链接提取器 类,可以非常方便从一个响应页面中,提取到url链接,只需要提前定义好规则即可.

### 1 构建 链接提取器类的 对象
from scrapy.linkextractors import LinkExtractor

le = LinkExtractor(参数)  # 参数值 都是元祖形式
    allow    # 接收一堆正则表达式, 提取出符合该正则的链接
    deny     # 接收一堆正则表达式, 剔除符合该正则的链接
    
    allow_domains    # 接收一堆域名, 符合该域名的链接被提取
    deny_domains     # 接收一堆域名, 剔除不符合该域名的链接
    
    restrict_xpaths  # 接收一堆xpath, 提取符合要求xpath的链接
    restrict_css     # 接收一堆css选择器, 提取符合要求的css选择器的链接
    
    tags     # 设置从哪个标签中提取链接  默认(a,area)
    attrs    # 设置从标签的哪个属性中提取链接  默认 (href, )
    
    其他参数   # 点击源码 自己看
    
    
    
### 2 根据响应对象  提取链接  
links = 对象.extract_links(响应对象)  # 且 自动将链接拼接完整了,不需要 response.urljoin(url)
    
    # .extract_links() 返回的是links
    一堆 Link对象(url='',text='', nofollow=False) 的列表


    
### 3 eg:
le = LinkExtractor(restrict_xpaths=("//ul[@class='viewlist_ul']/li/a",), deny_domains=("topicm.che168.com",) )

links = le.extract_links(resp)

    
# 注意:
在提取到的url中, 是有重复的内容的  但scrapy会自动过滤掉重复的url请求

二、CrawlSpider

2.1 工作流程

# 工作流程:
前期(构建起始页的请求对象) 和普通的spider是一致的
在第一次请求回来之后,会自动的将返回的response
按照rules中,多个订制的规则(Rule) 来匹配
进行提取链接,并进一步按照 规则的 callback参数 回调 进行具体的处理


# 形式
rules = (
        Rule(LinkExtractor(restrict_xpaths=('xxx',)), follow=True),  # 分页规则
        Rule(LinkExtractor(restrict_xpaths=('yyy',)), callback='parse_item', follow=False), # 详情页规则
    )


# 规则(Rule)的参数
1.第一个参数 link_extractor
参数值是LinkExtractor对象  # 链接提取器对象

2.callback='解析函数名'  # 注意:和普通spider的区别是 该参数值是字符串形式 'parse_item' ,不再是函数地址 self.parse

3.follow=True | False 
  指的是按照 当前规则(Rule) 提取后的链接,发送链接请求后的 响应内容
  是否还使用 当前所有规则(rules) 提取链接,并继续发送 链接的请求对象

  相当于 常规spider中 在parse中继续 scrapy.request(xxx, callback=self.parse)

2.2 抓取汽车之家

在scrapy中提供了CrawlSpider,可用来完成全站数据抓取

注意:和以往的spider不同:该爬虫需要用到crawl的模板,来创建爬虫(spider)

  1. 创建项目
# 1.创建项目
scrapy startproject qichezhijia

# 2.进入项目
cd qichezhijia

# 3.创建爬虫  使用CrawlSpider  -t 指定spider的模板名  eg:crawl ---> CrawlSpider
# scrapy genspider -t spider模板名 spider名 域名

scrapy genspider -t crawl ershouche che168.com 
  1. 修改spider中的rules、回调函数
# spiders/Ershouche.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule      # 使用crawl模板  会自动导入到这些


class ErshoucheSpider(CrawlSpider):
    name = 'ershouche'
    allowed_domains = ['che168.com', 'autohome.com.cn']
    start_urls = ['https://www.che168.com/beijing/a0_0msdgscncgpi1ltocsp1exx0/']

    # 分页规则
    le1 = LinkExtractor(restrict_xpaths=("//div[@id='listpagination']/a",))
    
    # 详情页规则
    le2 = LinkExtractor(restrict_xpaths=("//ul[@class='viewlist_ul']/li/a",), deny_domains=("topicm.che168.com",) )
    

    
    rules = (
        Rule(le1, follow=True),  # 分页规则   并响应内容 继续按照rules的所有规则 提取链接
        
        Rule(le2, callback='parse_item', follow=False), # 详情页规则  并响应内容 不再继续按照rules的所有规则 提取链接了
    )

    def parse_item(self, response):
        print(response.url)
    
    
    # 注意:
    该位置没有了parse函数了,上面一、常规spider中的parse函数的逻辑,都是集成到 CrawlSpider类中了。

三、源码模板文件

### scrapy源码的 模板文件

scrapy
  -templates
    --project             # 创建项目的模板
      ---module
        ----spiders
        __init__.py
        items.py.tmpl
        middlewares.py.tmpl
        pipelines.py.tmpl
        settings.py.tmpl   # 默认配置的模板
    
      ---scrapy.cfg
        
      ---runner.py.tmpl    # 自定义添加运行脚本runner.py.tmpl文件
        

    --spiders       # 创建爬虫(spider)的模板
      basic.tmpl    # 常规spider
      crawl.tmpl    # CrawlSpider
      csvfeed.tmpl
      xmlfeed.tmpl
    
    
    
### 应用1:修改源码 scrapy/templates/project/module/settings.py.tmpl
ROBOTSTXT_OBEY = False   # 不遵守robots协议
LOG_LEVEL = 'WARNING'    # 控制台打印日志级别
DOWNLOAD_DELAY = 3       # 请求的延迟  3秒


### 应用2:将运行脚本,添加到项目模板中
# 1.新建runner.py.tmpl  模板
scrapy/templates/project/runner.py.tmpl
    
from scrapy.cmdline import execute

if __name__ == '__main__':
    execute('scrapy crawl to_modified_spider_name'.split())  
    
    
# 注意:
运行runner.py,需要修改 to_modified_spider_name 为真正的spider名字 
    
    
    
# 2.修改 scrapy创建项目时的命令文件 startproject.py
scrapy/commands/startproject.py

# 要渲染的模板
TEMPLATES_TO_RENDER = (
    ('scrapy.cfg',),
    ('${project_name}', 'settings.py.tmpl'),
    ('${project_name}', 'items.py.tmpl'),
    ('${project_name}', 'pipelines.py.tmpl'),
    ('${project_name}', 'middlewares.py.tmpl'),
    ('runner.py.tmpl',),  # 添加运行脚本runner.py.tmpl文件
)
posted @ 2024-04-24 15:53  Edmond辉仔  阅读(6)  评论(0编辑  收藏  举报